mirror of
https://gitcode.com/github-mirrors/react-native-update-cli.git
synced 2025-09-16 09:41:38 +08:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
bf0cea66b9 | ||
![]() |
8c31ee5762 | ||
![]() |
002e8662d6 | ||
![]() |
ebfb9dd4b9 | ||
![]() |
59c5be2719 | ||
![]() |
2e8e242e75 | ||
![]() |
0cfb1a9beb | ||
![]() |
b22c598ca4 | ||
![]() |
573ab60e44 | ||
![]() |
4613da1fbe | ||
![]() |
f2f33a190d |
@@ -12,7 +12,8 @@
|
||||
"noDoubleEquals": "off"
|
||||
},
|
||||
"style": {
|
||||
"noNonNullAssertion": "off"
|
||||
"noNonNullAssertion": "off",
|
||||
"useNodejsImportProtocol": "off"
|
||||
},
|
||||
"a11y": {
|
||||
"useValidAnchor": "off"
|
||||
|
105
bun.lock
105
bun.lock
@@ -3,17 +3,17 @@
|
||||
"workspaces": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@badisi/latest-version": "^7.0.13",
|
||||
"@colors/colors": "^1.6.0",
|
||||
"bplist-parser": "^0.3.2",
|
||||
"bytebuffer": "^5.0.1",
|
||||
"cgbi-to-png": "^1.0.7",
|
||||
"chalk": "4",
|
||||
"cli-arguments": "^0.2.1",
|
||||
"commander": "^13",
|
||||
"compare-versions": "^6.1.1",
|
||||
"filesize-parser": "^1.5.1",
|
||||
"form-data": "^4.0.2",
|
||||
"fs-extra": "8",
|
||||
"global-dirs": "^4.0.0",
|
||||
"gradle-to-js": "^2.0.1",
|
||||
"i18next": "^24.2.3",
|
||||
"isomorphic-git": "^1.30.1",
|
||||
@@ -23,7 +23,8 @@
|
||||
"progress": "^2.0.3",
|
||||
"properties": "^1.2.1",
|
||||
"read": "^4.1.0",
|
||||
"semver": "^7.7.1",
|
||||
"registry-auth-token": "^5.1.0",
|
||||
"semver": "^7.7.2",
|
||||
"tcp-ping": "^0.1.1",
|
||||
"tty-table": "4.2",
|
||||
"yauzl": "^3.2.0",
|
||||
@@ -31,11 +32,11 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^1.9.4",
|
||||
"@swc/cli": "^0.7.2",
|
||||
"@swc/core": "^1.11.21",
|
||||
"@swc/cli": "0.7.7",
|
||||
"@swc/core": "^1.11.24",
|
||||
"@types/filesize-parser": "^1.5.3",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/node": "^22.14.1",
|
||||
"@types/node": "^22.15.18",
|
||||
"@types/node-fetch": "^2.6.12",
|
||||
"@types/progress": "^2.0.7",
|
||||
"@types/semver": "^7.7.0",
|
||||
@@ -53,8 +54,6 @@
|
||||
"packages": {
|
||||
"@babel/runtime": ["@babel/runtime@7.26.10", "", { "dependencies": { "regenerator-runtime": "^0.14.0" } }, "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw=="],
|
||||
|
||||
"@badisi/latest-version": ["@badisi/latest-version@7.0.13", "", { "dependencies": { "@colors/colors": "^1.6.0", "global-dirs": "3.0.1", "ora": "^8.2.0", "registry-auth-token": "^5.1.0", "semver": "^7.7.1" }, "bin": { "latest-version": "bin/latest-version", "lv": "bin/latest-version" } }, "sha512-iie68SUX7vUt6Ap9tVeb5tGE/Oj1wUAzAMhzY6mqOSy81jO9FrhRdGa8c3A7QJX3KSedn281pZ/ZZDgtsaFI6g=="],
|
||||
|
||||
"@biomejs/biome": ["@biomejs/biome@1.9.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "1.9.4", "@biomejs/cli-darwin-x64": "1.9.4", "@biomejs/cli-linux-arm64": "1.9.4", "@biomejs/cli-linux-arm64-musl": "1.9.4", "@biomejs/cli-linux-x64": "1.9.4", "@biomejs/cli-linux-x64-musl": "1.9.4", "@biomejs/cli-win32-arm64": "1.9.4", "@biomejs/cli-win32-x64": "1.9.4" }, "bin": { "biome": "bin/biome" } }, "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog=="],
|
||||
|
||||
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@1.9.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw=="],
|
||||
@@ -125,29 +124,29 @@
|
||||
|
||||
"@sindresorhus/is": ["@sindresorhus/is@5.6.0", "", {}, "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g=="],
|
||||
|
||||
"@swc/cli": ["@swc/cli@0.7.2", "", { "dependencies": { "@swc/counter": "^0.1.3", "@xhmikosr/bin-wrapper": "^13.0.5", "commander": "^8.3.0", "fast-glob": "^3.2.5", "minimatch": "^9.0.3", "piscina": "^4.3.1", "semver": "^7.3.8", "slash": "3.0.0", "source-map": "^0.7.3" }, "peerDependencies": { "@swc/core": "^1.2.66", "chokidar": "^4.0.1" }, "optionalPeers": ["chokidar"], "bin": { "swc": "bin/swc.js", "swcx": "bin/swcx.js", "spack": "bin/spack.js" } }, "sha512-B73b2Orrd0tauaX3Jct9MxkAI79U3OMHzRB++x2wfyq+JPjgC6foJK6zyY2JI0vsTlaTbGpx9+hsowTQ8RtQFA=="],
|
||||
"@swc/cli": ["@swc/cli@0.7.7", "", { "dependencies": { "@swc/counter": "^0.1.3", "@xhmikosr/bin-wrapper": "^13.0.5", "commander": "^8.3.0", "fast-glob": "^3.2.5", "minimatch": "^9.0.3", "piscina": "^4.3.1", "semver": "^7.3.8", "slash": "3.0.0", "source-map": "^0.7.3" }, "peerDependencies": { "@swc/core": "^1.2.66", "chokidar": "^4.0.1" }, "optionalPeers": ["chokidar"], "bin": { "swc": "bin/swc.js", "swcx": "bin/swcx.js", "spack": "bin/spack.js" } }, "sha512-j4yYm9bx3pxWofaJKX1BFwj/3ngUDynN4UIQ2Xd2h0h/7Gt7zkReBTpDN7g5S13mgAYxacaTHTOUsz18097E8w=="],
|
||||
|
||||
"@swc/core": ["@swc/core@1.11.21", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.21" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.11.21", "@swc/core-darwin-x64": "1.11.21", "@swc/core-linux-arm-gnueabihf": "1.11.21", "@swc/core-linux-arm64-gnu": "1.11.21", "@swc/core-linux-arm64-musl": "1.11.21", "@swc/core-linux-x64-gnu": "1.11.21", "@swc/core-linux-x64-musl": "1.11.21", "@swc/core-win32-arm64-msvc": "1.11.21", "@swc/core-win32-ia32-msvc": "1.11.21", "@swc/core-win32-x64-msvc": "1.11.21" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-/Y3BJLcwd40pExmdar8MH2UGGvCBrqNN7hauOMckrEX2Ivcbv3IMhrbGX4od1dnF880Ed8y/E9aStZCIQi0EGw=="],
|
||||
"@swc/core": ["@swc/core@1.11.24", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.21" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.11.24", "@swc/core-darwin-x64": "1.11.24", "@swc/core-linux-arm-gnueabihf": "1.11.24", "@swc/core-linux-arm64-gnu": "1.11.24", "@swc/core-linux-arm64-musl": "1.11.24", "@swc/core-linux-x64-gnu": "1.11.24", "@swc/core-linux-x64-musl": "1.11.24", "@swc/core-win32-arm64-msvc": "1.11.24", "@swc/core-win32-ia32-msvc": "1.11.24", "@swc/core-win32-x64-msvc": "1.11.24" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-MaQEIpfcEMzx3VWWopbofKJvaraqmL6HbLlw2bFZ7qYqYw3rkhM0cQVEgyzbHtTWwCwPMFZSC2DUbhlZgrMfLg=="],
|
||||
|
||||
"@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.11.21", "", { "os": "darwin", "cpu": "arm64" }, "sha512-v6gjw9YFWvKulCw3ZA1dY+LGMafYzJksm1mD4UZFZ9b36CyHFowYVYug1ajYRIRqEvvfIhHUNV660zTLoVFR8g=="],
|
||||
"@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.11.24", "", { "os": "darwin", "cpu": "arm64" }, "sha512-dhtVj0PC1APOF4fl5qT2neGjRLgHAAYfiVP8poJelhzhB/318bO+QCFWAiimcDoyMgpCXOhTp757gnoJJrheWA=="],
|
||||
|
||||
"@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.11.21", "", { "os": "darwin", "cpu": "x64" }, "sha512-CUiTiqKlzskwswrx9Ve5NhNoab30L1/ScOfQwr1duvNlFvarC8fvQSgdtpw2Zh3MfnfNPpyLZnYg7ah4kbT9JQ=="],
|
||||
"@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.11.24", "", { "os": "darwin", "cpu": "x64" }, "sha512-H/3cPs8uxcj2Fe3SoLlofN5JG6Ny5bl8DuZ6Yc2wr7gQFBmyBkbZEz+sPVgsID7IXuz7vTP95kMm1VL74SO5AQ=="],
|
||||
|
||||
"@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.11.21", "", { "os": "linux", "cpu": "arm" }, "sha512-YyBTAFM/QPqt1PscD8hDmCLnqPGKmUZpqeE25HXY8OLjl2MUs8+O4KjwPZZ+OGxpdTbwuWFyMoxjcLy80JODvg=="],
|
||||
"@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.11.24", "", { "os": "linux", "cpu": "arm" }, "sha512-PHJgWEpCsLo/NGj+A2lXZ2mgGjsr96ULNW3+T3Bj2KTc8XtMUkE8tmY2Da20ItZOvPNC/69KroU7edyo1Flfbw=="],
|
||||
|
||||
"@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.11.21", "", { "os": "linux", "cpu": "arm64" }, "sha512-DQD+ooJmwpNsh4acrftdkuwl5LNxxg8U4+C/RJNDd7m5FP9Wo4c0URi5U0a9Vk/6sQNh9aSGcYChDpqCDWEcBw=="],
|
||||
"@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.11.24", "", { "os": "linux", "cpu": "arm64" }, "sha512-C2FJb08+n5SD4CYWCTZx1uR88BN41ZieoHvI8A55hfVf2woT8+6ZiBzt74qW2g+ntZ535Jts5VwXAKdu41HpBg=="],
|
||||
|
||||
"@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.11.21", "", { "os": "linux", "cpu": "arm64" }, "sha512-y1L49+snt1a1gLTYPY641slqy55QotPdtRK9Y6jMi4JBQyZwxC8swWYlQWb+MyILwxA614fi62SCNZNznB3XSA=="],
|
||||
"@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.11.24", "", { "os": "linux", "cpu": "arm64" }, "sha512-ypXLIdszRo0re7PNNaXN0+2lD454G8l9LPK/rbfRXnhLWDBPURxzKlLlU/YGd2zP98wPcVooMmegRSNOKfvErw=="],
|
||||
|
||||
"@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.11.21", "", { "os": "linux", "cpu": "x64" }, "sha512-NesdBXv4CvVEaFUlqKj+GA4jJMNUzK2NtKOrUNEtTbXaVyNiXjFCSaDajMTedEB0jTAd9ybB0aBvwhgkJUWkWA=="],
|
||||
"@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.11.24", "", { "os": "linux", "cpu": "x64" }, "sha512-IM7d+STVZD48zxcgo69L0yYptfhaaE9cMZ+9OoMxirNafhKKXwoZuufol1+alEFKc+Wbwp+aUPe/DeWC/Lh3dg=="],
|
||||
|
||||
"@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.11.21", "", { "os": "linux", "cpu": "x64" }, "sha512-qFV60pwpKVOdmX67wqQzgtSrUGWX9Cibnp1CXyqZ9Mmt8UyYGvmGu7p6PMbTyX7vdpVUvWVRf8DzrW2//wmVHg=="],
|
||||
"@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.11.24", "", { "os": "linux", "cpu": "x64" }, "sha512-DZByJaMVzSfjQKKQn3cqSeqwy6lpMaQDQQ4HPlch9FWtDx/dLcpdIhxssqZXcR2rhaQVIaRQsCqwV6orSDGAGw=="],
|
||||
|
||||
"@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.11.21", "", { "os": "win32", "cpu": "arm64" }, "sha512-DJJe9k6gXR/15ZZVLv1SKhXkFst8lYCeZRNHH99SlBodvu4slhh/MKQ6YCixINRhCwliHrpXPym8/5fOq8b7Ig=="],
|
||||
"@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.11.24", "", { "os": "win32", "cpu": "arm64" }, "sha512-Q64Ytn23y9aVDKN5iryFi8mRgyHw3/kyjTjT4qFCa8AEb5sGUuSj//AUZ6c0J7hQKMHlg9do5Etvoe61V98/JQ=="],
|
||||
|
||||
"@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.11.21", "", { "os": "win32", "cpu": "ia32" }, "sha512-TqEXuy6wedId7bMwLIr9byds+mKsaXVHctTN88R1UIBPwJA92Pdk0uxDgip0pEFzHB/ugU27g6d8cwUH3h2eIw=="],
|
||||
"@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.11.24", "", { "os": "win32", "cpu": "ia32" }, "sha512-9pKLIisE/Hh2vJhGIPvSoTK4uBSPxNVyXHmOrtdDot4E1FUUI74Vi8tFdlwNbaj8/vusVnb8xPXsxF1uB0VgiQ=="],
|
||||
|
||||
"@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.11.21", "", { "os": "win32", "cpu": "x64" }, "sha512-BT9BNNbMxdpUM1PPAkYtviaV0A8QcXttjs2MDtOeSqqvSJaPtyM+Fof2/+xSwQDmDEFzbGCcn75M5+xy3lGqpA=="],
|
||||
"@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.11.24", "", { "os": "win32", "cpu": "x64" }, "sha512-sybnXtOsdB+XvzVFlBVGgRHLqp3yRpHK7CrmpuDKszhj/QhmsaZzY/GHSeALlMtLup13M0gqbcQvsTNlAHTg3w=="],
|
||||
|
||||
"@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="],
|
||||
|
||||
@@ -165,7 +164,7 @@
|
||||
|
||||
"@types/jsonfile": ["@types/jsonfile@6.1.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ=="],
|
||||
|
||||
"@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="],
|
||||
"@types/node": ["@types/node@22.15.18", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-v1DKRfUdyW+jJhZNEI1PYy29S2YRxMV5AOO/x/SjKmW0acCIOqmbj6Haf9eHAhsPmrhlHSxEhv/1WszcLWV4cg=="],
|
||||
|
||||
"@types/node-fetch": ["@types/node-fetch@2.6.12", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.0" } }, "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA=="],
|
||||
|
||||
@@ -267,10 +266,6 @@
|
||||
|
||||
"cli-arguments": ["cli-arguments@0.2.1", "", {}, "sha512-vaoTjiREjxKlpTNMiaJUkQnYRhgui8r+huhB6mMHcGQyz5F7Hd1o1jsW9C/wRKjlNYQ6fTvODLtZe7DxfEIz8g=="],
|
||||
|
||||
"cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="],
|
||||
|
||||
"cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="],
|
||||
|
||||
"cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
|
||||
|
||||
"clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="],
|
||||
@@ -283,8 +278,6 @@
|
||||
|
||||
"commander": ["commander@13.1.0", "", {}, "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw=="],
|
||||
|
||||
"compare-versions": ["compare-versions@6.1.1", "", {}, "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg=="],
|
||||
|
||||
"config-chain": ["config-chain@1.1.13", "", { "dependencies": { "ini": "^1.3.4", "proto-list": "~1.2.1" } }, "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ=="],
|
||||
|
||||
"content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="],
|
||||
@@ -327,7 +320,7 @@
|
||||
|
||||
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
||||
|
||||
"emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="],
|
||||
"emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||
|
||||
"es-abstract": ["es-abstract@1.23.3", "", { "dependencies": { "array-buffer-byte-length": "^1.0.1", "arraybuffer.prototype.slice": "^1.0.3", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", "data-view-buffer": "^1.0.1", "data-view-byte-length": "^1.0.1", "data-view-byte-offset": "^1.0.0", "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.0.3", "es-to-primitive": "^1.2.1", "function.prototype.name": "^1.1.6", "get-intrinsic": "^1.2.4", "get-symbol-description": "^1.0.2", "globalthis": "^1.0.3", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2", "has-proto": "^1.0.3", "has-symbols": "^1.0.3", "hasown": "^2.0.2", "internal-slot": "^1.0.7", "is-array-buffer": "^3.0.4", "is-callable": "^1.2.7", "is-data-view": "^1.0.1", "is-negative-zero": "^2.0.3", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.3", "is-string": "^1.0.7", "is-typed-array": "^1.1.13", "is-weakref": "^1.0.2", "object-inspect": "^1.13.1", "object-keys": "^1.1.1", "object.assign": "^4.1.5", "regexp.prototype.flags": "^1.5.2", "safe-array-concat": "^1.1.2", "safe-regex-test": "^1.0.3", "string.prototype.trim": "^1.2.9", "string.prototype.trimend": "^1.0.8", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.2", "typed-array-byte-length": "^1.0.1", "typed-array-byte-offset": "^1.0.2", "typed-array-length": "^1.0.6", "unbox-primitive": "^1.0.2", "which-typed-array": "^1.1.15" } }, "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A=="],
|
||||
|
||||
@@ -389,8 +382,6 @@
|
||||
|
||||
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
|
||||
|
||||
"get-east-asian-width": ["get-east-asian-width@1.3.0", "", {}, "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ=="],
|
||||
|
||||
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
|
||||
|
||||
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
|
||||
@@ -401,7 +392,7 @@
|
||||
|
||||
"glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||
|
||||
"global-dirs": ["global-dirs@3.0.1", "", { "dependencies": { "ini": "2.0.0" } }, "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA=="],
|
||||
"global-dirs": ["global-dirs@4.0.0", "", { "dependencies": { "ini": "2.0.0" } }, "sha512-PJ0OjGf/kVuu9gh5IPgAyssfJne5PsU9+ICxfWiRYDUnYq8ob+Y2nSWAEUNEHRj+gowyzI+wg5/nWkvcjcyLwg=="],
|
||||
|
||||
"globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="],
|
||||
|
||||
@@ -467,8 +458,6 @@
|
||||
|
||||
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
||||
|
||||
"is-interactive": ["is-interactive@2.0.0", "", {}, "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ=="],
|
||||
|
||||
"is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="],
|
||||
|
||||
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
||||
@@ -489,8 +478,6 @@
|
||||
|
||||
"is-typed-array": ["is-typed-array@1.1.13", "", { "dependencies": { "which-typed-array": "^1.1.14" } }, "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw=="],
|
||||
|
||||
"is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="],
|
||||
|
||||
"is-weakref": ["is-weakref@1.0.2", "", { "dependencies": { "call-bind": "^1.0.2" } }, "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ=="],
|
||||
|
||||
"isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
|
||||
@@ -515,8 +502,6 @@
|
||||
|
||||
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
|
||||
|
||||
"log-symbols": ["log-symbols@6.0.0", "", { "dependencies": { "chalk": "^5.3.0", "is-unicode-supported": "^1.3.0" } }, "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw=="],
|
||||
|
||||
"long": ["long@3.2.0", "", {}, "sha512-ZYvPPOMqUwPoDsbJaR10iQJYnMuZhRTvHYl62ErLIEX7RgFlziSBUUvrt3OVfc47QlHHpzPZYP17g3Fv7oeJkg=="],
|
||||
|
||||
"lowercase-keys": ["lowercase-keys@3.0.0", "", {}, "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ=="],
|
||||
@@ -537,8 +522,6 @@
|
||||
|
||||
"mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
|
||||
|
||||
"mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="],
|
||||
|
||||
"mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="],
|
||||
|
||||
"minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
||||
@@ -567,8 +550,6 @@
|
||||
|
||||
"onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
|
||||
|
||||
"ora": ["ora@8.2.0", "", { "dependencies": { "chalk": "^5.3.0", "cli-cursor": "^5.0.0", "cli-spinners": "^2.9.2", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.0.0", "log-symbols": "^6.0.0", "stdin-discarder": "^0.2.2", "string-width": "^7.2.0", "strip-ansi": "^7.1.0" } }, "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw=="],
|
||||
|
||||
"p-cancelable": ["p-cancelable@3.0.0", "", {}, "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw=="],
|
||||
|
||||
"p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
|
||||
@@ -629,8 +610,6 @@
|
||||
|
||||
"responselike": ["responselike@3.0.0", "", { "dependencies": { "lowercase-keys": "^3.0.0" } }, "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg=="],
|
||||
|
||||
"restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="],
|
||||
|
||||
"reusify": ["reusify@1.0.4", "", {}, "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="],
|
||||
|
||||
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
||||
@@ -643,7 +622,7 @@
|
||||
|
||||
"seek-bzip": ["seek-bzip@2.0.0", "", { "dependencies": { "commander": "^6.0.0" }, "bin": { "seek-bunzip": "bin/seek-bunzip", "seek-table": "bin/seek-bzip-table" } }, "sha512-SMguiTnYrhpLdk3PwfzHeotrcwi8bNV4iemL9tx9poR/yeaMYwB9VzR1w7b57DuWpuqR8n6oZboi0hj3AxZxQg=="],
|
||||
|
||||
"semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
|
||||
"semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
||||
|
||||
"semver-regex": ["semver-regex@4.0.5", "", {}, "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw=="],
|
||||
|
||||
@@ -679,8 +658,6 @@
|
||||
|
||||
"source-map": ["source-map@0.7.4", "", {}, "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA=="],
|
||||
|
||||
"stdin-discarder": ["stdin-discarder@0.2.2", "", {}, "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ=="],
|
||||
|
||||
"stream-to": ["stream-to@0.2.2", "", {}, "sha512-Kg1BSDTwgGiVMtTCJNlo7kk/xzL33ZuZveEBRt6rXw+f1WLK/8kmz2NVCT/Qnv0JkV85JOHcLhD82mnXsR3kPw=="],
|
||||
|
||||
"stream-to-buffer": ["stream-to-buffer@0.1.0", "", { "dependencies": { "stream-to": "~0.2.0" } }, "sha512-Da4WoKaZyu3nf+bIdIifh7IPkFjARBnBK+pYqn0EUJqksjV9afojjaCCHUemH30Jmu7T2qcKvlZm2ykN38uzaw=="],
|
||||
@@ -691,7 +668,7 @@
|
||||
|
||||
"streamx": ["streamx@2.20.2", "", { "dependencies": { "fast-fifo": "^1.3.2", "queue-tick": "^1.0.1", "text-decoder": "^1.1.0" }, "optionalDependencies": { "bare-events": "^2.2.0" } }, "sha512-aDGDLU+j9tJcUdPGOaHmVF1u/hhI+CsGkT02V3OKlHDV7IukOI+nTWAGkiZEKCO35rWN1wIr4tS7YFr1f4qSvA=="],
|
||||
|
||||
"string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
|
||||
"string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||
|
||||
"string.prototype.trim": ["string.prototype.trim@1.2.9", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.0", "es-object-atoms": "^1.0.0" } }, "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw=="],
|
||||
|
||||
@@ -809,8 +786,6 @@
|
||||
|
||||
"call-bind/get-intrinsic": ["get-intrinsic@1.2.4", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "hasown": "^2.0.0" } }, "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ=="],
|
||||
|
||||
"cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||
|
||||
"config-chain/ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="],
|
||||
|
||||
"define-data-property/es-define-property": ["es-define-property@1.0.0", "", { "dependencies": { "get-intrinsic": "^1.2.4" } }, "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ=="],
|
||||
@@ -845,22 +820,10 @@
|
||||
|
||||
"isomorphic-unzip/yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="],
|
||||
|
||||
"log-symbols/chalk": ["chalk@5.3.0", "", {}, "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w=="],
|
||||
|
||||
"log-symbols/is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="],
|
||||
|
||||
"make-dir/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
|
||||
|
||||
"object.assign/has-symbols": ["has-symbols@1.0.3", "", {}, "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="],
|
||||
|
||||
"ora/chalk": ["chalk@5.3.0", "", {}, "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w=="],
|
||||
|
||||
"ora/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
||||
|
||||
"restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],
|
||||
|
||||
"restore-cursor/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
|
||||
|
||||
"safe-array-concat/get-intrinsic": ["get-intrinsic@1.2.4", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "hasown": "^2.0.0" } }, "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ=="],
|
||||
|
||||
"safe-array-concat/has-symbols": ["has-symbols@1.0.3", "", {}, "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="],
|
||||
@@ -877,8 +840,6 @@
|
||||
|
||||
"smartwrap/yargs": ["yargs@15.4.1", "", { "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^18.1.2" } }, "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A=="],
|
||||
|
||||
"string-width/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
||||
|
||||
"string.prototype.trim/es-object-atoms": ["es-object-atoms@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw=="],
|
||||
|
||||
"string.prototype.trimend/es-object-atoms": ["es-object-atoms@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw=="],
|
||||
@@ -895,10 +856,6 @@
|
||||
|
||||
"which-typed-array/gopd": ["gopd@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.1.3" } }, "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA=="],
|
||||
|
||||
"wrap-ansi/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||
|
||||
"yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||
|
||||
"yazl/buffer-crc32": ["buffer-crc32@1.0.0", "", {}, "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w=="],
|
||||
|
||||
"@types/fs-extra/@types/node/undici-types": ["undici-types@6.19.8", "", {}, "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="],
|
||||
@@ -917,8 +874,6 @@
|
||||
|
||||
"call-bind/get-intrinsic/has-symbols": ["has-symbols@1.0.3", "", {}, "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="],
|
||||
|
||||
"cliui/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||
|
||||
"define-data-property/es-define-property/get-intrinsic": ["get-intrinsic@1.2.4", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "hasown": "^2.0.0" } }, "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ=="],
|
||||
|
||||
"define-data-property/gopd/get-intrinsic": ["get-intrinsic@1.2.4", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "hasown": "^2.0.0" } }, "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ=="],
|
||||
@@ -933,22 +888,16 @@
|
||||
|
||||
"is-array-buffer/get-intrinsic/has-symbols": ["has-symbols@1.0.3", "", {}, "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="],
|
||||
|
||||
"ora/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
||||
|
||||
"set-function-length/get-intrinsic/has-symbols": ["has-symbols@1.0.3", "", {}, "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="],
|
||||
|
||||
"side-channel/get-intrinsic/has-symbols": ["has-symbols@1.0.3", "", {}, "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="],
|
||||
|
||||
"smartwrap/yargs/cliui": ["cliui@6.0.0", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^6.2.0" } }, "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ=="],
|
||||
|
||||
"smartwrap/yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||
|
||||
"smartwrap/yargs/y18n": ["y18n@4.0.3", "", {}, "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="],
|
||||
|
||||
"smartwrap/yargs/yargs-parser": ["yargs-parser@18.1.3", "", { "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ=="],
|
||||
|
||||
"string-width/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
||||
|
||||
"typed-array-byte-length/gopd/get-intrinsic": ["get-intrinsic@1.2.4", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "hasown": "^2.0.0" } }, "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ=="],
|
||||
|
||||
"typed-array-byte-offset/gopd/get-intrinsic": ["get-intrinsic@1.2.4", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "hasown": "^2.0.0" } }, "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ=="],
|
||||
@@ -957,10 +906,6 @@
|
||||
|
||||
"which-typed-array/gopd/get-intrinsic": ["get-intrinsic@1.2.4", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "hasown": "^2.0.0" } }, "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ=="],
|
||||
|
||||
"wrap-ansi/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||
|
||||
"yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||
|
||||
"define-data-property/es-define-property/get-intrinsic/has-symbols": ["has-symbols@1.0.3", "", {}, "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="],
|
||||
|
||||
"define-data-property/gopd/get-intrinsic/has-symbols": ["has-symbols@1.0.3", "", {}, "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="],
|
||||
@@ -971,8 +916,6 @@
|
||||
|
||||
"smartwrap/yargs/cliui/wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="],
|
||||
|
||||
"smartwrap/yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||
|
||||
"typed-array-byte-length/gopd/get-intrinsic/has-symbols": ["has-symbols@1.0.3", "", {}, "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="],
|
||||
|
||||
"typed-array-byte-offset/gopd/get-intrinsic/has-symbols": ["has-symbols@1.0.3", "", {}, "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="],
|
||||
|
17
cli.json
17
cli.json
@@ -87,6 +87,9 @@
|
||||
"maxPackageVersion": {
|
||||
"hasValue": true
|
||||
},
|
||||
"semverRange": {
|
||||
"hasValue": true
|
||||
},
|
||||
"rollout": {
|
||||
"hasValue": true
|
||||
}
|
||||
@@ -118,7 +121,7 @@
|
||||
"description": "Bundle javascript and copy assets."
|
||||
},
|
||||
"bundle": {
|
||||
"description": "Bundle javascript code only.",
|
||||
"description": "Bundle javascript code only and optionally publish.",
|
||||
"options": {
|
||||
"dev": {
|
||||
"default": "false",
|
||||
@@ -157,6 +160,18 @@
|
||||
},
|
||||
"disableHermes": {
|
||||
"default": false
|
||||
},
|
||||
"name": {
|
||||
"hasValue": true,
|
||||
"description": "Version name for publishing"
|
||||
},
|
||||
"description": {
|
||||
"hasValue": true,
|
||||
"description": "Version description for publishing"
|
||||
},
|
||||
"metaInfo": {
|
||||
"hasValue": true,
|
||||
"description": "Meta information for publishing"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
17
package.json
17
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-update-cli",
|
||||
"version": "1.44.0",
|
||||
"version": "1.45.1",
|
||||
"description": "command line tool for react-native-update (remote updates for react native)",
|
||||
"main": "index.js",
|
||||
"bin": {
|
||||
@@ -14,7 +14,7 @@
|
||||
],
|
||||
"scripts": {
|
||||
"build": "swc src -d lib --strip-leading-paths",
|
||||
"prepare": "npm run build && chmod +x lib/index.js",
|
||||
"prepublishOnly": "npm run build && chmod +x lib/index.js",
|
||||
"lint": "tsc --noEmit & biome check --write ."
|
||||
},
|
||||
"repository": {
|
||||
@@ -35,17 +35,17 @@
|
||||
},
|
||||
"homepage": "https://github.com/reactnativecn/react-native-pushy/tree/master/react-native-pushy-cli",
|
||||
"dependencies": {
|
||||
"@badisi/latest-version": "^7.0.13",
|
||||
"@colors/colors": "^1.6.0",
|
||||
"bplist-parser": "^0.3.2",
|
||||
"bytebuffer": "^5.0.1",
|
||||
"cgbi-to-png": "^1.0.7",
|
||||
"chalk": "4",
|
||||
"cli-arguments": "^0.2.1",
|
||||
"commander": "^13",
|
||||
"compare-versions": "^6.1.1",
|
||||
"filesize-parser": "^1.5.1",
|
||||
"form-data": "^4.0.2",
|
||||
"fs-extra": "8",
|
||||
"global-dirs": "^4.0.0",
|
||||
"gradle-to-js": "^2.0.1",
|
||||
"i18next": "^24.2.3",
|
||||
"isomorphic-git": "^1.30.1",
|
||||
@@ -55,7 +55,8 @@
|
||||
"progress": "^2.0.3",
|
||||
"properties": "^1.2.1",
|
||||
"read": "^4.1.0",
|
||||
"semver": "^7.7.1",
|
||||
"registry-auth-token": "^5.1.0",
|
||||
"semver": "^7.7.2",
|
||||
"tcp-ping": "^0.1.1",
|
||||
"tty-table": "4.2",
|
||||
"yauzl": "^3.2.0",
|
||||
@@ -66,11 +67,11 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^1.9.4",
|
||||
"@swc/cli": "^0.7.2",
|
||||
"@swc/core": "^1.11.21",
|
||||
"@swc/cli": "0.7.7",
|
||||
"@swc/core": "^1.11.24",
|
||||
"@types/filesize-parser": "^1.5.3",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/node": "^22.14.1",
|
||||
"@types/node": "^22.15.18",
|
||||
"@types/node-fetch": "^2.6.12",
|
||||
"@types/progress": "^2.0.7",
|
||||
"@types/semver": "^7.7.0",
|
||||
|
13
src/api.ts
13
src/api.ts
@@ -1,7 +1,7 @@
|
||||
import fetch from 'node-fetch';
|
||||
import fs from 'node:fs';
|
||||
import util from 'node:util';
|
||||
import path from 'node:path';
|
||||
import fs from 'fs';
|
||||
import util from 'util';
|
||||
import path from 'path';
|
||||
import ProgressBar from 'progress';
|
||||
import packageJson from '../package.json';
|
||||
import tcpp from 'tcp-ping';
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
credentialFile,
|
||||
defaultEndpoint,
|
||||
} from './utils/constants';
|
||||
import type { Session } from 'types';
|
||||
import type { Session, Package } from 'types';
|
||||
import FormData from 'form-data';
|
||||
import { t } from './utils/i18n';
|
||||
|
||||
@@ -177,3 +177,8 @@ export async function uploadFile(fn: string, key?: string) {
|
||||
// const body = await response.json();
|
||||
return { hash: key || formData.key };
|
||||
}
|
||||
|
||||
export const getAllPackages = async (appId: string) => {
|
||||
const { data } = await get(`/app/${appId}/package/list?limit=1000`);
|
||||
return data as Package[] | undefined | null;
|
||||
};
|
||||
|
39
src/app.ts
39
src/app.ts
@@ -1,5 +1,5 @@
|
||||
import { question } from './utils';
|
||||
import fs from 'node:fs';
|
||||
import fs from 'fs';
|
||||
import Table from 'tty-table';
|
||||
|
||||
import { post, get, doDelete } from './api';
|
||||
@@ -8,8 +8,13 @@ import { t } from './utils/i18n';
|
||||
|
||||
const validPlatforms = ['ios', 'android', 'harmony'];
|
||||
|
||||
export async function getPlatform(platform?: string) {
|
||||
return assertPlatform(
|
||||
platform || (await question(t('platformQuestion'))),
|
||||
) as Platform;
|
||||
}
|
||||
|
||||
export function checkPlatform(platform: Platform) {
|
||||
export function assertPlatform(platform: string) {
|
||||
if (!validPlatforms.includes(platform)) {
|
||||
throw new Error(t('unsupportedPlatform', { platform }));
|
||||
}
|
||||
@@ -17,7 +22,7 @@ export function checkPlatform(platform: Platform) {
|
||||
}
|
||||
|
||||
export function getSelectedApp(platform: Platform) {
|
||||
checkPlatform(platform);
|
||||
assertPlatform(platform);
|
||||
|
||||
if (!fs.existsSync('update.json')) {
|
||||
throw new Error(t('appNotSelected', { platform }));
|
||||
@@ -69,9 +74,7 @@ export const commands = {
|
||||
}) {
|
||||
const name = options.name || (await question(t('appNameQuestion')));
|
||||
const { downloadUrl } = options;
|
||||
const platform = checkPlatform(
|
||||
options.platform || (await question(t('platformQuestion'))),
|
||||
);
|
||||
const platform = await getPlatform(options.platform);
|
||||
const { id } = await post('/app/create', { name, platform, downloadUrl });
|
||||
console.log(t('createAppSuccess', { id }));
|
||||
await this.selectApp({
|
||||
@@ -79,7 +82,13 @@ export const commands = {
|
||||
options: { platform },
|
||||
});
|
||||
},
|
||||
deleteApp: async ({ args, options }: { args: string[]; options: { platform: Platform } }) => {
|
||||
deleteApp: async ({
|
||||
args,
|
||||
options,
|
||||
}: {
|
||||
args: string[];
|
||||
options: { platform: Platform };
|
||||
}) => {
|
||||
const { platform } = options;
|
||||
const id = args[0] || chooseApp(platform);
|
||||
if (!id) {
|
||||
@@ -92,15 +101,21 @@ export const commands = {
|
||||
const { platform } = options;
|
||||
listApp(platform);
|
||||
},
|
||||
selectApp: async ({ args, options }: { args: string[]; options: { platform: Platform } }) => {
|
||||
const platform = checkPlatform(
|
||||
options.platform || (await question(t('platformQuestion'))),
|
||||
);
|
||||
selectApp: async ({
|
||||
args,
|
||||
options,
|
||||
}: {
|
||||
args: string[];
|
||||
options: { platform: Platform };
|
||||
}) => {
|
||||
const platform = await getPlatform(options.platform);
|
||||
const id = args[0]
|
||||
? Number.parseInt(args[0])
|
||||
: (await chooseApp(platform)).id;
|
||||
|
||||
let updateInfo: Partial<Record<Platform, { appId: number; appKey: string }>> = {};
|
||||
let updateInfo: Partial<
|
||||
Record<Platform, { appId: number; appKey: string }>
|
||||
> = {};
|
||||
if (fs.existsSync('update.json')) {
|
||||
try {
|
||||
updateInfo = JSON.parse(fs.readFileSync('update.json', 'utf8'));
|
||||
|
125
src/bundle.ts
125
src/bundle.ts
@@ -1,24 +1,31 @@
|
||||
import path from 'node:path';
|
||||
import path from 'path';
|
||||
import { translateOptions } from './utils';
|
||||
import * as fs from 'fs-extra';
|
||||
import { ZipFile } from 'yazl';
|
||||
import { open as openZipFile } from 'yauzl';
|
||||
import { ZipFile as YazlZipFile } from 'yazl';
|
||||
import {
|
||||
type Entry,
|
||||
open as openZipFile,
|
||||
type ZipFile as YauzlZipFile,
|
||||
} from 'yauzl';
|
||||
import { question, checkPlugins } from './utils';
|
||||
import { checkPlatform } from './app';
|
||||
import { spawn, spawnSync } from 'node:child_process';
|
||||
import { checkPlatform, getPlatform } from './app';
|
||||
import { spawn, spawnSync } from 'child_process';
|
||||
import semverSatisfies from 'semver/functions/satisfies';
|
||||
const g2js = require('gradle-to-js/lib/parser');
|
||||
import os from 'node:os';
|
||||
import os from 'os';
|
||||
const properties = require('properties');
|
||||
import { depVersions } from './utils/dep-versions';
|
||||
import { t } from './utils/i18n';
|
||||
import { tempDir } from './utils/constants';
|
||||
import { checkLockFiles } from './utils/check-lockfile';
|
||||
import { addGitIgnore } from './utils/add-gitignore';
|
||||
import { commands as versionCommands } from './versions';
|
||||
|
||||
let bsdiff;
|
||||
let hdiff;
|
||||
let diff;
|
||||
type Diff = (oldSource?: Buffer, newSource?: Buffer) => Buffer;
|
||||
|
||||
let bsdiff: Diff;
|
||||
let hdiff: Diff;
|
||||
let diff: Diff;
|
||||
try {
|
||||
bsdiff = require('node-bsdiff').diff;
|
||||
} catch (e) {}
|
||||
@@ -59,9 +66,7 @@ async function runReactNativeBundleCommand({
|
||||
if (platform === 'android') {
|
||||
gradleConfig = await checkGradleConfig();
|
||||
if (gradleConfig.crunchPngs !== false) {
|
||||
console.warn(
|
||||
'android 的 crunchPngs 选项似乎尚未禁用(如已禁用则请忽略此提示),这可能导致热更包体积异常增大,具体请参考 https://pushy.reactnative.cn/docs/getting-started.html#%E7%A6%81%E7%94%A8-android-%E7%9A%84-crunch-%E4%BC%98%E5%8C%96 \n',
|
||||
);
|
||||
console.warn(t('androidCrunchPngsWarning'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,7 +326,7 @@ async function compileHermesByteCode(
|
||||
sourcemapOutput: string,
|
||||
shouldCleanSourcemap: boolean,
|
||||
) {
|
||||
console.log('Hermes enabled, now compiling to hermes bytecode:\n');
|
||||
console.log(t('hermesEnabledCompiling'));
|
||||
// >= rn 0.69
|
||||
const rnDir = path.dirname(
|
||||
require.resolve('react-native', {
|
||||
@@ -351,7 +356,9 @@ async function compileHermesByteCode(
|
||||
);
|
||||
args.push('-output-source-map');
|
||||
}
|
||||
console.log(t('runningHermesc', { command: hermesCommand, args: args.join(' ') }));
|
||||
console.log(
|
||||
t('runningHermesc', { command: hermesCommand, args: args.join(' ') }),
|
||||
);
|
||||
spawnSync(hermesCommand, args, {
|
||||
stdio: 'ignore',
|
||||
});
|
||||
@@ -387,7 +394,7 @@ async function copyDebugidForSentry(
|
||||
sourcemapOutput: string,
|
||||
) {
|
||||
if (sourcemapOutput) {
|
||||
let copyDebugidPath;
|
||||
let copyDebugidPath: string | undefined;
|
||||
try {
|
||||
copyDebugidPath = require.resolve(
|
||||
'@sentry/react-native/scripts/copy-debugid.js',
|
||||
@@ -426,13 +433,13 @@ async function uploadSourcemapForSentry(
|
||||
version: string,
|
||||
) {
|
||||
if (sourcemapOutput) {
|
||||
let sentryCliPath;
|
||||
let sentryCliPath: string | undefined;
|
||||
try {
|
||||
sentryCliPath = require.resolve('@sentry/cli/bin/sentry-cli', {
|
||||
paths: [process.cwd()],
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('无法找到 Sentry CLI 工具,请确保已正确安装 @sentry/cli');
|
||||
console.error(t('sentryCliNotFound'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -471,12 +478,12 @@ async function uploadSourcemapForSentry(
|
||||
}
|
||||
|
||||
const ignorePackingFileNames = ['.', '..', 'index.bundlejs.map'];
|
||||
const ignorePackingExtensions = ['DS_Store','txt.map'];
|
||||
const ignorePackingExtensions = ['DS_Store', 'txt.map'];
|
||||
async function pack(dir: string, output: string) {
|
||||
console.log(t('packing'));
|
||||
fs.ensureDirSync(path.dirname(output));
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const zipfile = new ZipFile();
|
||||
const zipfile = new YazlZipFile();
|
||||
|
||||
function addDirectory(root: string, rel: string) {
|
||||
if (rel) {
|
||||
@@ -513,10 +520,13 @@ async function pack(dir: string, output: string) {
|
||||
console.log(t('fileGenerated', { file: output }));
|
||||
}
|
||||
|
||||
export function readEntire(entry: string, zipFile: ZipFile) {
|
||||
export function readEntry(
|
||||
entry: Entry,
|
||||
zipFile: YauzlZipFile,
|
||||
): Promise<Buffer> {
|
||||
const buffers: Buffer[] = [];
|
||||
return new Promise((resolve, reject) => {
|
||||
zipFile.openReadStream(entry, (err: any, stream: any) => {
|
||||
zipFile.openReadStream(entry, (err, stream) => {
|
||||
stream.pipe({
|
||||
write(chunk: Buffer) {
|
||||
buffers.push(chunk);
|
||||
@@ -544,7 +554,7 @@ async function diffFromPPK(origin: string, next: string, output: string) {
|
||||
const originEntries = {};
|
||||
const originMap = {};
|
||||
|
||||
let originSource;
|
||||
let originSource: Buffer | undefined;
|
||||
|
||||
await enumZipEntries(origin, (entry, zipFile) => {
|
||||
originEntries[entry.fileName] = entry;
|
||||
@@ -557,7 +567,7 @@ async function diffFromPPK(origin: string, next: string, output: string) {
|
||||
entry.fileName === 'bundle.harmony.js'
|
||||
) {
|
||||
// This is source.
|
||||
return readEntire(entry, zipFile).then((v) => (originSource = v));
|
||||
return readEntry(entry, zipFile).then((v) => (originSource = v));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -570,7 +580,7 @@ async function diffFromPPK(origin: string, next: string, output: string) {
|
||||
|
||||
const copies = {};
|
||||
|
||||
const zipfile = new ZipFile();
|
||||
const zipfile = new YazlZipFile();
|
||||
|
||||
const writePromise = new Promise((resolve, reject) => {
|
||||
zipfile.outputStream.on('error', (err) => {
|
||||
@@ -607,7 +617,7 @@ async function diffFromPPK(origin: string, next: string, output: string) {
|
||||
}
|
||||
} else if (entry.fileName === 'index.bundlejs') {
|
||||
//console.log('Found bundle');
|
||||
return readEntire(entry, nextZipfile).then((newSource) => {
|
||||
return readEntry(entry, nextZipfile).then((newSource) => {
|
||||
//console.log('Begin diff');
|
||||
zipfile.addBuffer(
|
||||
diff(originSource, newSource),
|
||||
@@ -617,7 +627,7 @@ async function diffFromPPK(origin: string, next: string, output: string) {
|
||||
});
|
||||
} else if (entry.fileName === 'bundle.harmony.js') {
|
||||
//console.log('Found bundle');
|
||||
return readEntire(entry, nextZipfile).then((newSource) => {
|
||||
return readEntry(entry, nextZipfile).then((newSource) => {
|
||||
//console.log('Begin diff');
|
||||
zipfile.addBuffer(
|
||||
diff(originSource, newSource),
|
||||
@@ -691,9 +701,9 @@ async function diffFromPackage(
|
||||
const originEntries = {};
|
||||
const originMap = {};
|
||||
|
||||
let originSource;
|
||||
let originSource: Buffer | undefined;
|
||||
|
||||
await enumZipEntries(origin, (entry: any, zipFile: any) => {
|
||||
await enumZipEntries(origin, (entry, zipFile) => {
|
||||
if (!/\/$/.test(entry.fileName)) {
|
||||
const fn = transformPackagePath(entry.fileName);
|
||||
if (!fn) {
|
||||
@@ -707,7 +717,7 @@ async function diffFromPackage(
|
||||
|
||||
if (fn === originBundleName) {
|
||||
// This is source.
|
||||
return readEntire(entry, zipFile).then((v) => (originSource = v));
|
||||
return readEntry(entry, zipFile).then((v) => (originSource = v));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -720,7 +730,7 @@ async function diffFromPackage(
|
||||
|
||||
const copies = {};
|
||||
|
||||
const zipfile = new ZipFile();
|
||||
const zipfile = new YazlZipFile();
|
||||
|
||||
const writePromise = new Promise((resolve, reject) => {
|
||||
zipfile.outputStream.on('error', (err) => {
|
||||
@@ -737,7 +747,7 @@ async function diffFromPackage(
|
||||
zipfile.addEmptyDirectory(entry.fileName);
|
||||
} else if (entry.fileName === 'index.bundlejs') {
|
||||
//console.log('Found bundle');
|
||||
return readEntire(entry, nextZipfile).then((newSource) => {
|
||||
return readEntry(entry, nextZipfile).then((newSource) => {
|
||||
//console.log('Begin diff');
|
||||
zipfile.addBuffer(
|
||||
diff(originSource, newSource),
|
||||
@@ -747,7 +757,7 @@ async function diffFromPackage(
|
||||
});
|
||||
} else if (entry.fileName === 'bundle.harmony.js') {
|
||||
//console.log('Found bundle');
|
||||
return readEntire(entry, nextZipfile).then((newSource) => {
|
||||
return readEntry(entry, nextZipfile).then((newSource) => {
|
||||
//console.log('Begin diff');
|
||||
zipfile.addBuffer(
|
||||
diff(originSource, newSource),
|
||||
@@ -789,14 +799,18 @@ async function diffFromPackage(
|
||||
|
||||
export async function enumZipEntries(
|
||||
zipFn: string,
|
||||
callback: (entry: any, zipFile: any) => void,
|
||||
callback: (
|
||||
entry: Entry,
|
||||
zipFile: YauzlZipFile,
|
||||
nestedPath?: string,
|
||||
) => Promise<any>,
|
||||
nestedPath = '',
|
||||
) {
|
||||
return new Promise((resolve, reject) => {
|
||||
openZipFile(
|
||||
zipFn,
|
||||
{ lazyEntries: true },
|
||||
async (err: any, zipfile: ZipFile) => {
|
||||
async (err: any, zipfile: YauzlZipFile) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
@@ -850,7 +864,7 @@ export async function enumZipEntries(
|
||||
});
|
||||
}
|
||||
|
||||
function diffArgsCheck(args, options, diffFn) {
|
||||
function diffArgsCheck(args: string[], options: any, diffFn: string) {
|
||||
const [origin, next] = args;
|
||||
|
||||
if (!origin || !next) {
|
||||
@@ -887,10 +901,8 @@ function diffArgsCheck(args, options, diffFn) {
|
||||
}
|
||||
|
||||
export const commands = {
|
||||
bundle: async function ({ options }) {
|
||||
const platform = checkPlatform(
|
||||
options.platform || (await question('平台(ios/android/harmony):')),
|
||||
);
|
||||
bundle: async ({ options }) => {
|
||||
const platform = await getPlatform(options.platform);
|
||||
|
||||
const {
|
||||
bundleName,
|
||||
@@ -903,6 +915,9 @@ export const commands = {
|
||||
expo,
|
||||
rncli,
|
||||
disableHermes,
|
||||
name,
|
||||
description,
|
||||
metaInfo,
|
||||
} = translateOptions({
|
||||
...options,
|
||||
tempDir,
|
||||
@@ -943,14 +958,17 @@ export const commands = {
|
||||
|
||||
await pack(path.resolve(intermediaDir), realOutput);
|
||||
|
||||
const v = await question('是否现在上传此热更包?(Y/N)');
|
||||
if (v.toLowerCase() === 'y') {
|
||||
const versionName = await this.publish({
|
||||
if (name) {
|
||||
const versionName = await versionCommands.publish({
|
||||
args: [realOutput],
|
||||
options: {
|
||||
platform,
|
||||
name,
|
||||
description,
|
||||
metaInfo,
|
||||
},
|
||||
});
|
||||
|
||||
if (isSentry) {
|
||||
await copyDebugidForSentry(bundleName, intermediaDir, sourcemapOutput);
|
||||
await uploadSourcemapForSentry(
|
||||
@@ -960,6 +978,29 @@ export const commands = {
|
||||
versionName,
|
||||
);
|
||||
}
|
||||
} else if (!options['no-interactive']) {
|
||||
const v = await question(t('uploadBundlePrompt'));
|
||||
if (v.toLowerCase() === 'y') {
|
||||
const versionName = await versionCommands.publish({
|
||||
args: [realOutput],
|
||||
options: {
|
||||
platform,
|
||||
},
|
||||
});
|
||||
if (isSentry) {
|
||||
await copyDebugidForSentry(
|
||||
bundleName,
|
||||
intermediaDir,
|
||||
sourcemapOutput,
|
||||
);
|
||||
await uploadSourcemapForSentry(
|
||||
bundleName,
|
||||
intermediaDir,
|
||||
sourcemapOutput,
|
||||
versionName,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@@ -8,7 +8,6 @@ function printUsage() {
|
||||
// const commandName = args[0];
|
||||
// TODO: print usage of commandName, or print global usage.
|
||||
|
||||
console.log('Usage is under development now.');
|
||||
console.log(
|
||||
'Visit `https://github.com/reactnativecn/react-native-update` for document.',
|
||||
);
|
||||
|
@@ -1,10 +1,60 @@
|
||||
export default {
|
||||
loginFirst:
|
||||
'Not logged in.\nPlease run `cresc login` in the project directory to login.',
|
||||
lockNotFound:
|
||||
'No lock file detected, which may cause inconsistent dependencies and hot-updating issues.',
|
||||
multipleLocksFound:
|
||||
'Multiple lock files detected ({{lockFiles}}), which may cause inconsistent dependencies and hot-updating issues.',
|
||||
addedToGitignore: 'Added {{line}} to .gitignore',
|
||||
androidCrunchPngsWarning:
|
||||
'The crunchPngs option of android seems not disabled (Please ignore this warning if already disabled), which may cause abnormal consumption of mobile network traffic. Please refer to https://cresc.dev/docs/getting-started#disable-crunchpngs-on-android \n',
|
||||
appId: 'App ID',
|
||||
appIdMismatchApk:
|
||||
'App ID mismatch! Current APK: {{appIdInPkg}}, current update.json: {{appId}}',
|
||||
appIdMismatchApp:
|
||||
'App ID mismatch! Current APP: {{appIdInPkg}}, current update.json: {{appId}}',
|
||||
appIdMismatchIpa:
|
||||
'App ID mismatch! Current IPA: {{appIdInPkg}}, current update.json: {{appId}}',
|
||||
appKeyMismatchApk:
|
||||
'App Key mismatch! Current APK: {{appKeyInPkg}}, current update.json: {{appKey}}',
|
||||
appKeyMismatchApp:
|
||||
'App Key mismatch! Current APP: {{appKeyInPkg}}, current update.json: {{appKey}}',
|
||||
appKeyMismatchIpa:
|
||||
'App Key mismatch! Current IPA: {{appKeyInPkg}}, current update.json: {{appKey}}',
|
||||
appName: 'App Name',
|
||||
appNameQuestion: 'App Name:',
|
||||
appNotSelected:
|
||||
'App not selected. run `cresc selectApp --platform {{platform}}` first!',
|
||||
appUploadSuccess:
|
||||
'Successfully uploaded APP native package (id: {{id}}, version: {{version}}, buildTime: {{buildTime}})',
|
||||
apkUploadSuccess:
|
||||
'Successfully uploaded APK native package (id: {{id}}, version: {{version}}, buildTime: {{buildTime}})',
|
||||
boundTo: ', bound to: {{name}} ({{id}})',
|
||||
buildTimeNotFound:
|
||||
'Cannot get the build timestamp of this package. Please update `react-native-update` to the latest version and re-package and upload.',
|
||||
bundleCommandError:
|
||||
'"react-native bundle" command exited with code {{code}}.',
|
||||
bundleNotFound:
|
||||
'Bundle file not found. Please ensure that this {{packageType}} is a release version and the bundle file name is the default `{{entryFile}}`',
|
||||
bundlingWithRN: 'Bundling with react-native: {{version}}',
|
||||
cancelled: 'Cancelled',
|
||||
composingSourceMap: 'Composing source map',
|
||||
copyFileFailed: 'Failed to copy file: {{error}}',
|
||||
copyHarmonyBundleError: 'Error copying Harmony bundle: {{error}}',
|
||||
copyingDebugId: 'Copying debugid',
|
||||
createAppSuccess: 'App created successfully (id: {{id}})',
|
||||
deleteFile: 'Delete {{- file}}',
|
||||
deletingFile: 'Delete {{- file}}',
|
||||
enterAppIdQuestion: 'Enter AppId:',
|
||||
enterNativePackageId: 'Enter native package ID:',
|
||||
errorInHarmonyApp: 'Error in getEntryFromHarmonyApp: {{error}}',
|
||||
expiredStatus: '(Expired)',
|
||||
failedToParseIcon: '[Warning] failed to parse icon: {{error}}',
|
||||
failedToParseUpdateJson:
|
||||
'Failed to parse file `update.json`. Try to remove it manually.',
|
||||
fileGenerated: '{{- file}} generated.',
|
||||
fileSizeExceeded:
|
||||
'This file size is {{fileSize}} , exceeding the current quota {{maxSize}} . You may consider upgrading to a higher plan to increase this quota. Details can be found at: {{- pricingPageUrl}}',
|
||||
hermesDisabled: 'Hermes disabled',
|
||||
hermesEnabledCompiling: 'Hermes enabled, now compiling to hermes bytecode:\n',
|
||||
ipaUploadSuccess:
|
||||
'Successfully uploaded IPA native package (id: {{id}}, version: {{version}}, buildTime: {{buildTime}})',
|
||||
keyStrings: 'Key strings:',
|
||||
latestVersionTag: '(latest: {{version}})',
|
||||
lockBestPractice: `
|
||||
Best practices for lock files:
|
||||
1. All members of the development team should use the same package manager to maintain a single lock file.
|
||||
@@ -12,84 +62,71 @@ Best practices for lock files:
|
||||
3. Pay attention to changes in the lock file during code review.
|
||||
This can reduce the risk of inconsistent dependencies and supply chain attacks.
|
||||
`,
|
||||
lockNotFound:
|
||||
'No lock file detected, which may cause inconsistent dependencies and hot-updating issues.',
|
||||
loggedOut: 'Logged out',
|
||||
loginExpired:
|
||||
'Login information has expired. Please use `cresc login` command to re-login',
|
||||
fileSizeExceeded:
|
||||
'This file size is {{fileSize}} , exceeding the current quota {{maxSize}} . You may consider upgrading to a higher plan to increase this quota. Details can be found at: {{pricingPageUrl}}',
|
||||
bundleNotFound:
|
||||
'Bundle file not found. Please ensure that this {{packageType}} is a release version and the bundle file name is the default `{{entryFile}}`',
|
||||
buildTimeNotFound:
|
||||
'Cannot get the build timestamp of this package. Please update `react-native-update` to the latest version and re-package and upload.',
|
||||
latestVersionTag: '(latest: {{version}})',
|
||||
loginFirst:
|
||||
'Not logged in.\nPlease run `cresc login` in the project directory to login.',
|
||||
multipleLocksFound:
|
||||
'Multiple lock files detected ({{- lockFiles}}), which may cause inconsistent dependencies and hot-updating issues.',
|
||||
nativePackageId: 'Native Package ID',
|
||||
nativeVersion: 'Native Version',
|
||||
nativeVersionNotFoundGte: 'No native version found >= {{version}}',
|
||||
nativeVersionNotFoundLte: 'No native version found <= {{version}}',
|
||||
nativeVersionNotFoundMatch: 'No matching native version found: {{version}}',
|
||||
nativePackageIdNotFound: 'No native package id found: {{id}}',
|
||||
noPackagesFound: 'No packages found. (appId: {{appId}})',
|
||||
offset: 'Offset {{offset}}',
|
||||
operationComplete: 'Operation complete, bound to {{count}} native versions',
|
||||
operationSuccess: 'Operation successful',
|
||||
packageIdRequired: 'Please provide packageId or packageVersion parameter',
|
||||
packageUploadSuccess:
|
||||
'Successfully uploaded new hot update package (id: {{id}})',
|
||||
packing: 'Packing',
|
||||
pausedStatus: '(Paused)',
|
||||
platform: 'Platform',
|
||||
platformPrompt: 'Platform (ios/android/harmony):',
|
||||
platformQuestion: 'Platform(ios/android/harmony):',
|
||||
platformRequired: 'Platform must be specified.',
|
||||
pluginDetectionError: 'error while detecting {{name}} plugin: {{error}}',
|
||||
pluginDetected: 'detected {{name}} plugin',
|
||||
ppkPackageGenerated: 'ppk package generated and saved to: {{- output}}',
|
||||
processingError: 'Error processing file: {{error}}',
|
||||
processingPackage: 'Processing the package {{count}} ...',
|
||||
processingStringPool: 'Processing the string pool ...',
|
||||
publishUsage:
|
||||
'Usage: pushy publish <ppk file> --platform ios|android|harmony',
|
||||
rnuVersionNotFound:
|
||||
'react-native-update: Cannot get the version number. Please run the command in the project directory',
|
||||
unsupportedPlatform: 'Unsupported platform `{{platform}}`',
|
||||
appId: 'App ID',
|
||||
appName: 'App Name',
|
||||
platform: 'Platform',
|
||||
totalApps: 'Total {{count}} {{platform}} apps',
|
||||
appNotSelected:
|
||||
'App not selected. run `cresc selectApp --platform {{platform}}` first!',
|
||||
enterAppIdQuestion: 'Enter AppId:',
|
||||
appNameQuestion: 'App Name:',
|
||||
platformQuestion: 'Platform(ios/android/harmony):',
|
||||
createAppSuccess: 'App created successfully (id: {{id}})',
|
||||
cancelled: 'Cancelled',
|
||||
operationSuccess: 'Operation successful',
|
||||
failedToParseUpdateJson:
|
||||
'Failed to parse file `update.json`. Try to remove it manually.',
|
||||
ppkPackageGenerated: 'ppk package generated and saved to: {{- output}}',
|
||||
Message: 'Welcome to Cresc hot update service, {{name}}.',
|
||||
loggedOut: 'Logged out',
|
||||
usageUnderDevelopment: 'Usage is under development now.',
|
||||
hermesDisabled: 'Hermes disabled',
|
||||
hermesEnabled: 'Hermes enabled, now compiling to hermes bytecode:\n',
|
||||
runningHermesc: 'Running hermesc: {{command}} {{args}}',
|
||||
composingSourceMap: 'Composing source map',
|
||||
copyingDebugId: 'Copying debugid',
|
||||
rolloutConfigSet:
|
||||
'Set {{rollout}}% rollout for version {{version}} on native version(s) {{versions}}',
|
||||
rolloutRangeError: 'rollout must be an integer between 1-100',
|
||||
runningHermesc: 'Running hermesc: {{- command}} {{- args}}',
|
||||
sentryCliNotFound:
|
||||
'Cannot find Sentry CLI tool, please make sure @sentry/cli is properly installed',
|
||||
sentryReleaseCreated: 'Sentry release created for version: {{version}}',
|
||||
uploadingSourcemap: 'Uploading sourcemap',
|
||||
packing: 'Packing',
|
||||
deletingFile: 'Delete {{- file}}',
|
||||
bundlingWithRN: 'Bundling with react-native: {{version}}',
|
||||
fileGenerated: '{{- file}} generated.',
|
||||
processingError: 'Error processing file: {{error}}',
|
||||
usageDiff: 'Usage: cresc {{command}} <origin> <next>',
|
||||
pluginDetected: 'detected {{name}} plugin',
|
||||
pluginDetectionError: 'error while detecting {{name}} plugin: {{error}}',
|
||||
addedToGitignore: 'Added {{line}} to .gitignore',
|
||||
processingStringPool: 'Processing the string pool ...',
|
||||
processingPackage: 'Processing the package {{count}} ...',
|
||||
typeStrings: 'Type strings:',
|
||||
keyStrings: 'Key strings:',
|
||||
failedToParseIcon: '[Warning] failed to parse icon: {{error}}',
|
||||
errorInHarmonyApp: 'Error in getEntryFromHarmonyApp: {{error}}',
|
||||
totalApps: 'Total {{count}} {{platform}} apps',
|
||||
totalPackages: 'Total {{count}} packages',
|
||||
usageUploadIpa: 'Usage: cresc uploadIpa <ipa file>',
|
||||
usageUploadApk: 'Usage: cresc uploadApk <apk file>',
|
||||
usageUploadApp: 'Usage: cresc uploadApp <app file>',
|
||||
typeStrings: 'Type strings:',
|
||||
unsupportedPlatform: 'Unsupported platform `{{platform}}`',
|
||||
uploadBundlePrompt: 'Upload this bundle now?(Y/N)',
|
||||
uploadingSourcemap: 'Uploading sourcemap',
|
||||
usageDiff: 'Usage: cresc {{command}} <origin> <next>',
|
||||
usageParseApk: 'Usage: cresc parseApk <apk file>',
|
||||
usageParseApp: 'Usage: cresc parseApp <app file>',
|
||||
usageParseIpa: 'Usage: cresc parseIpa <ipa file>',
|
||||
usageParseApk: 'Usage: cresc parseApk <apk file>',
|
||||
offset: 'Offset {{offset}}',
|
||||
packageUploadSuccess:
|
||||
'Successfully uploaded new hot update package (id: {{id}})',
|
||||
rolloutRangeError: 'rollout must be an integer between 1-100',
|
||||
nativeVersionNotFound: 'No native version found >= {{version}}',
|
||||
nativeVersionNotFoundLess: 'No native version found <= {{version}}',
|
||||
nativeVersionNotFoundMatch: 'No matching native version found: {{version}}',
|
||||
packageIdRequired: 'Please provide packageId or packageVersion parameter',
|
||||
operationComplete: 'Operation complete, bound to {{count}} native versions',
|
||||
platformRequired: 'Platform must be specified.',
|
||||
bundleCommandError:
|
||||
'"react-native bundle" command exited with code {{code}}.',
|
||||
copyHarmonyBundleError: 'Error copying Harmony bundle: {{error}}',
|
||||
copyFileFailed: 'Failed to copy file: {{error}}',
|
||||
deleteFile: 'Delete {{- file}}',
|
||||
rolloutConfigSet:
|
||||
'Set {{rollout}}% rollout for version {{version}} on native version(s) {{versions}}',
|
||||
usageUnderDevelopment: 'Usage is under development now.',
|
||||
usageUploadApk: 'Usage: cresc uploadApk <apk file>',
|
||||
usageUploadApp: 'Usage: cresc uploadApp <app file>',
|
||||
usageUploadIpa: 'Usage: cresc uploadIpa <ipa file>',
|
||||
versionBind:
|
||||
'Bound version {{version}} to native version {{nativeVersion}} (id: {{id}})',
|
||||
welcomeMessage: 'Welcome to Cresc hot update service, {{name}}.',
|
||||
versionNameQuestion: 'Enter version name:',
|
||||
versionDescriptionQuestion: 'Enter version description:',
|
||||
versionMetaInfoQuestion: 'Enter custom meta info:',
|
||||
updateNativePackageQuestion: 'Bind to native package now?(Y/N)',
|
||||
unnamed: '(Unnamed)',
|
||||
};
|
||||
|
@@ -1,7 +1,58 @@
|
||||
export default {
|
||||
loginFirst: '尚未登录。\n请在项目目录中运行`pushy login`命令来登录',
|
||||
lockNotFound:
|
||||
'没有检测到任何 lock 文件,这可能导致依赖关系不一致而使热更异常。',
|
||||
addedToGitignore: '已将 {{line}} 添加到 .gitignore',
|
||||
androidCrunchPngsWarning:
|
||||
'android 的 crunchPngs 选项似乎尚未禁用(如已禁用则请忽略此提示),这可能导致热更包体积异常增大,具体请参考 https://pushy.reactnative.cn/docs/getting-started.html#%E7%A6%81%E7%94%A8-android-%E7%9A%84-crunch-%E4%BC%98%E5%8C%96 \n',
|
||||
appId: '应用 id',
|
||||
appIdMismatchApk:
|
||||
'appId不匹配!当前apk: {{appIdInPkg}}, 当前update.json: {{appId}}',
|
||||
appIdMismatchApp:
|
||||
'appId不匹配!当前app: {{appIdInPkg}}, 当前update.json: {{appId}}',
|
||||
appIdMismatchIpa:
|
||||
'appId不匹配!当前ipa: {{appIdInPkg}}, 当前update.json: {{appId}}',
|
||||
appKeyMismatchApk:
|
||||
'appKey不匹配!当前apk: {{appKeyInPkg}}, 当前update.json: {{appKey}}',
|
||||
appKeyMismatchApp:
|
||||
'appKey不匹配!当前app: {{appKeyInPkg}}, 当前update.json: {{appKey}}',
|
||||
appKeyMismatchIpa:
|
||||
'appKey不匹配!当前ipa: {{appKeyInPkg}}, 当前update.json: {{appKey}}',
|
||||
appName: '应用名称',
|
||||
appNameQuestion: '应用名称:',
|
||||
appNotSelected:
|
||||
'尚未选择应用。请先运行 `pushy selectApp --platform {{platform}}` 来选择应用',
|
||||
appUploadSuccess:
|
||||
'已成功上传app原生包(id: {{id}}, version: {{version}}, buildTime: {{buildTime}})',
|
||||
apkUploadSuccess:
|
||||
'已成功上传apk原生包(id: {{id}}, version: {{version}}, buildTime: {{buildTime}})',
|
||||
boundTo: ', 已绑定:{{name}} ({{id}})',
|
||||
buildTimeNotFound:
|
||||
'无法获取此包的编译时间戳。请更新 `react-native-update` 到最新版本后重新打包上传。',
|
||||
bundleCommandError: '"react-native bundle" 命令退出,代码为 {{code}}。',
|
||||
bundleNotFound:
|
||||
'找不到 bundle 文件。请确保此 {{packageType}} 为 release 版本,且 bundle 文件名为默认的 `{{entryFile}}`',
|
||||
bundlingWithRN: '正在使用 react-native {{version}} 打包',
|
||||
cancelled: '已取消',
|
||||
composingSourceMap: '正在生成 source map',
|
||||
copyFileFailed: '复制文件失败:{{error}}',
|
||||
copyHarmonyBundleError: '复制 Harmony bundle 错误:{{error}}',
|
||||
copyingDebugId: '正在复制 debugid',
|
||||
createAppSuccess: '已成功创建应用(id: {{id}})',
|
||||
deleteFile: '删除 {{- file}}',
|
||||
deletingFile: '删除 {{- file}}',
|
||||
enterAppIdQuestion: '输入应用 id:',
|
||||
enterNativePackageId: '输入原生包 id:',
|
||||
errorInHarmonyApp: '获取 Harmony 应用入口时出错:{{error}}',
|
||||
expiredStatus: '(已过期)',
|
||||
failedToParseIcon: '[警告] 解析图标失败:{{error}}',
|
||||
failedToParseUpdateJson: '无法解析文件 `update.json`。请手动删除它。',
|
||||
fileGenerated: '已生成 {{- file}}',
|
||||
fileSizeExceeded:
|
||||
'此文件大小 {{fileSize}} , 超出当前额度 {{maxSize}} 。您可以考虑升级付费业务以提升此额度。详情请访问: {{- pricingPageUrl}}',
|
||||
hermesDisabled: 'Hermes 已禁用',
|
||||
hermesEnabledCompiling: 'Hermes 已启用,正在编译为 hermes 字节码:\n',
|
||||
ipaUploadSuccess:
|
||||
'已成功上传ipa原生包(id: {{id}}, version: {{version}}, buildTime: {{buildTime}})',
|
||||
keyStrings: '键字符串:',
|
||||
latestVersionTag: '(最新:{{version}})',
|
||||
lockBestPractice: `
|
||||
关于 lock 文件的最佳实践:
|
||||
1. 开发团队中的所有成员应该使用相同的包管理器,维护同一份 lock 文件。
|
||||
@@ -9,81 +60,66 @@ export default {
|
||||
3. 代码审核时应关注 lock 文件的变化。
|
||||
这样可以最大限度避免因依赖关系不一致而导致的热更异常,也降低供应链攻击等安全隐患。
|
||||
`,
|
||||
multipleLocksFound:
|
||||
'检测到多种不同格式的锁文件({{lockFiles}}),这可能导致依赖关系不一致而使热更异常。',
|
||||
lockNotFound:
|
||||
'没有检测到任何 lock 文件,这可能导致依赖关系不一致而使热更异常。',
|
||||
loggedOut: '已退出登录',
|
||||
loginExpired: '登录信息已过期,请使用 `pushy login` 命令重新登录',
|
||||
fileSizeExceeded:
|
||||
'此文件大小 {{fileSize}} , 超出当前额度 {{maxSize}} 。您可以考虑升级付费业务以提升此额度。详情请访问: {{pricingPageUrl}}',
|
||||
bundleNotFound:
|
||||
'找不到 bundle 文件。请确保此 {{packageType}} 为 release 版本,且 bundle 文件名为默认的 `{{entryFile}}`',
|
||||
buildTimeNotFound:
|
||||
'无法获取此包的编译时间戳。请更新 `react-native-update` 到最新版本后重新打包上传。',
|
||||
latestVersionTag: '(最新:{{version}})',
|
||||
loginFirst: '尚未登录。\n请在项目目录中运行`pushy login`命令来登录',
|
||||
multipleLocksFound:
|
||||
'检测到多种不同格式的锁文件({{- lockFiles}}),这可能导致依赖关系不一致而使热更异常。',
|
||||
nativePackageId: '原生包 Id',
|
||||
nativeVersion: '原生版本',
|
||||
nativeVersionNotFoundGte: '未查询到 >= {{version}} 的原生版本',
|
||||
nativeVersionNotFoundLte: '未查询到 <= {{version}} 的原生版本',
|
||||
nativeVersionNotFoundMatch: '未查询到匹配原生版本:{{version}}',
|
||||
nativePackageIdNotFound: '未查询到原生包 id: {{id}}',
|
||||
noPackagesFound: '未查询到任何原生包(appId: {{appId}})',
|
||||
offset: '偏移量 {{offset}}',
|
||||
operationComplete: '操作完成,共已绑定 {{count}} 个原生版本',
|
||||
operationSuccess: '操作成功',
|
||||
packageIdRequired: '请提供 packageId 或 packageVersion 参数',
|
||||
packageUploadSuccess: '已成功上传新热更包(id: {{id}})',
|
||||
packing: '正在打包',
|
||||
pausedStatus: '(已暂停)',
|
||||
platform: '平台',
|
||||
platformPrompt: '平台(ios/android/harmony):',
|
||||
platformQuestion: '平台(ios/android/harmony):',
|
||||
platformRequired: '必须指定平台。',
|
||||
pluginDetectionError: '检测 {{name}} 插件时出错:{{error}}',
|
||||
pluginDetected: '检测到 {{name}} 插件',
|
||||
ppkPackageGenerated: 'ppk 热更包已生成并保存到: {{- output}}',
|
||||
processingError: '处理文件时出错:{{error}}',
|
||||
processingPackage: '正在处理包 {{count}}...',
|
||||
processingStringPool: '正在处理字符串池...',
|
||||
publishUsage:
|
||||
'使用方法: pushy publish ppk后缀文件 --platform ios|android|harmony',
|
||||
rnuVersionNotFound:
|
||||
'react-native-update: 无法获取版本号。请在项目目录中运行命令',
|
||||
unsupportedPlatform: '无法识别的平台 `{{platform}}`',
|
||||
appId: '应用 id',
|
||||
appName: '应用名称',
|
||||
platform: '平台',
|
||||
totalApps: '共 {{count}} 个 {{platform}} 应用',
|
||||
appNotSelected:
|
||||
'尚未选择应用。请先运行 `pushy selectApp --platform {{platform}}` 来选择应用',
|
||||
enterAppIdQuestion: '输入应用 id:',
|
||||
appNameQuestion: '应用名称:',
|
||||
platformQuestion: '平台(ios/android/harmony):',
|
||||
createAppSuccess: '已成功创建应用(id: {{id}})',
|
||||
cancelled: '已取消',
|
||||
operationSuccess: '操作成功',
|
||||
failedToParseUpdateJson: '无法解析文件 `update.json`。请手动删除它。',
|
||||
ppkPackageGenerated: 'ppk 热更包已生成并保存到: {{- output}}',
|
||||
welcomeMessage: '欢迎使用 pushy 热更新服务,{{name}}。',
|
||||
loggedOut: '已退出登录',
|
||||
usageUnderDevelopment: '使用说明正在开发中。',
|
||||
hermesDisabled: 'Hermes 已禁用',
|
||||
hermesEnabled: 'Hermes 已启用,正在编译为 hermes 字节码:\n',
|
||||
runningHermesc: '运行 hermesc:{{command}} {{args}}',
|
||||
composingSourceMap: '正在生成 source map',
|
||||
copyingDebugId: '正在复制 debugid',
|
||||
sentryCliNotFound: '无法找到 Sentry CLI 工具,请确保已正确安装 @sentry/cli',
|
||||
sentryReleaseCreated: '已为版本 {{version}} 创建 Sentry release',
|
||||
uploadingSourcemap: '正在上传 sourcemap',
|
||||
packing: '正在打包',
|
||||
deletingFile: '删除 {{- file}}',
|
||||
bundlingWithRN: '正在使用 react-native {{version}} 打包',
|
||||
fileGenerated: '已生成 {{- file}}。',
|
||||
processingError: '处理文件时出错:{{error}}',
|
||||
usageDiff: '用法:pushy {{command}} <origin> <next>',
|
||||
pluginDetected: '检测到 {{name}} 插件',
|
||||
pluginDetectionError: '检测 {{name}} 插件时出错:{{error}}',
|
||||
addedToGitignore: '已将 {{line}} 添加到 .gitignore',
|
||||
processingStringPool: '正在处理字符串池...',
|
||||
processingPackage: '正在处理包 {{count}}...',
|
||||
typeStrings: '类型字符串:',
|
||||
keyStrings: '键字符串:',
|
||||
failedToParseIcon: '[警告] 解析图标失败:{{error}}',
|
||||
errorInHarmonyApp: '获取 Harmony 应用入口时出错:{{error}}',
|
||||
totalPackages: '共 {{count}} 个包',
|
||||
usageUploadIpa: '使用方法: pushy uploadIpa ipa后缀文件',
|
||||
usageUploadApk: '使用方法: pushy uploadApk apk后缀文件',
|
||||
usageUploadApp: '使用方法: pushy uploadApp app后缀文件',
|
||||
usageParseApp: '使用方法: pushy parseApp app后缀文件',
|
||||
usageParseIpa: '使用方法: pushy parseIpa ipa后缀文件',
|
||||
usageParseApk: '使用方法: pushy parseApk apk后缀文件',
|
||||
offset: '偏移量 {{offset}}',
|
||||
packageUploadSuccess: '已成功上传新热更包(id: {{id}})',
|
||||
rolloutRangeError: 'rollout 必须是 1-100 的整数',
|
||||
nativeVersionNotFound: '未查询到 >= {{version}} 的原生版本',
|
||||
nativeVersionNotFoundLess: '未查询到 <= {{version}} 的原生版本',
|
||||
nativeVersionNotFoundMatch: '未查询到匹配原生版本:{{version}}',
|
||||
packageIdRequired: '请提供 packageId 或 packageVersion 参数',
|
||||
operationComplete: '操作完成,共已绑定 {{count}} 个原生版本',
|
||||
platformRequired: '必须指定平台。',
|
||||
bundleCommandError: '"react-native bundle" 命令退出,代码为 {{code}}。',
|
||||
copyHarmonyBundleError: '复制 Harmony bundle 错误:{{error}}',
|
||||
copyFileFailed: '复制文件失败:{{error}}',
|
||||
deleteFile: '删除 {{- file}}',
|
||||
rolloutConfigSet:
|
||||
'已在原生版本 {{versions}} 上设置灰度发布 {{rollout}}% 热更版本 {{version}}',
|
||||
rolloutRangeError: 'rollout 必须是 1-100 的整数',
|
||||
runningHermesc: '运行 hermesc:{{- command}} {{- args}}',
|
||||
sentryCliNotFound: '无法找到 Sentry CLI 工具,请确保已正确安装 @sentry/cli',
|
||||
sentryReleaseCreated: '已为版本 {{version}} 创建 Sentry release',
|
||||
totalApps: '共 {{count}} 个 {{platform}} 应用',
|
||||
totalPackages: '共 {{count}} 个包',
|
||||
typeStrings: '类型字符串:',
|
||||
unsupportedPlatform: '无法识别的平台 `{{platform}}`',
|
||||
uploadBundlePrompt: '是否现在上传此热更包?(Y/N)',
|
||||
uploadingSourcemap: '正在上传 sourcemap',
|
||||
usageDiff: '用法:pushy {{command}} <origin> <next>',
|
||||
usageParseApk: '使用方法: pushy parseApk apk后缀文件',
|
||||
usageParseApp: '使用方法: pushy parseApp app后缀文件',
|
||||
usageParseIpa: '使用方法: pushy parseIpa ipa后缀文件',
|
||||
usageUploadApk: '使用方法: pushy uploadApk apk后缀文件',
|
||||
usageUploadApp: '使用方法: pushy uploadApp app后缀文件',
|
||||
usageUploadIpa: '使用方法: pushy uploadIpa ipa后缀文件',
|
||||
versionBind:
|
||||
'已将热更版本 {{version}} 绑定到原生版本 {{nativeVersion}} (id: {{id}})',
|
||||
welcomeMessage: '欢迎使用 pushy 热更新服务,{{name}}。',
|
||||
versionNameQuestion: '输入版本名称:',
|
||||
versionDescriptionQuestion: '输入版本描述:',
|
||||
versionMetaInfoQuestion: '输入自定义的 meta info:',
|
||||
updateNativePackageQuestion: '是否现在将此热更应用到原生包上?(Y/N)',
|
||||
unnamed: '(未命名)',
|
||||
};
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import { get, post, uploadFile } from './api';
|
||||
import { get, getAllPackages, post, uploadFile } from './api';
|
||||
import { question, saveToLocal } from './utils';
|
||||
import { t } from './utils/i18n';
|
||||
|
||||
import { checkPlatform, getSelectedApp } from './app';
|
||||
import { checkPlatform, getPlatform, getSelectedApp } from './app';
|
||||
|
||||
import { getApkInfo, getIpaInfo, getAppInfo } from './utils';
|
||||
import Table from 'tty-table';
|
||||
@@ -11,39 +11,40 @@ import { getCommitInfo } from './utils/git';
|
||||
import type { Platform } from 'types';
|
||||
|
||||
export async function listPackage(appId: string) {
|
||||
const { data } = await get(`/app/${appId}/package/list?limit=1000`);
|
||||
const allPkgs = await getAllPackages(appId);
|
||||
|
||||
const header = [{ value: '原生包 Id' }, { value: '原生版本' }];
|
||||
const header = [
|
||||
{ value: t('nativePackageId') },
|
||||
{ value: t('nativeVersion') },
|
||||
];
|
||||
const rows = [];
|
||||
for (const pkg of data) {
|
||||
for (const pkg of allPkgs) {
|
||||
const { version } = pkg;
|
||||
let versionInfo = '';
|
||||
if (version) {
|
||||
versionInfo = `, 已绑定:${version.name} (${version.id})`;
|
||||
} else {
|
||||
// versionInfo = ' (newest)';
|
||||
versionInfo = t('boundTo', { name: version.name, id: version.id });
|
||||
}
|
||||
let output = pkg.name;
|
||||
if (pkg.status === 'paused') {
|
||||
output += '(已暂停)';
|
||||
output += t('pausedStatus');
|
||||
}
|
||||
if (pkg.status === 'expired') {
|
||||
output += '(已过期)';
|
||||
output += t('expiredStatus');
|
||||
}
|
||||
output += versionInfo;
|
||||
rows.push([pkg.id, output]);
|
||||
}
|
||||
|
||||
console.log(Table(header, rows).render());
|
||||
console.log(t('totalPackages', { count: data.length }));
|
||||
return data;
|
||||
console.log(t('totalPackages', { count: allPkgs.length }));
|
||||
return allPkgs;
|
||||
}
|
||||
|
||||
export async function choosePackage(appId: string) {
|
||||
const list = await listPackage(appId);
|
||||
|
||||
while (true) {
|
||||
const id = await question('输入原生包 id:');
|
||||
const id = await question(t('enterNativePackageId'));
|
||||
const app = list.find((v) => v.id === Number(id));
|
||||
if (app) {
|
||||
return app;
|
||||
@@ -66,15 +67,11 @@ export const commands = {
|
||||
const { appId, appKey } = await getSelectedApp('ios');
|
||||
|
||||
if (appIdInPkg && appIdInPkg != appId) {
|
||||
throw new Error(
|
||||
`appId不匹配!当前ipa: ${appIdInPkg}, 当前update.json: ${appId}`,
|
||||
);
|
||||
throw new Error(t('appIdMismatchIpa', { appIdInPkg, appId }));
|
||||
}
|
||||
|
||||
if (appKeyInPkg && appKeyInPkg !== appKey) {
|
||||
throw new Error(
|
||||
`appKey不匹配!当前ipa: ${appKeyInPkg}, 当前update.json: ${appKey}`,
|
||||
);
|
||||
throw new Error(t('appKeyMismatchIpa', { appKeyInPkg, appKey }));
|
||||
}
|
||||
|
||||
const { hash } = await uploadFile(fn);
|
||||
@@ -87,9 +84,7 @@ export const commands = {
|
||||
commit: await getCommitInfo(),
|
||||
});
|
||||
saveToLocal(fn, `${appId}/package/${id}.ipa`);
|
||||
console.log(
|
||||
`已成功上传ipa原生包(id: ${id}, version: ${versionName}, buildTime: ${buildTime})`,
|
||||
);
|
||||
console.log(t('ipaUploadSuccess', { id, version: versionName, buildTime }));
|
||||
},
|
||||
uploadApk: async ({ args }: { args: string[] }) => {
|
||||
const fn = args[0];
|
||||
@@ -105,15 +100,11 @@ export const commands = {
|
||||
const { appId, appKey } = await getSelectedApp('android');
|
||||
|
||||
if (appIdInPkg && appIdInPkg != appId) {
|
||||
throw new Error(
|
||||
`appId不匹配!当前apk: ${appIdInPkg}, 当前update.json: ${appId}`,
|
||||
);
|
||||
throw new Error(t('appIdMismatchApk', { appIdInPkg, appId }));
|
||||
}
|
||||
|
||||
if (appKeyInPkg && appKeyInPkg !== appKey) {
|
||||
throw new Error(
|
||||
`appKey不匹配!当前apk: ${appKeyInPkg}, 当前update.json: ${appKey}`,
|
||||
);
|
||||
throw new Error(t('appKeyMismatchApk', { appKeyInPkg, appKey }));
|
||||
}
|
||||
|
||||
const { hash } = await uploadFile(fn);
|
||||
@@ -126,9 +117,7 @@ export const commands = {
|
||||
commit: await getCommitInfo(),
|
||||
});
|
||||
saveToLocal(fn, `${appId}/package/${id}.apk`);
|
||||
console.log(
|
||||
`已成功上传apk原生包(id: ${id}, version: ${versionName}, buildTime: ${buildTime})`,
|
||||
);
|
||||
console.log(t('apkUploadSuccess', { id, version: versionName, buildTime }));
|
||||
},
|
||||
uploadApp: async ({ args }: { args: string[] }) => {
|
||||
const fn = args[0];
|
||||
@@ -144,15 +133,11 @@ export const commands = {
|
||||
const { appId, appKey } = await getSelectedApp('harmony');
|
||||
|
||||
if (appIdInPkg && appIdInPkg != appId) {
|
||||
throw new Error(
|
||||
`appId不匹配!当前app: ${appIdInPkg}, 当前update.json: ${appId}`,
|
||||
);
|
||||
throw new Error(t('appIdMismatchApp', { appIdInPkg, appId }));
|
||||
}
|
||||
|
||||
if (appKeyInPkg && appKeyInPkg !== appKey) {
|
||||
throw new Error(
|
||||
`appKey不匹配!当前app: ${appKeyInPkg}, 当前update.json: ${appKey}`,
|
||||
);
|
||||
throw new Error(t('appKeyMismatchApp', { appKeyInPkg, appKey }));
|
||||
}
|
||||
|
||||
const { hash } = await uploadFile(fn);
|
||||
@@ -165,9 +150,7 @@ export const commands = {
|
||||
commit: await getCommitInfo(),
|
||||
});
|
||||
saveToLocal(fn, `${appId}/package/${id}.app`);
|
||||
console.log(
|
||||
`已成功上传app原生包(id: ${id}, version: ${versionName}, buildTime: ${buildTime})`,
|
||||
);
|
||||
console.log(t('appUploadSuccess', { id, version: versionName, buildTime }));
|
||||
},
|
||||
parseApp: async ({ args }: { args: string[] }) => {
|
||||
const fn = args[0];
|
||||
@@ -191,9 +174,7 @@ export const commands = {
|
||||
console.log(await getApkInfo(fn));
|
||||
},
|
||||
packages: async ({ options }: { options: { platform: Platform } }) => {
|
||||
const platform = checkPlatform(
|
||||
options.platform || (await question('平台(ios/android/harmony):')),
|
||||
);
|
||||
const platform = await getPlatform(options.platform);
|
||||
const { appId } = await getSelectedApp(platform);
|
||||
await listPackage(appId);
|
||||
},
|
||||
|
12
src/types.ts
12
src/types.ts
@@ -8,3 +8,15 @@ export interface Session {
|
||||
}
|
||||
|
||||
export type Platform = 'ios' | 'android' | 'harmony';
|
||||
|
||||
export interface Package {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface Version {
|
||||
id: string;
|
||||
hash: string;
|
||||
name: string;
|
||||
packages?: Package[];
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { question } from './utils';
|
||||
import { post, get, replaceSession, saveSession, closeSession } from './api';
|
||||
import crypto from 'node:crypto';
|
||||
import crypto from 'crypto';
|
||||
import { t } from './utils/i18n';
|
||||
|
||||
function md5(str: string) {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import fs from 'node:fs';
|
||||
// import path from 'node:path';
|
||||
import fs from 'fs';
|
||||
// import path from 'path';
|
||||
import { credentialFile, tempDir } from './constants';
|
||||
import { t } from './i18n';
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
const Unzip = require('isomorphic-unzip');
|
||||
const { isBrowser, decodeNullUnicode } = require('./utils');
|
||||
import { enumZipEntries, readEntire } from '../../bundle';
|
||||
import { enumZipEntries, readEntry } from '../../bundle';
|
||||
|
||||
class Zip {
|
||||
constructor(file) {
|
||||
@@ -53,7 +53,7 @@ class Zip {
|
||||
let originSource;
|
||||
await enumZipEntries(this.file, (entry, zipFile) => {
|
||||
if (regex.test(entry.fileName)) {
|
||||
return readEntire(entry, zipFile).then((v) => (originSource = v));
|
||||
return readEntry(entry, zipFile).then((v) => (originSource = v));
|
||||
}
|
||||
});
|
||||
return originSource;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { t } from './i18n';
|
||||
|
||||
const lockFiles = [
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import path from 'node:path';
|
||||
import path from 'path';
|
||||
|
||||
const scriptName = path.basename(process.argv[1]) as 'cresc' | 'pushy';
|
||||
export const IS_CRESC = scriptName === 'cresc';
|
||||
|
@@ -1,19 +1,21 @@
|
||||
const currentPackage = require(`${process.cwd()}/package.json`);
|
||||
|
||||
const depKeys = Object.keys(currentPackage.dependencies);
|
||||
const devDepKeys = Object.keys(currentPackage.devDependencies);
|
||||
const dedupedDeps = [...new Set([...depKeys, ...devDepKeys])];
|
||||
|
||||
const _depVersions: Record<string, string> = {};
|
||||
|
||||
for (const dep of dedupedDeps) {
|
||||
try {
|
||||
const packageJsonPath = require.resolve(`${dep}/package.json`, {
|
||||
paths: [process.cwd()],
|
||||
});
|
||||
const version = require(packageJsonPath).version;
|
||||
_depVersions[dep] = version;
|
||||
} catch (e) {}
|
||||
if (currentPackage) {
|
||||
const depKeys = currentPackage.dependencies ? Object.keys(currentPackage.dependencies) : [];
|
||||
const devDepKeys = currentPackage.devDependencies ? Object.keys(currentPackage.devDependencies) : [];
|
||||
const dedupedDeps = [...new Set([...depKeys, ...devDepKeys])];
|
||||
|
||||
for (const dep of dedupedDeps) {
|
||||
try {
|
||||
const packageJsonPath = require.resolve(`${dep}/package.json`, {
|
||||
paths: [process.cwd()],
|
||||
});
|
||||
const version = require(packageJsonPath).version;
|
||||
_depVersions[dep] = version;
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
export const depVersions = Object.keys(_depVersions)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import git from 'isomorphic-git';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
export interface CommitInfo {
|
||||
hash: string;
|
||||
|
@@ -15,6 +15,9 @@ i18next.init({
|
||||
translation: zh,
|
||||
},
|
||||
},
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
});
|
||||
|
||||
declare module 'i18next' {
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import fs from 'fs-extra';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import pkg from '../../package.json';
|
||||
import AppInfoParser from './app-info-parser';
|
||||
import semverSatisfies from 'semver/functions/satisfies';
|
||||
import chalk from 'chalk';
|
||||
import latestVersion from '@badisi/latest-version';
|
||||
import latestVersion from '../utils/latest-version';
|
||||
import { checkPlugins } from './check-plugin';
|
||||
|
||||
import { read } from 'read';
|
||||
@@ -98,7 +98,7 @@ export async function getAppInfo(fn: string) {
|
||||
const metaJsonFile = await appInfoParser.parser.getEntryFromHarmonyApp(
|
||||
/rawfile\/meta.json/,
|
||||
);
|
||||
let metaData = {};
|
||||
let metaData: Record<string, any> = {};
|
||||
if (metaJsonFile) {
|
||||
metaData = JSON.parse(metaJsonFile.toString());
|
||||
}
|
||||
@@ -181,16 +181,13 @@ export async function printVersionCommand() {
|
||||
version: chalk.green(latestRnuCliVersion),
|
||||
})}`
|
||||
: '';
|
||||
console.log(
|
||||
`react-native-update-cli: ${pkg.version}${latestRnuCliVersion}`,
|
||||
);
|
||||
let rnuVersion = '';
|
||||
rnuVersion = depVersions['react-native-update'];
|
||||
latestRnuVersion = latestRnuVersion
|
||||
? ` ${t('latestVersionTag', { version: chalk.green(latestRnuVersion) })}`
|
||||
: '';
|
||||
console.log(`react-native-update: ${rnuVersion}${latestRnuVersion}`);
|
||||
console.log(`react-native-update-cli: ${pkg.version}${latestRnuCliVersion}`);
|
||||
const rnuVersion = depVersions['react-native-update'];
|
||||
if (rnuVersion) {
|
||||
latestRnuVersion = latestRnuVersion
|
||||
? ` ${t('latestVersionTag', { version: chalk.green(latestRnuVersion) })}`
|
||||
: '';
|
||||
console.log(`react-native-update: ${rnuVersion}${latestRnuVersion}`);
|
||||
if (IS_CRESC) {
|
||||
if (semverSatisfies(rnuVersion, '<10.27.0')) {
|
||||
console.error(
|
||||
|
443
src/utils/latest-version/cli.ts
Normal file
443
src/utils/latest-version/cli.ts
Normal file
@@ -0,0 +1,443 @@
|
||||
import {
|
||||
blue,
|
||||
bold,
|
||||
cyan,
|
||||
gray,
|
||||
green,
|
||||
italic,
|
||||
magenta,
|
||||
red,
|
||||
reset,
|
||||
strip,
|
||||
underline,
|
||||
yellow,
|
||||
} from '@colors/colors/safe';
|
||||
import { existsSync, readFileSync } from 'fs';
|
||||
import { dirname } from 'path';
|
||||
import latestVersion, {
|
||||
type Package,
|
||||
type PackageJson,
|
||||
type LatestVersionPackage,
|
||||
type LatestVersionOptions,
|
||||
} from '.';
|
||||
import semverMajor from 'semver/functions/major';
|
||||
import semverDiff from 'semver/functions/diff';
|
||||
|
||||
interface TableColumn {
|
||||
label: string;
|
||||
attrName: keyof TableRow;
|
||||
align: 'left' | 'center' | 'right';
|
||||
maxLength: number;
|
||||
items: string[];
|
||||
}
|
||||
|
||||
type TableRowGroup =
|
||||
| 'patch'
|
||||
| 'minor'
|
||||
| 'major'
|
||||
| 'majorVersionZero'
|
||||
| 'unknown';
|
||||
|
||||
interface TableRow {
|
||||
name: string;
|
||||
location: string;
|
||||
installed: string;
|
||||
tagOrRange: string;
|
||||
separator: string;
|
||||
wanted: string;
|
||||
latest: string;
|
||||
group: TableRowGroup;
|
||||
}
|
||||
|
||||
const colorizeDiff = (from: string, to: string): string => {
|
||||
const toParts = to.split('.');
|
||||
|
||||
const diffIndex = from.split('.').findIndex((part, i) => part !== toParts[i]);
|
||||
if (diffIndex !== -1) {
|
||||
let color = magenta;
|
||||
if (toParts[0] !== '0') {
|
||||
color = diffIndex === 0 ? red : diffIndex === 1 ? cyan : green;
|
||||
}
|
||||
const start = toParts.slice(0, diffIndex).join('.');
|
||||
const mid = diffIndex === 0 ? '' : '.';
|
||||
const end = color(toParts.slice(diffIndex).join('.'));
|
||||
return `${start}${mid}${end}`;
|
||||
}
|
||||
return to;
|
||||
};
|
||||
|
||||
const columnCellRenderer = (column: TableColumn, row: TableRow): string => {
|
||||
let text = row[column.attrName];
|
||||
const gap =
|
||||
text.length < column.maxLength
|
||||
? ' '.repeat(column.maxLength - text.length)
|
||||
: '';
|
||||
|
||||
switch (column.attrName) {
|
||||
case 'name':
|
||||
text = yellow(text);
|
||||
break;
|
||||
case 'installed':
|
||||
case 'separator':
|
||||
text = blue(text);
|
||||
break;
|
||||
case 'location':
|
||||
case 'tagOrRange':
|
||||
text = gray(text);
|
||||
break;
|
||||
case 'wanted':
|
||||
text = colorizeDiff(row.installed, text);
|
||||
break;
|
||||
case 'latest':
|
||||
if (text !== row.wanted) {
|
||||
text = colorizeDiff(row.installed, text);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return column.align === 'right' ? `${gap}${text}` : `${text}${gap}`;
|
||||
};
|
||||
|
||||
const columnHeaderRenderer = (column: TableColumn): string => {
|
||||
const text = column.label;
|
||||
const gap =
|
||||
text.length < column.maxLength
|
||||
? ' '.repeat(column.maxLength - text.length)
|
||||
: '';
|
||||
return column.align === 'right'
|
||||
? `${gap}${underline(text)}`
|
||||
: `${underline(text)}${gap}`;
|
||||
};
|
||||
|
||||
const drawBox = (
|
||||
lines: string[],
|
||||
color = yellow,
|
||||
horizontalPadding = 3,
|
||||
): void => {
|
||||
const maxLineWidth = lines.reduce(
|
||||
(max, row) => Math.max(max, strip(row).length),
|
||||
0,
|
||||
);
|
||||
|
||||
console.log(color(`┌${'─'.repeat(maxLineWidth + horizontalPadding * 2)}┐`));
|
||||
lines.forEach((row) => {
|
||||
const padding = ' '.repeat(horizontalPadding);
|
||||
const fullRow = `${row}${' '.repeat(maxLineWidth - strip(row).length)}`;
|
||||
console.log(
|
||||
`${color('│')}${padding}${reset(fullRow)}${padding}${color('│')}`,
|
||||
);
|
||||
});
|
||||
console.log(color(`└${'─'.repeat(maxLineWidth + horizontalPadding * 2)}┘`));
|
||||
};
|
||||
|
||||
const getTableColumns = (rows: TableRow[]): TableColumn[] => {
|
||||
const columns: TableColumn[] = [
|
||||
{
|
||||
label: 'Package',
|
||||
attrName: 'name',
|
||||
align: 'left',
|
||||
maxLength: 0,
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
label: 'Location',
|
||||
attrName: 'location',
|
||||
align: 'left',
|
||||
maxLength: 0,
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
label: 'Installed',
|
||||
attrName: 'installed',
|
||||
align: 'right',
|
||||
maxLength: 0,
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
label: '',
|
||||
attrName: 'separator',
|
||||
align: 'center',
|
||||
maxLength: 0,
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
label: 'Range',
|
||||
attrName: 'tagOrRange',
|
||||
align: 'right',
|
||||
maxLength: 0,
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
label: '',
|
||||
attrName: 'separator',
|
||||
align: 'center',
|
||||
maxLength: 0,
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
label: 'Wanted',
|
||||
attrName: 'wanted',
|
||||
align: 'right',
|
||||
maxLength: 0,
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
label: 'Latest',
|
||||
attrName: 'latest',
|
||||
align: 'right',
|
||||
maxLength: 0,
|
||||
items: [],
|
||||
},
|
||||
];
|
||||
rows.forEach((row) => {
|
||||
columns.forEach((column) => {
|
||||
column.maxLength = Math.max(
|
||||
column.label.length,
|
||||
column.maxLength,
|
||||
row[column.attrName].length || 0,
|
||||
);
|
||||
});
|
||||
});
|
||||
return columns;
|
||||
};
|
||||
|
||||
const getTableRows = (updates: LatestVersionPackage[]): TableRow[] => {
|
||||
return updates.reduce<TableRow[]>((all, pkg) => {
|
||||
const {
|
||||
name,
|
||||
latest,
|
||||
local,
|
||||
globalNpm,
|
||||
globalYarn,
|
||||
wantedTagOrRange,
|
||||
updatesAvailable,
|
||||
} = pkg;
|
||||
const getGroup = (a?: string, b?: string): TableRowGroup => {
|
||||
if (b && semverMajor(b) === 0) {
|
||||
return 'majorVersionZero';
|
||||
} else if (a && b) {
|
||||
const releaseType = semverDiff(a, b) ?? '';
|
||||
if (['major', 'premajor', 'prerelease'].includes(releaseType)) {
|
||||
return 'major';
|
||||
} else if (['minor', 'preminor'].includes(releaseType)) {
|
||||
return 'minor';
|
||||
} else if (['patch', 'prepatch'].includes(releaseType)) {
|
||||
return 'patch';
|
||||
}
|
||||
}
|
||||
return 'unknown';
|
||||
};
|
||||
const add = (
|
||||
group: TableRowGroup,
|
||||
location: string,
|
||||
installed?: string,
|
||||
wanted?: string,
|
||||
) =>
|
||||
all.push({
|
||||
name: ' ' + name,
|
||||
location,
|
||||
installed: installed ?? 'unknown',
|
||||
latest: latest ?? 'unknown',
|
||||
tagOrRange: wantedTagOrRange ?? 'unknown',
|
||||
separator: '→',
|
||||
wanted: wanted ?? 'unknown',
|
||||
group,
|
||||
});
|
||||
if (updatesAvailable) {
|
||||
if (updatesAvailable.local) {
|
||||
add(
|
||||
getGroup(local, updatesAvailable.local),
|
||||
'local',
|
||||
local,
|
||||
updatesAvailable.local,
|
||||
);
|
||||
}
|
||||
if (updatesAvailable.globalNpm) {
|
||||
add(
|
||||
getGroup(globalNpm, updatesAvailable.globalNpm),
|
||||
'NPM global',
|
||||
globalNpm,
|
||||
updatesAvailable.globalNpm,
|
||||
);
|
||||
}
|
||||
if (updatesAvailable.globalYarn) {
|
||||
add(
|
||||
getGroup(globalYarn, updatesAvailable.globalYarn),
|
||||
'YARN global',
|
||||
globalYarn,
|
||||
updatesAvailable.globalYarn,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (local && local !== latest) {
|
||||
add(getGroup(local, latest), 'local', local, pkg.wanted);
|
||||
}
|
||||
if (globalNpm && globalNpm !== latest) {
|
||||
add(getGroup(globalNpm, latest), 'NPM global', globalNpm, pkg.wanted);
|
||||
}
|
||||
if (globalYarn && globalYarn !== latest) {
|
||||
add(
|
||||
getGroup(globalYarn, latest),
|
||||
'YARN global',
|
||||
globalYarn,
|
||||
pkg.wanted,
|
||||
);
|
||||
}
|
||||
if (!local && !globalNpm && !globalYarn) {
|
||||
add('unknown', 'unknown', 'unknown', pkg.wanted);
|
||||
}
|
||||
}
|
||||
return all;
|
||||
}, []);
|
||||
};
|
||||
|
||||
const displayTable = (latestVersionPackages: LatestVersionPackage[]): void => {
|
||||
const updates = latestVersionPackages.filter((pkg) => pkg.updatesAvailable);
|
||||
if (updates.length) {
|
||||
const rows = getTableRows(updates);
|
||||
const hasUpdates = rows.some((row) => row.installed !== 'unknown');
|
||||
const columns = getTableColumns(rows);
|
||||
const columnGap = 2;
|
||||
|
||||
const getGroupLines = (
|
||||
groupType: TableRowGroup,
|
||||
color: (str: string) => string,
|
||||
title: string,
|
||||
description?: string,
|
||||
): string[] => {
|
||||
const items = rows
|
||||
.filter((row) => row.group === groupType)
|
||||
.sort((a, b) => (a.name > b.name ? 1 : -1));
|
||||
return !items.length
|
||||
? []
|
||||
: [
|
||||
'',
|
||||
color(`${bold(title)} ${italic(`(${description})`)}`),
|
||||
...items.map((row) =>
|
||||
columns
|
||||
.map((column) => columnCellRenderer(column, row))
|
||||
.join(' '.repeat(columnGap)),
|
||||
),
|
||||
];
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
||||
drawBox(
|
||||
[
|
||||
'',
|
||||
hasUpdates ? yellow('Important updates are available.') : undefined,
|
||||
hasUpdates ? '' : undefined,
|
||||
columns.map(columnHeaderRenderer).join(' '.repeat(columnGap)),
|
||||
...getGroupLines(
|
||||
'patch',
|
||||
green,
|
||||
'Patch',
|
||||
'backwards-compatible bug fixes',
|
||||
),
|
||||
...getGroupLines(
|
||||
'minor',
|
||||
cyan,
|
||||
'Minor',
|
||||
'backwards-compatible features',
|
||||
),
|
||||
...getGroupLines(
|
||||
'major',
|
||||
red,
|
||||
'Major',
|
||||
'potentially breaking API changes',
|
||||
),
|
||||
...getGroupLines(
|
||||
'majorVersionZero',
|
||||
magenta,
|
||||
'Major version zero',
|
||||
'not stable, anything may change',
|
||||
),
|
||||
...getGroupLines('unknown', blue, 'Missing', 'not installed'),
|
||||
'',
|
||||
].filter((line) => line !== undefined) as string[],
|
||||
);
|
||||
} else {
|
||||
console.log(green('🎉 Packages are up-to-date'));
|
||||
}
|
||||
};
|
||||
|
||||
const checkVersions = async (
|
||||
packages: Package | Package[] | PackageJson,
|
||||
skipMissing: boolean,
|
||||
options: LatestVersionOptions = { useCache: true },
|
||||
): Promise<void> => {
|
||||
const ora = (await import('ora')).default;
|
||||
const spinner = ora({ text: cyan('Checking versions...') });
|
||||
spinner.start();
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
let latestVersionPackages: LatestVersionPackage[] = await latestVersion(
|
||||
packages,
|
||||
options,
|
||||
);
|
||||
if (skipMissing) {
|
||||
latestVersionPackages = latestVersionPackages.filter(
|
||||
(pkg) => pkg.local ?? pkg.globalNpm ?? pkg.globalYarn,
|
||||
);
|
||||
}
|
||||
spinner.stop();
|
||||
displayTable(latestVersionPackages);
|
||||
};
|
||||
|
||||
void (async () => {
|
||||
let args = process.argv.slice(2);
|
||||
|
||||
const skipMissing = args.includes('--skip-missing');
|
||||
|
||||
// Remove any options from the arguments
|
||||
args = args.filter((arg) => !arg.startsWith('-'));
|
||||
|
||||
// If argument is a package.json file
|
||||
if (args.length === 1 && args[0].endsWith('package.json')) {
|
||||
if (existsSync(args[0])) {
|
||||
process.chdir(dirname(args[0]));
|
||||
await checkVersions(
|
||||
JSON.parse(readFileSync(args[0]).toString()) as PackageJson,
|
||||
skipMissing,
|
||||
);
|
||||
} else {
|
||||
console.log(cyan('No package.json file were found'));
|
||||
}
|
||||
}
|
||||
// else..
|
||||
else {
|
||||
// Check if a local package.json file exists
|
||||
let localPkgJson: PackageJson | undefined;
|
||||
if (existsSync('package.json')) {
|
||||
localPkgJson = JSON.parse(readFileSync('package.json').toString());
|
||||
}
|
||||
|
||||
// Check given arguments
|
||||
if (args.length) {
|
||||
// Map arguments with any range that could be found in local package.json
|
||||
args = args.map((arg) => {
|
||||
if (localPkgJson?.dependencies?.[arg]) {
|
||||
return `${arg}@${localPkgJson.dependencies?.[arg]}`;
|
||||
}
|
||||
if (localPkgJson?.devDependencies?.[arg]) {
|
||||
return `${arg}@${localPkgJson.devDependencies?.[arg]}`;
|
||||
}
|
||||
if (localPkgJson?.peerDependencies?.[arg]) {
|
||||
return `${arg}@${localPkgJson.peerDependencies?.[arg]}`;
|
||||
}
|
||||
return arg;
|
||||
});
|
||||
await checkVersions(args, skipMissing);
|
||||
}
|
||||
// ...else check the local package.json if any
|
||||
else if (localPkgJson) {
|
||||
await checkVersions(localPkgJson, skipMissing);
|
||||
}
|
||||
// ...else do nothing
|
||||
else {
|
||||
console.log(cyan('No packages were found'));
|
||||
}
|
||||
}
|
||||
})();
|
497
src/utils/latest-version/index.ts
Normal file
497
src/utils/latest-version/index.ts
Normal file
@@ -0,0 +1,497 @@
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
||||
import type {
|
||||
RequestOptions as HttpRequestOptions,
|
||||
Agent,
|
||||
IncomingMessage,
|
||||
} from 'http';
|
||||
import type { RequestOptions as HttpsRequestOptions } from 'https';
|
||||
import { join, dirname, resolve as pathResolve, parse } from 'path';
|
||||
import { npm, yarn } from 'global-dirs';
|
||||
import { homedir } from 'os';
|
||||
import { URL } from 'url';
|
||||
|
||||
import getRegistryUrl from 'registry-auth-token/registry-url';
|
||||
import registryAuthToken from 'registry-auth-token';
|
||||
import maxSatisfying from 'semver/ranges/max-satisfying';
|
||||
import gt from 'semver/functions/gt';
|
||||
|
||||
interface RegistryVersions {
|
||||
/**
|
||||
* The latest version of the package found on the registry (if found).
|
||||
*/
|
||||
latest?: string;
|
||||
/**
|
||||
* The next version of the package found on the registry (if found).
|
||||
*/
|
||||
next?: string;
|
||||
/**
|
||||
* The latest version of the package found on the registry and satisfied by the wanted tag or version range.
|
||||
*/
|
||||
wanted?: string;
|
||||
}
|
||||
|
||||
interface InstalledVersions {
|
||||
/**
|
||||
* The current local installed version of the package (if installed).
|
||||
*/
|
||||
local?: string;
|
||||
/**
|
||||
* The current npm global installed version of the package (if installed).
|
||||
*/
|
||||
globalNpm?: string;
|
||||
/**
|
||||
* The current yarn global installed version of the package (if installed).
|
||||
*/
|
||||
globalYarn?: string;
|
||||
}
|
||||
|
||||
interface LatestVersionPackage extends InstalledVersions, RegistryVersions {
|
||||
/**
|
||||
* The name of the package.
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* The tag or version range that was provided (if provided).
|
||||
* @default "latest"
|
||||
*/
|
||||
wantedTagOrRange?: string;
|
||||
/**
|
||||
* Whether the local or global installed versions (if any) could be upgraded or not, based on the wanted version.
|
||||
*/
|
||||
updatesAvailable:
|
||||
| {
|
||||
local: string | false;
|
||||
globalNpm: string | false;
|
||||
globalYarn: string | false;
|
||||
}
|
||||
| false;
|
||||
/**
|
||||
* Any error that might have occurred during the process.
|
||||
*/
|
||||
error?: Error;
|
||||
}
|
||||
|
||||
interface RequestOptions {
|
||||
readonly ca?: string | Buffer | Array<string | Buffer>;
|
||||
readonly rejectUnauthorized?: boolean;
|
||||
readonly agent?: Agent | boolean;
|
||||
readonly timeout?: number;
|
||||
}
|
||||
|
||||
interface LatestVersionOptions {
|
||||
/**
|
||||
* Awaiting the api to return might take time, depending on the network, and might impact your package loading performance.
|
||||
* You can use the cache mechanism to improve load performance and reduce unnecessary network requests.
|
||||
* If `useCache` is not supplied, the api will always check for updates and wait for every requests to return before returning itself.
|
||||
* If `useCache` is used, the api will always returned immediately, with either (for each provided packages):
|
||||
* 1) a latest/next version available if a cache was found
|
||||
* 2) no latest/next version available if no cache was found - in such case updates will be fetched in the background and a cache will
|
||||
* be created for each provided packages and made available for the next call to the api.
|
||||
* @default false
|
||||
*/
|
||||
readonly useCache?: boolean;
|
||||
|
||||
/**
|
||||
* How long the cache for the provided packages should be used before being refreshed (in milliseconds).
|
||||
* If `useCache` is not supplied, this option has no effect.
|
||||
* If `0` is used, this will force the cache to refresh immediately:
|
||||
* 1) The api will returned immediately (without any latest nor next version available for the provided packages)
|
||||
* 2) New updates will be fetched in the background
|
||||
* 3) The cache for each provided packages will be refreshed and made available for the next call to the api
|
||||
* @default ONE_DAY
|
||||
*/
|
||||
readonly cacheMaxAge?: number;
|
||||
|
||||
/**
|
||||
* A JavaScript package registry url that implements the CommonJS Package Registry specification.
|
||||
* @default "Looks at any registry urls in the .npmrc file or fallback to the default npm registry instead"
|
||||
* @example <caption>.npmrc</caption>
|
||||
* registry = 'https://custom-registry.com/'
|
||||
* @pkgscope:registry = 'https://custom-registry.com/'
|
||||
*/
|
||||
readonly registryUrl?: string;
|
||||
|
||||
/**
|
||||
* Set of options to be passed down to Node.js http/https request.
|
||||
* @example <caption>Behind a proxy with self-signed certificate</caption>
|
||||
* { ca: [ fs.readFileSync('proxy-cert.pem') ] }
|
||||
* @example <caption>Bypassing certificate validation</caption>
|
||||
* { rejectUnauthorized: false }
|
||||
*/
|
||||
readonly requestOptions?: RequestOptions;
|
||||
}
|
||||
|
||||
interface LatestVersion {
|
||||
/**
|
||||
* Get latest versions of packages from of a package json like object.
|
||||
* @param {PackageJson} item - A package json like object (with dependencies, devDependencies and peerDependencies attributes).
|
||||
* @example { dependencies: { 'npm': 'latest' }, devDependencies: { 'npm': '1.3.2' }, peerDependencies: { '@scope/name': '^5.0.2' } }
|
||||
* @param {LatestVersionOptions} [options] - An object optionally specifying the use of the cache, the max age of the cache, the registry url and the http or https options.
|
||||
* If `useCache` is not supplied, the default of `false` is used.
|
||||
* If `cacheMaxAge` is not supplied, the default of `one day` is used.
|
||||
* If `registryUrl` is not supplied, the default from `.npmrc` is used or a fallback to the `npm registry url` instead.
|
||||
* @returns {Promise<LatestVersionPackage[]>}
|
||||
*/
|
||||
(item: PackageJson, options?: LatestVersionOptions): Promise<
|
||||
LatestVersionPackage[]
|
||||
>;
|
||||
|
||||
/**
|
||||
* Get latest version of a single package.
|
||||
* @param {Package} item - A single package object (represented by a string that should match the following format: `${'@' | ''}${string}@${string}`)
|
||||
* @example 'npm', 'npm@1.3.2', '@scope/name@^5.0.2'
|
||||
* @param {LatestVersionOptions} [options] - An object optionally specifying the use of the cache, the max age of the cache, the registry url and the http or https options.
|
||||
* If `useCache` is not supplied, the default of `false` is used.
|
||||
* If `cacheMaxAge` is not supplied, the default of `one day` is used.
|
||||
* If `registryUrl` is not supplied, the default from `.npmrc` is used or a fallback to the npm registry url instead.
|
||||
* @returns {Promise<LatestVersionPackage>}
|
||||
*/
|
||||
(
|
||||
item: Package,
|
||||
options?: LatestVersionOptions,
|
||||
): Promise<LatestVersionPackage>;
|
||||
|
||||
/**
|
||||
* Get latest versions of a collection of packages.
|
||||
* @param {Package[]} items - A collection of package object (represented by a string that should match the following format: `${'@' | ''}${string}@${string}`)
|
||||
* @example ['npm', 'npm@1.3.2', '@scope/name@^5.0.2']
|
||||
* @param {LatestVersionOptions} [options] - An object optionally specifying the use of the cache, the max age of the cache, the registry url and the http or https options.
|
||||
* If `useCache` is not supplied, the default of `false` is used.
|
||||
* If `cacheMaxAge` is not supplied, the default of `one day` is used.
|
||||
* If `registryUrl` is not supplied, the default from `.npmrc` is used or a fallback to the npm registry url instead.
|
||||
* @returns {Promise<LatestVersionPackage[]>}
|
||||
*/
|
||||
(items: Package[], options?: LatestVersionOptions): Promise<
|
||||
LatestVersionPackage[]
|
||||
>; // eslint-disable-line @typescript-eslint/unified-signatures
|
||||
}
|
||||
type PackageRange = `${'@' | ''}${string}@${string}`;
|
||||
type Package = PackageRange | string; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents
|
||||
type PackageJsonDependencies = Record<string, string>;
|
||||
type PackageJson = Record<string, any> &
|
||||
(
|
||||
| {
|
||||
dependencies: PackageJsonDependencies;
|
||||
}
|
||||
| {
|
||||
devDependencies: PackageJsonDependencies;
|
||||
}
|
||||
| {
|
||||
peerDependencies: PackageJsonDependencies;
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
interface PackageMetadata {
|
||||
name: string;
|
||||
lastUpdateDate: number;
|
||||
versions: string[];
|
||||
distTags: Record<string, string>;
|
||||
}
|
||||
|
||||
export const ONE_DAY = 1000 * 60 * 60 * 24; // eslint-disable-line @typescript-eslint/naming-convention
|
||||
|
||||
const isPackageJson = (obj: any): obj is PackageJson => {
|
||||
return (
|
||||
(obj as PackageJson).dependencies !== undefined ||
|
||||
(obj as PackageJson).devDependencies !== undefined ||
|
||||
(obj as PackageJson).peerDependencies !== undefined
|
||||
);
|
||||
};
|
||||
|
||||
const downloadMetadata = (
|
||||
pkgName: string,
|
||||
options?: LatestVersionOptions,
|
||||
): Promise<PackageMetadata> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const i = pkgName.indexOf('/');
|
||||
const pkgScope = i !== -1 ? pkgName.slice(0, i) : '';
|
||||
const registryUrl = options?.registryUrl ?? getRegistryUrl(pkgScope);
|
||||
const pkgUrl = new URL(
|
||||
encodeURIComponent(pkgName).replace(/^%40/, '@'),
|
||||
registryUrl,
|
||||
);
|
||||
|
||||
let requestOptions: HttpRequestOptions | HttpsRequestOptions = {
|
||||
headers: {
|
||||
accept:
|
||||
'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*',
|
||||
},
|
||||
host: pkgUrl.hostname,
|
||||
path: pkgUrl.pathname,
|
||||
port: pkgUrl.port,
|
||||
};
|
||||
const authInfo = registryAuthToken(pkgUrl.toString(), { recursive: true });
|
||||
if (authInfo && requestOptions.headers) {
|
||||
requestOptions.headers.authorization = `${authInfo.type} ${authInfo.token}`;
|
||||
}
|
||||
if (options?.requestOptions) {
|
||||
requestOptions = { ...requestOptions, ...options.requestOptions };
|
||||
}
|
||||
|
||||
const { get } = require(pkgUrl.protocol === 'https:' ? 'https' : 'http');
|
||||
const request = get(requestOptions, (res: IncomingMessage) => {
|
||||
if (res.statusCode === 200) {
|
||||
let rawData = '';
|
||||
res.setEncoding('utf8');
|
||||
res.on('data', (chunk: string) => (rawData += chunk));
|
||||
res.once('error', (err) => {
|
||||
res.removeAllListeners();
|
||||
reject(`Request error (${err.message}): ${pkgUrl}`);
|
||||
});
|
||||
res.once('end', () => {
|
||||
res.removeAllListeners();
|
||||
try {
|
||||
const pkgMetadata = JSON.parse(rawData);
|
||||
resolve({
|
||||
name: pkgName,
|
||||
lastUpdateDate: Date.now(),
|
||||
versions: Object.keys(pkgMetadata.versions as string[]),
|
||||
distTags: pkgMetadata['dist-tags'],
|
||||
});
|
||||
return;
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.removeAllListeners();
|
||||
res.resume(); // consume response data to free up memory
|
||||
reject(`Request error (${res.statusCode}): ${pkgUrl}`);
|
||||
return;
|
||||
}
|
||||
});
|
||||
const abort = (error: Error | string): void => {
|
||||
request.destroy();
|
||||
reject(error);
|
||||
};
|
||||
request.once('timeout', () => {
|
||||
abort(`Request timed out: ${pkgUrl}`);
|
||||
});
|
||||
request.once('error', (err: Error) => {
|
||||
abort(err);
|
||||
});
|
||||
request.on('close', () => {
|
||||
request.removeAllListeners();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const getCacheDir = (name = '@badisi/latest-version'): string => {
|
||||
const homeDir = homedir();
|
||||
switch (process.platform) {
|
||||
case 'darwin':
|
||||
return join(homeDir, 'Library', 'Caches', name);
|
||||
case 'win32':
|
||||
return join(
|
||||
process.env.LOCALAPPDATA ?? join(homeDir, 'AppData', 'Local'),
|
||||
name,
|
||||
'Cache',
|
||||
);
|
||||
default:
|
||||
return join(process.env.XDG_CACHE_HOME ?? join(homeDir, '.cache'), name);
|
||||
}
|
||||
};
|
||||
|
||||
const saveMetadataToCache = (pkg: PackageMetadata): void => {
|
||||
const filePath = join(getCacheDir(), `${pkg.name}.json`);
|
||||
if (!existsSync(dirname(filePath))) {
|
||||
mkdirSync(dirname(filePath), { recursive: true });
|
||||
}
|
||||
writeFileSync(filePath, JSON.stringify(pkg));
|
||||
};
|
||||
|
||||
const getMetadataFromCache = (
|
||||
pkgName: string,
|
||||
options?: LatestVersionOptions,
|
||||
): PackageMetadata | undefined => {
|
||||
const maxAge = options?.cacheMaxAge ?? ONE_DAY;
|
||||
if (maxAge !== 0) {
|
||||
const pkgCacheFilePath = join(getCacheDir(), `${pkgName}.json`);
|
||||
if (existsSync(pkgCacheFilePath)) {
|
||||
const pkg = JSON.parse(
|
||||
readFileSync(pkgCacheFilePath).toString(),
|
||||
) as PackageMetadata;
|
||||
if (Date.now() - pkg.lastUpdateDate < maxAge) {
|
||||
return pkg;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined; // invalidates cache
|
||||
};
|
||||
|
||||
const getRegistryVersions = async (
|
||||
pkgName: string,
|
||||
tagOrRange?: string,
|
||||
options?: LatestVersionOptions,
|
||||
): Promise<RegistryVersions> => {
|
||||
let pkgMetadata: PackageMetadata | undefined;
|
||||
if (pkgName.length && options?.useCache) {
|
||||
pkgMetadata = getMetadataFromCache(pkgName, options);
|
||||
if (!pkgMetadata) {
|
||||
pkgMetadata = await downloadMetadata(pkgName, options);
|
||||
saveMetadataToCache(pkgMetadata);
|
||||
}
|
||||
} else if (pkgName.length) {
|
||||
pkgMetadata = await downloadMetadata(pkgName, options);
|
||||
}
|
||||
|
||||
const versions: RegistryVersions = {
|
||||
latest: pkgMetadata?.distTags.latest,
|
||||
next: pkgMetadata?.distTags.next,
|
||||
};
|
||||
if (tagOrRange && pkgMetadata?.distTags[tagOrRange]) {
|
||||
versions.wanted = pkgMetadata.distTags[tagOrRange];
|
||||
} else if (tagOrRange && pkgMetadata?.versions.length) {
|
||||
versions.wanted =
|
||||
maxSatisfying(pkgMetadata.versions, tagOrRange) ?? undefined;
|
||||
}
|
||||
return versions;
|
||||
};
|
||||
|
||||
const getInstalledVersion = (
|
||||
pkgName: string,
|
||||
location: keyof InstalledVersions = 'local',
|
||||
): string | undefined => {
|
||||
try {
|
||||
if (location === 'globalNpm') {
|
||||
return require(join(npm.packages, pkgName, 'package.json'))
|
||||
?.version as string;
|
||||
} else if (location === 'globalYarn') {
|
||||
// Make sure package is globally installed by Yarn
|
||||
const yarnGlobalPkg = require(pathResolve(
|
||||
yarn.packages,
|
||||
'..',
|
||||
'package.json',
|
||||
));
|
||||
if (!yarnGlobalPkg?.dependencies?.[pkgName]) {
|
||||
return undefined;
|
||||
}
|
||||
return require(join(yarn.packages, pkgName, 'package.json'))
|
||||
?.version as string;
|
||||
} else {
|
||||
/**
|
||||
* Compute the local paths manually as require.resolve() and require.resolve.paths()
|
||||
* cannot be trusted anymore.
|
||||
* @see https://github.com/nodejs/node/issues/33460
|
||||
* @see https://github.com/nodejs/loaders/issues/26
|
||||
*/
|
||||
const { root } = parse(process.cwd());
|
||||
let path = process.cwd();
|
||||
const localPaths = [join(path, 'node_modules')];
|
||||
while (path !== root) {
|
||||
path = dirname(path);
|
||||
localPaths.push(join(path, 'node_modules'));
|
||||
}
|
||||
for (const localPath of localPaths) {
|
||||
const pkgPath = join(localPath, pkgName, 'package.json');
|
||||
if (existsSync(pkgPath)) {
|
||||
return require(pkgPath)?.version as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const getInfo = async (
|
||||
pkg: Package,
|
||||
options?: LatestVersionOptions,
|
||||
): Promise<LatestVersionPackage> => {
|
||||
const i = pkg.lastIndexOf('@');
|
||||
let pkgInfo: LatestVersionPackage = {
|
||||
name: i > 1 ? pkg.slice(0, i) : pkg,
|
||||
wantedTagOrRange: i > 1 ? pkg.slice(i + 1) : 'latest',
|
||||
updatesAvailable: false,
|
||||
};
|
||||
|
||||
try {
|
||||
pkgInfo = {
|
||||
...pkgInfo,
|
||||
local: getInstalledVersion(pkgInfo.name, 'local'),
|
||||
globalNpm: getInstalledVersion(pkgInfo.name, 'globalNpm'),
|
||||
globalYarn: getInstalledVersion(pkgInfo.name, 'globalYarn'),
|
||||
...(await getRegistryVersions(
|
||||
pkgInfo.name,
|
||||
pkgInfo.wantedTagOrRange,
|
||||
options,
|
||||
)),
|
||||
};
|
||||
const local =
|
||||
pkgInfo.local && pkgInfo.wanted
|
||||
? gt(pkgInfo.wanted, pkgInfo.local)
|
||||
? pkgInfo.wanted
|
||||
: false
|
||||
: false;
|
||||
const globalNpm =
|
||||
pkgInfo.globalNpm && pkgInfo.wanted
|
||||
? gt(pkgInfo.wanted, pkgInfo.globalNpm)
|
||||
? pkgInfo.wanted
|
||||
: false
|
||||
: false;
|
||||
const globalYarn =
|
||||
pkgInfo.globalYarn && pkgInfo.wanted
|
||||
? gt(pkgInfo.wanted, pkgInfo.globalYarn)
|
||||
? pkgInfo.wanted
|
||||
: false
|
||||
: false;
|
||||
pkgInfo.updatesAvailable =
|
||||
local || globalNpm || globalYarn
|
||||
? { local, globalNpm, globalYarn }
|
||||
: false;
|
||||
} catch (err: any) {
|
||||
pkgInfo.error = err?.message ?? err;
|
||||
}
|
||||
|
||||
return pkgInfo;
|
||||
};
|
||||
|
||||
const latestVersion: LatestVersion = async (
|
||||
arg: Package | Package[] | PackageJson,
|
||||
options?: LatestVersionOptions,
|
||||
): Promise<any> => {
|
||||
const pkgs: Package[] = [];
|
||||
if (typeof arg === 'string') {
|
||||
pkgs.push(arg);
|
||||
} else if (Array.isArray(arg)) {
|
||||
pkgs.push(...arg);
|
||||
} else if (isPackageJson(arg)) {
|
||||
const addDeps = (deps?: PackageJsonDependencies): void => {
|
||||
if (deps) {
|
||||
pkgs.push(
|
||||
...Object.keys(deps).map((key: string) => `${key}@${deps[key]}`),
|
||||
);
|
||||
}
|
||||
};
|
||||
addDeps(arg.dependencies as PackageJsonDependencies | undefined);
|
||||
addDeps(arg.devDependencies as PackageJsonDependencies | undefined);
|
||||
addDeps(arg.peerDependencies as PackageJsonDependencies | undefined);
|
||||
}
|
||||
|
||||
const jobs = await Promise.allSettled(
|
||||
pkgs.map((pkg) => getInfo(pkg, options)),
|
||||
);
|
||||
const results = jobs.map(
|
||||
(jobResult: PromiseSettledResult<LatestVersionPackage>) =>
|
||||
(jobResult as PromiseFulfilledResult<LatestVersionPackage>).value,
|
||||
);
|
||||
return typeof arg === 'string' ? results[0] : results;
|
||||
};
|
||||
|
||||
export type {
|
||||
LatestVersion,
|
||||
Package,
|
||||
PackageRange,
|
||||
PackageJson,
|
||||
PackageJsonDependencies,
|
||||
RegistryVersions,
|
||||
LatestVersionPackage,
|
||||
RequestOptions,
|
||||
LatestVersionOptions,
|
||||
};
|
||||
export default latestVersion;
|
271
src/versions.ts
271
src/versions.ts
@@ -1,25 +1,13 @@
|
||||
import { get, post, put, uploadFile } from './api';
|
||||
import { get, getAllPackages, post, put, uploadFile } from './api';
|
||||
import { question, saveToLocal } from './utils';
|
||||
import { t } from './utils/i18n';
|
||||
|
||||
import { checkPlatform, getSelectedApp } from './app';
|
||||
import { getPlatform, getSelectedApp } from './app';
|
||||
import { choosePackage } from './package';
|
||||
import { compare } from 'compare-versions';
|
||||
import { depVersions } from './utils/dep-versions';
|
||||
import { getCommitInfo } from './utils/git';
|
||||
import type { Platform } from 'types';
|
||||
|
||||
interface Package {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface Version {
|
||||
id: string;
|
||||
hash: string;
|
||||
name: string;
|
||||
packages?: Package[];
|
||||
}
|
||||
import type { Package, Platform, Version } from 'types';
|
||||
import semverSatisfies from 'semver/functions/satisfies';
|
||||
|
||||
interface CommandOptions {
|
||||
name?: string;
|
||||
@@ -31,6 +19,7 @@ interface CommandOptions {
|
||||
packageVersion?: string;
|
||||
minPackageVersion?: string;
|
||||
maxPackageVersion?: string;
|
||||
semverRange?: string;
|
||||
rollout?: string;
|
||||
}
|
||||
|
||||
@@ -113,6 +102,49 @@ async function chooseVersion(appId: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export const bindVersionToPackages = async ({
|
||||
appId,
|
||||
versionId,
|
||||
pkgs,
|
||||
rollout,
|
||||
}: {
|
||||
appId: string;
|
||||
versionId: string;
|
||||
pkgs: Package[];
|
||||
rollout?: number;
|
||||
}) => {
|
||||
if (rollout !== undefined) {
|
||||
const rolloutConfig: Record<string, number> = {};
|
||||
for (const pkg of pkgs) {
|
||||
rolloutConfig[pkg.name] = rollout;
|
||||
}
|
||||
await put(`/app/${appId}/version/${versionId}`, {
|
||||
config: {
|
||||
rollout: rolloutConfig,
|
||||
},
|
||||
});
|
||||
console.log(
|
||||
`${t('rolloutConfigSet', {
|
||||
versions: pkgs.map((pkg: Package) => pkg.name).join(', '),
|
||||
rollout: rollout,
|
||||
})}`,
|
||||
);
|
||||
}
|
||||
for (const pkg of pkgs) {
|
||||
await put(`/app/${appId}/package/${pkg.id}`, {
|
||||
versionId,
|
||||
});
|
||||
console.log(
|
||||
`${t('versionBind', {
|
||||
version: versionId,
|
||||
nativeVersion: pkg.name,
|
||||
id: pkg.id,
|
||||
})}`,
|
||||
);
|
||||
}
|
||||
console.log(t('operationComplete', { count: pkgs.length }));
|
||||
};
|
||||
|
||||
export const commands = {
|
||||
publish: async function ({
|
||||
args,
|
||||
@@ -125,26 +157,21 @@ export const commands = {
|
||||
const { name, description, metaInfo } = options;
|
||||
|
||||
if (!fn || !fn.endsWith('.ppk')) {
|
||||
throw new Error(
|
||||
'使用方法: pushy publish ppk后缀文件 --platform ios|android|harmony',
|
||||
);
|
||||
throw new Error(t('publishUsage'));
|
||||
}
|
||||
|
||||
const platform = checkPlatform(
|
||||
options.platform ||
|
||||
((await question('平台(ios/android/harmony):')) as Platform),
|
||||
);
|
||||
const platform = await getPlatform(options.platform);
|
||||
const { appId } = await getSelectedApp(platform);
|
||||
|
||||
const { hash } = await uploadFile(fn);
|
||||
|
||||
const versionName =
|
||||
name || (await question('输入版本名称: ')) || '(未命名)';
|
||||
name || (await question(t('versionNameQuestion'))) || t('unnamed');
|
||||
const { id } = await post(`/app/${appId}/version/create`, {
|
||||
name: versionName,
|
||||
hash,
|
||||
description: description || (await question('输入版本描述:')),
|
||||
metaInfo: metaInfo || (await question('输入自定义的 meta info:')),
|
||||
description: description || (await question(t('versionDescriptionQuestion'))),
|
||||
metaInfo: metaInfo || (await question(t('versionMetaInfoQuestion'))),
|
||||
deps: depVersions,
|
||||
commit: await getCommitInfo(),
|
||||
});
|
||||
@@ -152,17 +179,14 @@ export const commands = {
|
||||
saveToLocal(fn, `${appId}/ppk/${id}.ppk`);
|
||||
console.log(t('packageUploadSuccess', { id }));
|
||||
|
||||
const v = await question('是否现在将此热更应用到原生包上?(Y/N)');
|
||||
const v = await question(t('updateNativePackageQuestion'));
|
||||
if (v.toLowerCase() === 'y') {
|
||||
await this.update({ args: [], options: { versionId: id, platform } });
|
||||
}
|
||||
return versionName;
|
||||
},
|
||||
versions: async ({ options }: { options: CommandOptions }) => {
|
||||
const platform = checkPlatform(
|
||||
options.platform ||
|
||||
((await question('平台(ios/android/harmony):')) as Platform),
|
||||
);
|
||||
const platform = await getPlatform(options.platform);
|
||||
const { appId } = await getSelectedApp(platform);
|
||||
await listVersions(appId);
|
||||
},
|
||||
@@ -173,20 +197,18 @@ export const commands = {
|
||||
args: string[];
|
||||
options: CommandOptions;
|
||||
}) => {
|
||||
const platform = checkPlatform(
|
||||
options.platform ||
|
||||
((await question('平台(ios/android/harmony):')) as Platform),
|
||||
);
|
||||
const platform = await getPlatform(options.platform);
|
||||
const { appId } = await getSelectedApp(platform);
|
||||
let versionId = options.versionId || (await chooseVersion(appId)).id;
|
||||
if (versionId === 'null') {
|
||||
versionId = undefined;
|
||||
}
|
||||
|
||||
let pkgId: string | undefined;
|
||||
let pkgId = options.packageId;
|
||||
let pkgVersion = options.packageVersion;
|
||||
let minPkgVersion = options.minPackageVersion;
|
||||
let maxPkgVersion = options.maxPackageVersion;
|
||||
let semverRange = options.semverRange;
|
||||
let rollout: number | undefined = undefined;
|
||||
|
||||
if (options.rollout !== undefined) {
|
||||
@@ -200,142 +222,78 @@ export const commands = {
|
||||
}
|
||||
}
|
||||
|
||||
const allPkgs = await getAllPackages(appId);
|
||||
|
||||
if (!allPkgs) {
|
||||
throw new Error(t('noPackagesFound', { appId }));
|
||||
}
|
||||
|
||||
let pkgsToBind: Package[] = [];
|
||||
|
||||
if (minPkgVersion) {
|
||||
minPkgVersion = String(minPkgVersion).trim();
|
||||
const { data } = await get(`/app/${appId}/package/list?limit=1000`);
|
||||
const pkgs = data.filter((pkg: Package) =>
|
||||
compare(pkg.name, minPkgVersion, '>='),
|
||||
pkgsToBind = allPkgs.filter((pkg: Package) =>
|
||||
semverSatisfies(pkg.name, `>=${minPkgVersion}`),
|
||||
);
|
||||
if (pkgs.length === 0) {
|
||||
throw new Error(t('nativeVersionNotFound', { version: minPkgVersion }));
|
||||
}
|
||||
if (rollout !== undefined) {
|
||||
const rolloutConfig: Record<string, number> = {};
|
||||
for (const pkg of pkgs) {
|
||||
rolloutConfig[pkg.name] = rollout;
|
||||
}
|
||||
await put(`/app/${appId}/version/${versionId}`, {
|
||||
config: {
|
||||
rollout: rolloutConfig,
|
||||
},
|
||||
});
|
||||
console.log(
|
||||
`${t('rolloutConfigSet', {
|
||||
versions: pkgs.map((pkg: Package) => pkg.name).join(', '),
|
||||
rollout: rollout,
|
||||
})}`,
|
||||
if (pkgsToBind.length === 0) {
|
||||
throw new Error(
|
||||
t('nativeVersionNotFoundGte', { version: minPkgVersion }),
|
||||
);
|
||||
}
|
||||
for (const pkg of pkgs) {
|
||||
await put(`/app/${appId}/package/${pkg.id}`, {
|
||||
versionId,
|
||||
});
|
||||
console.log(
|
||||
`${t('versionBind', {
|
||||
version: versionId,
|
||||
nativeVersion: pkg.name,
|
||||
id: pkg.id,
|
||||
})}`,
|
||||
);
|
||||
}
|
||||
console.log(t('operationComplete', { count: pkgs.length }));
|
||||
return;
|
||||
}
|
||||
if (maxPkgVersion) {
|
||||
} else if (maxPkgVersion) {
|
||||
maxPkgVersion = String(maxPkgVersion).trim();
|
||||
const { data } = await get(`/app/${appId}/package/list?limit=1000`);
|
||||
const pkgs = data.filter((pkg: Package) =>
|
||||
compare(pkg.name, maxPkgVersion, '<='),
|
||||
pkgsToBind = allPkgs.filter((pkg: Package) =>
|
||||
semverSatisfies(pkg.name, `<=${maxPkgVersion}`),
|
||||
);
|
||||
if (pkgs.length === 0) {
|
||||
throw new Error(t('nativeVersionNotFoundLess', { version: maxPkgVersion }));
|
||||
}
|
||||
if (rollout !== undefined) {
|
||||
const rolloutConfig: Record<string, number> = {};
|
||||
for (const pkg of pkgs) {
|
||||
rolloutConfig[pkg.name] = rollout;
|
||||
}
|
||||
await put(`/app/${appId}/version/${versionId}`, {
|
||||
config: {
|
||||
rollout: rolloutConfig,
|
||||
},
|
||||
});
|
||||
console.log(
|
||||
`${t('rolloutConfigSet', {
|
||||
versions: pkgs.map((pkg: Package) => pkg.name).join(', '),
|
||||
rollout: rollout,
|
||||
})}`,
|
||||
if (pkgsToBind.length === 0) {
|
||||
throw new Error(
|
||||
t('nativeVersionNotFoundLte', { version: maxPkgVersion }),
|
||||
);
|
||||
}
|
||||
for (const pkg of pkgs) {
|
||||
await put(`/app/${appId}/package/${pkg.id}`, {
|
||||
versionId,
|
||||
});
|
||||
console.log(
|
||||
`${t('versionBind', {
|
||||
version: versionId,
|
||||
nativeVersion: pkg.name,
|
||||
id: pkg.id,
|
||||
})}`,
|
||||
);
|
||||
}
|
||||
console.log(t('operationComplete', { count: pkgs.length }));
|
||||
return;
|
||||
}
|
||||
|
||||
const { data } = await get(`/app/${appId}/package/list?limit=1000`);
|
||||
if (pkgVersion) {
|
||||
} else if (pkgVersion) {
|
||||
pkgVersion = pkgVersion.trim();
|
||||
const pkg = data.find((pkg: Package) => pkg.name === pkgVersion);
|
||||
const pkg = allPkgs.find((pkg: Package) => pkg.name === pkgVersion);
|
||||
if (pkg) {
|
||||
pkgId = pkg.id;
|
||||
pkgsToBind = [pkg];
|
||||
} else {
|
||||
throw new Error(t('nativeVersionNotFoundMatch', { version: pkgVersion }));
|
||||
throw new Error(
|
||||
t('nativeVersionNotFoundMatch', { version: pkgVersion }),
|
||||
);
|
||||
}
|
||||
} else if (semverRange) {
|
||||
semverRange = semverRange.trim();
|
||||
pkgsToBind = allPkgs.filter((pkg: Package) =>
|
||||
semverSatisfies(pkg.name, semverRange!),
|
||||
);
|
||||
if (pkgsToBind.length === 0) {
|
||||
throw new Error(
|
||||
t('nativeVersionNotFoundMatch', { version: semverRange }),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (!pkgId) {
|
||||
pkgId = (await choosePackage(appId)).id;
|
||||
}
|
||||
}
|
||||
if (!pkgId) {
|
||||
pkgId = options.packageId || (await choosePackage(appId)).id;
|
||||
}
|
||||
|
||||
if (!pkgId) {
|
||||
throw new Error(t('packageIdRequired'));
|
||||
}
|
||||
|
||||
if (!pkgVersion) {
|
||||
const pkg = data.find((pkg: Package) => String(pkg.id) === String(pkgId));
|
||||
if (!pkgId) {
|
||||
throw new Error(t('packageIdRequired'));
|
||||
}
|
||||
const pkg = allPkgs.find(
|
||||
(pkg: Package) => String(pkg.id) === String(pkgId),
|
||||
);
|
||||
if (pkg) {
|
||||
pkgVersion = pkg.name;
|
||||
pkgsToBind = [pkg];
|
||||
} else {
|
||||
throw new Error(t('nativePackageIdNotFound', { id: pkgId }));
|
||||
}
|
||||
}
|
||||
|
||||
if (rollout !== undefined && pkgVersion) {
|
||||
await put(`/app/${appId}/version/${versionId}`, {
|
||||
config: {
|
||||
rollout: {
|
||||
[pkgVersion]: rollout,
|
||||
},
|
||||
},
|
||||
});
|
||||
console.log(
|
||||
`${t('rolloutConfigSet', {
|
||||
versions: pkgVersion,
|
||||
rollout: rollout,
|
||||
})}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (versionId !== undefined) {
|
||||
await put(`/app/${appId}/package/${pkgId}`, {
|
||||
versionId,
|
||||
});
|
||||
console.log(
|
||||
`${t('versionBind', {
|
||||
version: versionId,
|
||||
nativeVersion: pkgVersion,
|
||||
id: pkgId,
|
||||
})}`,
|
||||
);
|
||||
}
|
||||
await bindVersionToPackages({
|
||||
appId,
|
||||
versionId,
|
||||
pkgs: pkgsToBind,
|
||||
rollout,
|
||||
});
|
||||
console.log(t('operationSuccess'));
|
||||
},
|
||||
updateVersionInfo: async ({
|
||||
@@ -345,10 +303,7 @@ export const commands = {
|
||||
args: string[];
|
||||
options: CommandOptions;
|
||||
}) => {
|
||||
const platform = checkPlatform(
|
||||
options.platform ||
|
||||
((await question('平台(ios/android/harmony):')) as Platform),
|
||||
);
|
||||
const platform = await getPlatform(options.platform);
|
||||
const { appId } = await getSelectedApp(platform);
|
||||
const versionId = options.versionId || (await chooseVersion(appId)).id;
|
||||
|
||||
|
Reference in New Issue
Block a user