react-native-update-cli 1.42.0 → 1.42.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api.js +9 -4
- package/lib/app.js +34 -26
- package/lib/bundle.js +4 -4
- package/lib/locales/en.js +20 -1
- package/lib/locales/zh.js +20 -1
- package/lib/utils/app-info-parser/index.js +13 -4
- package/lib/utils/check-plugin.js +2 -2
- package/lib/utils/constants.js +4 -0
- package/lib/utils/i18n.js +7 -2
- package/lib/utils/index.js +45 -24
- package/lib/versions.js +1 -1
- package/package.json +1 -1
- package/src/api.ts +13 -9
- package/src/app.ts +20 -32
- package/src/bundle.ts +4 -4
- package/src/locales/en.ts +25 -0
- package/src/locales/zh.ts +24 -0
- package/src/utils/app-info-parser/{index.js → index.ts} +7 -5
- package/src/utils/check-plugin.ts +2 -2
- package/src/utils/constants.ts +5 -3
- package/src/utils/i18n.ts +8 -2
- package/src/utils/index.ts +55 -40
- package/src/versions.ts +9 -3
package/lib/api.js
CHANGED
|
@@ -50,6 +50,7 @@ const _tcpping = /*#__PURE__*/ _interop_require_default(require("tcp-ping"));
|
|
|
50
50
|
const _filesizeparser = /*#__PURE__*/ _interop_require_default(require("filesize-parser"));
|
|
51
51
|
const _constants = require("./utils/constants");
|
|
52
52
|
const _formdata = /*#__PURE__*/ _interop_require_default(require("form-data"));
|
|
53
|
+
const _i18n = require("./utils/i18n");
|
|
53
54
|
function _interop_require_default(obj) {
|
|
54
55
|
return obj && obj.__esModule ? obj : {
|
|
55
56
|
default: obj
|
|
@@ -58,8 +59,7 @@ function _interop_require_default(obj) {
|
|
|
58
59
|
const tcpPing = _nodeutil.default.promisify(_tcpping.default.ping);
|
|
59
60
|
let session;
|
|
60
61
|
let savedSession;
|
|
61
|
-
const
|
|
62
|
-
const host = process.env.PUSHY_REGISTRY || process.env.RNU_API || defaultEndpoint;
|
|
62
|
+
const host = process.env.PUSHY_REGISTRY || process.env.RNU_API || _constants.defaultEndpoint;
|
|
63
63
|
const userAgent = `react-native-update-cli/${_packagejson.default.version}`;
|
|
64
64
|
const getSession = ()=>session;
|
|
65
65
|
const replaceSession = (newSession)=>{
|
|
@@ -102,7 +102,7 @@ async function query(url, options) {
|
|
|
102
102
|
if (resp.status !== 200) {
|
|
103
103
|
const message = (json == null ? void 0 : json.message) || resp.statusText;
|
|
104
104
|
if (resp.status === 401) {
|
|
105
|
-
throw new Error(
|
|
105
|
+
throw new Error((0, _i18n.t)('loginExpired'));
|
|
106
106
|
}
|
|
107
107
|
throw new Error(message);
|
|
108
108
|
}
|
|
@@ -155,7 +155,12 @@ async function uploadFile(fn, key) {
|
|
|
155
155
|
}
|
|
156
156
|
const fileSize = _nodefs.default.statSync(fn).size;
|
|
157
157
|
if (maxSize && fileSize > (0, _filesizeparser.default)(maxSize)) {
|
|
158
|
-
|
|
158
|
+
const readableFileSize = `${(fileSize / 1048576).toFixed(1)}m`;
|
|
159
|
+
throw new Error((0, _i18n.t)('fileSizeExceeded', {
|
|
160
|
+
fileSize: readableFileSize,
|
|
161
|
+
maxSize,
|
|
162
|
+
pricingPageUrl: _constants.pricingPageUrl
|
|
163
|
+
}));
|
|
159
164
|
}
|
|
160
165
|
const bar = new _progress.default(' Uploading [:bar] :percent :etas', {
|
|
161
166
|
complete: '=',
|
package/lib/app.js
CHANGED
|
@@ -29,45 +29,52 @@ const _utils = require("./utils");
|
|
|
29
29
|
const _nodefs = /*#__PURE__*/ _interop_require_default(require("node:fs"));
|
|
30
30
|
const _ttytable = /*#__PURE__*/ _interop_require_default(require("tty-table"));
|
|
31
31
|
const _api = require("./api");
|
|
32
|
+
const _i18n = require("./utils/i18n");
|
|
32
33
|
function _interop_require_default(obj) {
|
|
33
34
|
return obj && obj.__esModule ? obj : {
|
|
34
35
|
default: obj
|
|
35
36
|
};
|
|
36
37
|
}
|
|
37
|
-
const validPlatforms =
|
|
38
|
-
ios
|
|
39
|
-
android
|
|
40
|
-
harmony
|
|
41
|
-
|
|
38
|
+
const validPlatforms = [
|
|
39
|
+
'ios',
|
|
40
|
+
'android',
|
|
41
|
+
'harmony'
|
|
42
|
+
];
|
|
42
43
|
function checkPlatform(platform) {
|
|
43
|
-
if (!validPlatforms
|
|
44
|
-
throw new Error(
|
|
44
|
+
if (!validPlatforms.includes(platform)) {
|
|
45
|
+
throw new Error((0, _i18n.t)('unsupportedPlatform', {
|
|
46
|
+
platform
|
|
47
|
+
}));
|
|
45
48
|
}
|
|
46
49
|
return platform;
|
|
47
50
|
}
|
|
48
51
|
function getSelectedApp(platform) {
|
|
49
52
|
checkPlatform(platform);
|
|
50
53
|
if (!_nodefs.default.existsSync('update.json')) {
|
|
51
|
-
throw new Error(
|
|
54
|
+
throw new Error((0, _i18n.t)('appNotSelected', {
|
|
55
|
+
platform
|
|
56
|
+
}));
|
|
52
57
|
}
|
|
53
58
|
const updateInfo = JSON.parse(_nodefs.default.readFileSync('update.json', 'utf8'));
|
|
54
59
|
if (!updateInfo[platform]) {
|
|
55
|
-
throw new Error(
|
|
60
|
+
throw new Error((0, _i18n.t)('appNotSelected', {
|
|
61
|
+
platform
|
|
62
|
+
}));
|
|
56
63
|
}
|
|
57
64
|
return updateInfo[platform];
|
|
58
65
|
}
|
|
59
|
-
async function listApp(platform) {
|
|
66
|
+
async function listApp(platform = '') {
|
|
60
67
|
const { data } = await (0, _api.get)('/app/list');
|
|
61
68
|
const list = platform ? data.filter((v)=>v.platform === platform) : data;
|
|
62
69
|
const header = [
|
|
63
70
|
{
|
|
64
|
-
value:
|
|
71
|
+
value: (0, _i18n.t)('appId')
|
|
65
72
|
},
|
|
66
73
|
{
|
|
67
|
-
value: '
|
|
74
|
+
value: (0, _i18n.t)('appName')
|
|
68
75
|
},
|
|
69
76
|
{
|
|
70
|
-
value: '
|
|
77
|
+
value: (0, _i18n.t)('platform')
|
|
71
78
|
}
|
|
72
79
|
];
|
|
73
80
|
const rows = [];
|
|
@@ -79,17 +86,16 @@ async function listApp(platform) {
|
|
|
79
86
|
]);
|
|
80
87
|
}
|
|
81
88
|
console.log((0, _ttytable.default)(header, rows).render());
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
89
|
+
console.log(`\n${(0, _i18n.t)('totalApps', {
|
|
90
|
+
count: list.length,
|
|
91
|
+
platform
|
|
92
|
+
})}`);
|
|
87
93
|
return list;
|
|
88
94
|
}
|
|
89
95
|
async function chooseApp(platform) {
|
|
90
96
|
const list = await listApp(platform);
|
|
91
97
|
while(true){
|
|
92
|
-
const id = await (0, _utils.question)(
|
|
98
|
+
const id = await (0, _utils.question)((0, _i18n.t)('enterAppIdQuestion'));
|
|
93
99
|
const app = list.find((v)=>v.id === Number(id));
|
|
94
100
|
if (app) {
|
|
95
101
|
return app;
|
|
@@ -98,15 +104,17 @@ async function chooseApp(platform) {
|
|
|
98
104
|
}
|
|
99
105
|
const commands = {
|
|
100
106
|
createApp: async function({ options }) {
|
|
101
|
-
const name = options.name || await (0, _utils.question)('
|
|
107
|
+
const name = options.name || await (0, _utils.question)((0, _i18n.t)('appNameQuestion'));
|
|
102
108
|
const { downloadUrl } = options;
|
|
103
|
-
const platform = checkPlatform(options.platform || await (0, _utils.question)(
|
|
109
|
+
const platform = checkPlatform(options.platform || await (0, _utils.question)((0, _i18n.t)('platformQuestion')));
|
|
104
110
|
const { id } = await (0, _api.post)('/app/create', {
|
|
105
111
|
name,
|
|
106
112
|
platform,
|
|
107
113
|
downloadUrl
|
|
108
114
|
});
|
|
109
|
-
console.log(
|
|
115
|
+
console.log((0, _i18n.t)('createAppSuccess', {
|
|
116
|
+
id
|
|
117
|
+
}));
|
|
110
118
|
await this.selectApp({
|
|
111
119
|
args: [
|
|
112
120
|
id
|
|
@@ -120,24 +128,24 @@ const commands = {
|
|
|
120
128
|
const { platform } = options;
|
|
121
129
|
const id = args[0] || chooseApp(platform);
|
|
122
130
|
if (!id) {
|
|
123
|
-
console.log('
|
|
131
|
+
console.log((0, _i18n.t)('cancelled'));
|
|
124
132
|
}
|
|
125
133
|
await (0, _api.doDelete)(`/app/${id}`);
|
|
126
|
-
console.log('
|
|
134
|
+
console.log((0, _i18n.t)('operationSuccess'));
|
|
127
135
|
},
|
|
128
136
|
apps: async ({ options })=>{
|
|
129
137
|
const { platform } = options;
|
|
130
138
|
listApp(platform);
|
|
131
139
|
},
|
|
132
140
|
selectApp: async ({ args, options })=>{
|
|
133
|
-
const platform = checkPlatform(options.platform || await (0, _utils.question)(
|
|
141
|
+
const platform = checkPlatform(options.platform || await (0, _utils.question)((0, _i18n.t)('platformQuestion')));
|
|
134
142
|
const id = args[0] ? Number.parseInt(args[0]) : (await chooseApp(platform)).id;
|
|
135
143
|
let updateInfo = {};
|
|
136
144
|
if (_nodefs.default.existsSync('update.json')) {
|
|
137
145
|
try {
|
|
138
146
|
updateInfo = JSON.parse(_nodefs.default.readFileSync('update.json', 'utf8'));
|
|
139
147
|
} catch (e) {
|
|
140
|
-
console.error(
|
|
148
|
+
console.error((0, _i18n.t)('failedToParseUpdateJson'));
|
|
141
149
|
throw e;
|
|
142
150
|
}
|
|
143
151
|
}
|
package/lib/bundle.js
CHANGED
|
@@ -124,15 +124,15 @@ async function runReactNativeBundleCommand({ bundleName, dev, entryFile, outputF
|
|
|
124
124
|
};
|
|
125
125
|
const getRnCli = ()=>{
|
|
126
126
|
try {
|
|
127
|
-
// rn
|
|
128
|
-
cliPath = require.resolve('
|
|
127
|
+
// rn < 0.75
|
|
128
|
+
cliPath = require.resolve('react-native/local-cli/cli.js', {
|
|
129
129
|
paths: [
|
|
130
130
|
process.cwd()
|
|
131
131
|
]
|
|
132
132
|
});
|
|
133
133
|
} catch (e) {
|
|
134
|
-
// rn
|
|
135
|
-
cliPath = require.resolve('react-native/
|
|
134
|
+
// rn >= 0.75
|
|
135
|
+
cliPath = require.resolve('@react-native-community/cli/build/bin.js', {
|
|
136
136
|
paths: [
|
|
137
137
|
process.cwd()
|
|
138
138
|
]
|
package/lib/locales/en.js
CHANGED
|
@@ -19,5 +19,24 @@ Best practices for lock files:
|
|
|
19
19
|
2. Add the lock file to version control (but do not commit multiple lock files of different formats).
|
|
20
20
|
3. Pay attention to changes in the lock file during code review.
|
|
21
21
|
This can reduce the risk of inconsistent dependencies and supply chain attacks.
|
|
22
|
-
|
|
22
|
+
`,
|
|
23
|
+
loginExpired: 'Login information has expired. Please use `cresc login` command to re-login',
|
|
24
|
+
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}}',
|
|
25
|
+
bundleNotFound: 'Bundle file not found. Please ensure that this {{packageType}} is a release version and the bundle file name is the default `{{entryFile}}`',
|
|
26
|
+
buildTimeNotFound: 'Cannot get the build timestamp of this package. Please update `react-native-update` to the latest version and re-package and upload.',
|
|
27
|
+
latestVersionTag: '(latest: {{version}})',
|
|
28
|
+
rnuVersionNotFound: 'react-native-update: Cannot get the version number. Please run the command in the project directory',
|
|
29
|
+
unsupportedPlatform: 'Unsupported platform `{{platform}}`',
|
|
30
|
+
appId: 'App ID',
|
|
31
|
+
appName: 'App Name',
|
|
32
|
+
platform: 'Platform',
|
|
33
|
+
totalApps: 'Total {{count}} apps',
|
|
34
|
+
appNotSelected: 'App not selected. run `cresc selectApp --platform {{platform}}` first!',
|
|
35
|
+
enterAppIdQuestion: 'Enter AppId:',
|
|
36
|
+
appNameQuestion: 'App Name:',
|
|
37
|
+
platformQuestion: 'Platform(ios/android/harmony):',
|
|
38
|
+
createAppSuccess: 'App created successfully (id: {{id}})',
|
|
39
|
+
cancelled: 'Cancelled',
|
|
40
|
+
operationSuccess: 'Operation successful',
|
|
41
|
+
failedToParseUpdateJson: 'Failed to parse file `update.json`. Try to remove it manually.'
|
|
23
42
|
};
|
package/lib/locales/zh.js
CHANGED
|
@@ -19,5 +19,24 @@ const _default = {
|
|
|
19
19
|
3. 代码审核时应关注 lock 文件的变化。
|
|
20
20
|
这样可以最大限度避免因依赖关系不一致而导致的热更异常,也降低供应链攻击等安全隐患。
|
|
21
21
|
`,
|
|
22
|
-
multipleLocksFound: '检测到多种不同格式的锁文件({lockFiles}),这可能导致依赖关系不一致而使热更异常。'
|
|
22
|
+
multipleLocksFound: '检测到多种不同格式的锁文件({lockFiles}),这可能导致依赖关系不一致而使热更异常。',
|
|
23
|
+
loginExpired: '登录信息已过期,请使用 `pushy login` 命令重新登录',
|
|
24
|
+
fileSizeExceeded: '此文件大小 {{fileSize}} , 超出当前额度 {{maxSize}} 。您可以考虑升级付费业务以提升此额度。详情请访问: {{pricingPageUrl}}',
|
|
25
|
+
bundleNotFound: '找不到 bundle 文件。请确保此 {{packageType}} 为 release 版本,且 bundle 文件名为默认的 `{{entryFile}}`',
|
|
26
|
+
buildTimeNotFound: '无法获取此包的编译时间戳。请更新 `react-native-update` 到最新版本后重新打包上传。',
|
|
27
|
+
latestVersionTag: '(最新:{{version}})',
|
|
28
|
+
rnuVersionNotFound: 'react-native-update: 无法获取版本号。请在项目目录中运行命令',
|
|
29
|
+
unsupportedPlatform: '无法识别的平台 `{{platform}}`',
|
|
30
|
+
appId: '应用 id',
|
|
31
|
+
appName: '应用名称',
|
|
32
|
+
platform: '平台',
|
|
33
|
+
totalApps: '共 {{count}} 个{{platform}}应用',
|
|
34
|
+
appNotSelected: '尚未选择应用。请先运行 `pushy selectApp --platform {{platform}}` 来选择应用',
|
|
35
|
+
enterAppIdQuestion: '输入应用 id:',
|
|
36
|
+
appNameQuestion: '应用名称:',
|
|
37
|
+
platformQuestion: '平台(ios/android/harmony):',
|
|
38
|
+
createAppSuccess: '已成功创建应用(id: {{id}})',
|
|
39
|
+
cancelled: '已取消',
|
|
40
|
+
operationSuccess: '操作成功',
|
|
41
|
+
failedToParseUpdateJson: '无法解析文件 `update.json`。请手动删除它。'
|
|
23
42
|
};
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "default", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return _default;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
2
11
|
const ApkParser = require('./apk');
|
|
3
12
|
const IpaParser = require('./ipa');
|
|
4
13
|
const AppParser = require('./app');
|
|
@@ -13,12 +22,12 @@ class AppInfoParser {
|
|
|
13
22
|
}
|
|
14
23
|
/**
|
|
15
24
|
* parser for parsing .ipa or .apk file
|
|
16
|
-
* @param {String | File
|
|
25
|
+
* @param {String | File} file // file's path in Node, instance of File in Browser
|
|
17
26
|
*/ constructor(file){
|
|
18
27
|
if (!file) {
|
|
19
|
-
throw new Error("Param miss: file(file's path in Node, instance of File
|
|
28
|
+
throw new Error("Param miss: file(file's path in Node, instance of File in browser).");
|
|
20
29
|
}
|
|
21
|
-
const splits = (file
|
|
30
|
+
const splits = (typeof file === 'string' ? file : file.name).split('.');
|
|
22
31
|
const fileType = splits[splits.length - 1].toLowerCase();
|
|
23
32
|
if (!supportFileTypes.includes(fileType)) {
|
|
24
33
|
throw new Error('Unsupported file type, only support .ipa or .apk or .app file.');
|
|
@@ -37,4 +46,4 @@ class AppInfoParser {
|
|
|
37
46
|
}
|
|
38
47
|
}
|
|
39
48
|
}
|
|
40
|
-
|
|
49
|
+
const _default = AppInfoParser;
|
|
@@ -19,10 +19,10 @@ async function checkPlugins() {
|
|
|
19
19
|
const isEnabled = await plugin.detect();
|
|
20
20
|
if (isEnabled && plugin.bundleParams) {
|
|
21
21
|
Object.assign(params, plugin.bundleParams);
|
|
22
|
-
console.log(
|
|
22
|
+
console.log(`detected ${plugin.name} plugin`);
|
|
23
23
|
}
|
|
24
24
|
} catch (err) {
|
|
25
|
-
console.warn(
|
|
25
|
+
console.warn(`error while detecting ${plugin.name} plugin:`, err);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
return params;
|
package/lib/utils/constants.js
CHANGED
|
@@ -15,6 +15,9 @@ _export(exports, {
|
|
|
15
15
|
credentialFile: function() {
|
|
16
16
|
return credentialFile;
|
|
17
17
|
},
|
|
18
|
+
defaultEndpoint: function() {
|
|
19
|
+
return defaultEndpoint;
|
|
20
|
+
},
|
|
18
21
|
pricingPageUrl: function() {
|
|
19
22
|
return pricingPageUrl;
|
|
20
23
|
},
|
|
@@ -37,3 +40,4 @@ const credentialFile = IS_CRESC ? '.cresc.token' : '.update';
|
|
|
37
40
|
const updateJson = IS_CRESC ? 'cresc.config.json' : 'update.json';
|
|
38
41
|
const tempDir = IS_CRESC ? '.cresc.temp' : '.pushy';
|
|
39
42
|
const pricingPageUrl = IS_CRESC ? 'https://cresc.dev/pricing' : 'https://pushy.reactnative.cn/pricing.html';
|
|
43
|
+
const defaultEndpoint = IS_CRESC ? 'https://api.cresc.dev' : 'https://update.reactnative.cn/api';
|
package/lib/utils/i18n.js
CHANGED
|
@@ -20,9 +20,14 @@ function _interop_require_default(obj) {
|
|
|
20
20
|
_i18next.default.init({
|
|
21
21
|
lng: _constants.IS_CRESC ? 'en' : 'zh',
|
|
22
22
|
// debug: process.env.NODE_ENV !== 'production',
|
|
23
|
+
// debug: true,
|
|
23
24
|
resources: {
|
|
24
|
-
en:
|
|
25
|
-
|
|
25
|
+
en: {
|
|
26
|
+
translation: _en.default
|
|
27
|
+
},
|
|
28
|
+
zh: {
|
|
29
|
+
translation: _zh.default
|
|
30
|
+
}
|
|
26
31
|
}
|
|
27
32
|
});
|
|
28
33
|
const t = _i18next.default.t;
|
package/lib/utils/index.js
CHANGED
|
@@ -46,6 +46,7 @@ const _checkplugin = require("./check-plugin");
|
|
|
46
46
|
const _read = require("read");
|
|
47
47
|
const _constants = require("./constants");
|
|
48
48
|
const _depversions = require("./dep-versions");
|
|
49
|
+
const _i18n = require("./i18n");
|
|
49
50
|
function _interop_require_default(obj) {
|
|
50
51
|
return obj && obj.__esModule ? obj : {
|
|
51
52
|
default: obj
|
|
@@ -77,7 +78,10 @@ async function getApkInfo(fn) {
|
|
|
77
78
|
const appInfoParser = new _appinfoparser.default(fn);
|
|
78
79
|
const bundleFile = await appInfoParser.parser.getEntry(/assets\/index.android.bundle/);
|
|
79
80
|
if (!bundleFile) {
|
|
80
|
-
throw new Error(
|
|
81
|
+
throw new Error((0, _i18n.t)('bundleNotFound', {
|
|
82
|
+
packageType: 'apk',
|
|
83
|
+
entryFile: 'index.android.bundle'
|
|
84
|
+
}));
|
|
81
85
|
}
|
|
82
86
|
const updateJsonFile = await appInfoParser.parser.getEntry(/res\/raw\/update.json/);
|
|
83
87
|
let appCredential = {};
|
|
@@ -94,7 +98,7 @@ async function getApkInfo(fn) {
|
|
|
94
98
|
}
|
|
95
99
|
}
|
|
96
100
|
if (buildTime == 0) {
|
|
97
|
-
throw new Error(
|
|
101
|
+
throw new Error((0, _i18n.t)('buildTimeNotFound'));
|
|
98
102
|
}
|
|
99
103
|
return {
|
|
100
104
|
versionName,
|
|
@@ -106,7 +110,10 @@ async function getAppInfo(fn) {
|
|
|
106
110
|
const appInfoParser = new _appinfoparser.default(fn);
|
|
107
111
|
const bundleFile = await appInfoParser.parser.getEntryFromHarmonyApp(/rawfile\/bundle.harmony.js/);
|
|
108
112
|
if (!bundleFile) {
|
|
109
|
-
throw new Error(
|
|
113
|
+
throw new Error((0, _i18n.t)('bundleNotFound', {
|
|
114
|
+
packageType: 'app',
|
|
115
|
+
entryFile: 'bundle.harmony.js'
|
|
116
|
+
}));
|
|
110
117
|
}
|
|
111
118
|
const updateJsonFile = await appInfoParser.parser.getEntryFromHarmonyApp(/rawfile\/update.json/);
|
|
112
119
|
let appCredential = {};
|
|
@@ -124,7 +131,7 @@ async function getAppInfo(fn) {
|
|
|
124
131
|
buildTime = pushy_build_time;
|
|
125
132
|
}
|
|
126
133
|
if (buildTime == 0) {
|
|
127
|
-
throw new Error(
|
|
134
|
+
throw new Error((0, _i18n.t)('buildTimeNotFound'));
|
|
128
135
|
}
|
|
129
136
|
return {
|
|
130
137
|
versionName,
|
|
@@ -136,7 +143,10 @@ async function getIpaInfo(fn) {
|
|
|
136
143
|
const appInfoParser = new _appinfoparser.default(fn);
|
|
137
144
|
const bundleFile = await appInfoParser.parser.getEntry(/payload\/.+?\.app\/main.jsbundle/);
|
|
138
145
|
if (!bundleFile) {
|
|
139
|
-
throw new Error(
|
|
146
|
+
throw new Error((0, _i18n.t)('bundleNotFound', {
|
|
147
|
+
packageType: 'ipa',
|
|
148
|
+
entryFile: 'main.jsbundle'
|
|
149
|
+
}));
|
|
140
150
|
}
|
|
141
151
|
const updateJsonFile = await appInfoParser.parser.getEntry(/payload\/.+?\.app\/assets\/update.json/);
|
|
142
152
|
let appCredential = {};
|
|
@@ -150,7 +160,7 @@ async function getIpaInfo(fn) {
|
|
|
150
160
|
buildTimeTxtBuffer = await appInfoParser.parser.getEntry(/payload\/.+?\.app\/frameworks\/react_native_update.framework\/pushy_build_time.txt/);
|
|
151
161
|
}
|
|
152
162
|
if (!buildTimeTxtBuffer) {
|
|
153
|
-
throw new Error(
|
|
163
|
+
throw new Error((0, _i18n.t)('buildTimeNotFound'));
|
|
154
164
|
}
|
|
155
165
|
const buildTime = buildTimeTxtBuffer.toString().replace('\n', '');
|
|
156
166
|
return {
|
|
@@ -169,34 +179,45 @@ function saveToLocal(originPath, destName) {
|
|
|
169
179
|
}
|
|
170
180
|
async function getLatestVersion(pkgNames) {
|
|
171
181
|
return (0, _latestversion.default)(pkgNames, {
|
|
172
|
-
useCache: true,
|
|
182
|
+
// useCache: true,
|
|
173
183
|
requestOptions: {
|
|
174
184
|
timeout: 2000
|
|
175
185
|
}
|
|
176
186
|
}).then((pkgs)=>pkgs.map((pkg)=>pkg.latest)).catch(()=>[]);
|
|
177
187
|
}
|
|
178
188
|
async function printVersionCommand() {
|
|
179
|
-
let [
|
|
189
|
+
let [latestRnuCliVersion, latestRnuVersion] = await getLatestVersion([
|
|
180
190
|
'react-native-update-cli',
|
|
181
191
|
'react-native-update'
|
|
182
192
|
]);
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
193
|
+
latestRnuCliVersion = latestRnuCliVersion ? ` ${(0, _i18n.t)('latestVersionTag', {
|
|
194
|
+
version: _chalk.default.green(latestRnuCliVersion)
|
|
195
|
+
})}` : '';
|
|
196
|
+
console.log(`react-native-update-cli: ${_packagejson.default.version}${latestRnuCliVersion}`);
|
|
197
|
+
let rnuVersion = '';
|
|
198
|
+
rnuVersion = _depversions.depVersions['react-native-update'];
|
|
199
|
+
latestRnuVersion = latestRnuVersion ? ` ${(0, _i18n.t)('latestVersionTag', {
|
|
200
|
+
version: _chalk.default.green(latestRnuVersion)
|
|
201
|
+
})}` : '';
|
|
202
|
+
console.log(`react-native-update: ${rnuVersion}${latestRnuVersion}`);
|
|
203
|
+
if (rnuVersion) {
|
|
204
|
+
if (_constants.IS_CRESC) {
|
|
205
|
+
if ((0, _satisfies.default)(rnuVersion, '<10.27.0')) {
|
|
206
|
+
console.error('Unsupported version, please update to the latest version: npm i react-native-update@latest');
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
} else {
|
|
210
|
+
if ((0, _satisfies.default)(rnuVersion, '<8.5.2')) {
|
|
211
|
+
console.warn(`当前版本已不再支持,请至少升级到 v8 的最新小版本后重新打包(代码无需改动): npm i react-native-update@8 .
|
|
212
|
+
如有使用安装 apk 的功能,请注意添加所需权限 https://pushy.reactnative.cn/docs/api#async-function-downloadandinstallapkurl`);
|
|
213
|
+
} else if ((0, _satisfies.default)(rnuVersion, '9.0.0 - 9.2.1')) {
|
|
214
|
+
console.warn(`当前版本已不再支持,请至少升级到 v9 的最新小版本后重新打包(代码无需改动,可直接热更): npm i react-native-update@9 .
|
|
215
|
+
如有使用安装 apk 的功能,请注意添加所需权限 https://pushy.reactnative.cn/docs/api#async-function-downloadandinstallapkurl`);
|
|
216
|
+
} else if ((0, _satisfies.default)(rnuVersion, '10.0.0 - 10.17.0')) {
|
|
217
|
+
console.warn('当前版本已不再支持,请升级到 v10 的最新小版本(代码无需改动,可直接热更): npm i react-native-update@10');
|
|
218
|
+
}
|
|
198
219
|
}
|
|
199
220
|
} else {
|
|
200
|
-
console.log(
|
|
221
|
+
console.log((0, _i18n.t)('rnuVersionNotFound'));
|
|
201
222
|
}
|
|
202
223
|
}
|
package/lib/versions.js
CHANGED
|
@@ -58,7 +58,7 @@ async function chooseVersion(appId) {
|
|
|
58
58
|
while(true){
|
|
59
59
|
const data = await showVersion(appId, offset);
|
|
60
60
|
const cmd = await (0, _utils.question)('Enter versionId or page Up/page Down/Begin(U/D/B)');
|
|
61
|
-
switch(cmd.
|
|
61
|
+
switch(cmd.toUpperCase()){
|
|
62
62
|
case 'U':
|
|
63
63
|
offset = Math.max(0, offset - 10);
|
|
64
64
|
break;
|
package/package.json
CHANGED
package/src/api.ts
CHANGED
|
@@ -6,19 +6,20 @@ import ProgressBar from 'progress';
|
|
|
6
6
|
import packageJson from '../package.json';
|
|
7
7
|
import tcpp from 'tcp-ping';
|
|
8
8
|
import filesizeParser from 'filesize-parser';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
pricingPageUrl,
|
|
11
|
+
credentialFile,
|
|
12
|
+
defaultEndpoint,
|
|
13
|
+
} from './utils/constants';
|
|
10
14
|
import type { Session } from 'types';
|
|
11
15
|
import FormData from 'form-data';
|
|
16
|
+
import { t } from './utils/i18n';
|
|
12
17
|
|
|
13
18
|
const tcpPing = util.promisify(tcpp.ping);
|
|
14
19
|
|
|
15
20
|
let session: Session | undefined;
|
|
16
21
|
let savedSession: Session | undefined;
|
|
17
22
|
|
|
18
|
-
const defaultEndpoint = IS_CRESC
|
|
19
|
-
? 'https://api.cresc.dev'
|
|
20
|
-
: 'https://update.reactnative.cn/api';
|
|
21
|
-
|
|
22
23
|
const host =
|
|
23
24
|
process.env.PUSHY_REGISTRY || process.env.RNU_API || defaultEndpoint;
|
|
24
25
|
|
|
@@ -73,7 +74,7 @@ async function query(url: string, options: fetch.RequestInit) {
|
|
|
73
74
|
if (resp.status !== 200) {
|
|
74
75
|
const message = json?.message || resp.statusText;
|
|
75
76
|
if (resp.status === 401) {
|
|
76
|
-
throw new Error('
|
|
77
|
+
throw new Error(t('loginExpired'));
|
|
77
78
|
}
|
|
78
79
|
throw new Error(message);
|
|
79
80
|
}
|
|
@@ -133,10 +134,13 @@ export async function uploadFile(fn: string, key?: string) {
|
|
|
133
134
|
|
|
134
135
|
const fileSize = fs.statSync(fn).size;
|
|
135
136
|
if (maxSize && fileSize > filesizeParser(maxSize)) {
|
|
137
|
+
const readableFileSize = `${(fileSize / 1048576).toFixed(1)}m`;
|
|
136
138
|
throw new Error(
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
139
|
+
t('fileSizeExceeded', {
|
|
140
|
+
fileSize: readableFileSize,
|
|
141
|
+
maxSize,
|
|
142
|
+
pricingPageUrl,
|
|
143
|
+
}),
|
|
140
144
|
);
|
|
141
145
|
}
|
|
142
146
|
|
package/src/app.ts
CHANGED
|
@@ -4,16 +4,14 @@ import Table from 'tty-table';
|
|
|
4
4
|
|
|
5
5
|
import { post, get, doDelete } from './api';
|
|
6
6
|
import type { Platform } from './types';
|
|
7
|
+
import { t } from './utils/i18n';
|
|
8
|
+
|
|
9
|
+
const validPlatforms = ['ios', 'android', 'harmony'];
|
|
7
10
|
|
|
8
|
-
const validPlatforms = {
|
|
9
|
-
ios: 1,
|
|
10
|
-
android: 1,
|
|
11
|
-
harmony: 1,
|
|
12
|
-
};
|
|
13
11
|
|
|
14
12
|
export function checkPlatform(platform: Platform) {
|
|
15
|
-
if (!validPlatforms
|
|
16
|
-
throw new Error(
|
|
13
|
+
if (!validPlatforms.includes(platform)) {
|
|
14
|
+
throw new Error(t('unsupportedPlatform', { platform }));
|
|
17
15
|
}
|
|
18
16
|
return platform;
|
|
19
17
|
}
|
|
@@ -22,27 +20,23 @@ export function getSelectedApp(platform: Platform) {
|
|
|
22
20
|
checkPlatform(platform);
|
|
23
21
|
|
|
24
22
|
if (!fs.existsSync('update.json')) {
|
|
25
|
-
throw new Error(
|
|
26
|
-
`App not selected. run 'pushy selectApp --platform ${platform}' first!`,
|
|
27
|
-
);
|
|
23
|
+
throw new Error(t('appNotSelected', { platform }));
|
|
28
24
|
}
|
|
29
25
|
const updateInfo = JSON.parse(fs.readFileSync('update.json', 'utf8'));
|
|
30
26
|
if (!updateInfo[platform]) {
|
|
31
|
-
throw new Error(
|
|
32
|
-
`App not selected. run 'pushy selectApp --platform ${platform}' first!`,
|
|
33
|
-
);
|
|
27
|
+
throw new Error(t('appNotSelected', { platform }));
|
|
34
28
|
}
|
|
35
29
|
return updateInfo[platform];
|
|
36
30
|
}
|
|
37
31
|
|
|
38
|
-
export async function listApp(platform: Platform) {
|
|
32
|
+
export async function listApp(platform: Platform | '' = '') {
|
|
39
33
|
const { data } = await get('/app/list');
|
|
40
34
|
const list = platform ? data.filter((v) => v.platform === platform) : data;
|
|
41
35
|
|
|
42
36
|
const header = [
|
|
43
|
-
{ value: '
|
|
44
|
-
{ value: '
|
|
45
|
-
{ value: '
|
|
37
|
+
{ value: t('appId') },
|
|
38
|
+
{ value: t('appName') },
|
|
39
|
+
{ value: t('platform') },
|
|
46
40
|
];
|
|
47
41
|
const rows = [];
|
|
48
42
|
for (const app of list) {
|
|
@@ -51,11 +45,7 @@ export async function listApp(platform: Platform) {
|
|
|
51
45
|
|
|
52
46
|
console.log(Table(header, rows).render());
|
|
53
47
|
|
|
54
|
-
|
|
55
|
-
console.log(`\共 ${list.length} ${platform} 个应用`);
|
|
56
|
-
} else {
|
|
57
|
-
console.log(`\共 ${list.length} 个应用`);
|
|
58
|
-
}
|
|
48
|
+
console.log(`\n${t('totalApps', { count: list.length, platform })}`);
|
|
59
49
|
return list;
|
|
60
50
|
}
|
|
61
51
|
|
|
@@ -63,7 +53,7 @@ export async function chooseApp(platform: Platform) {
|
|
|
63
53
|
const list = await listApp(platform);
|
|
64
54
|
|
|
65
55
|
while (true) {
|
|
66
|
-
const id = await question('
|
|
56
|
+
const id = await question(t('enterAppIdQuestion'));
|
|
67
57
|
const app = list.find((v) => v.id === Number(id));
|
|
68
58
|
if (app) {
|
|
69
59
|
return app;
|
|
@@ -77,13 +67,13 @@ export const commands = {
|
|
|
77
67
|
}: {
|
|
78
68
|
options: { name: string; downloadUrl: string; platform: Platform };
|
|
79
69
|
}) {
|
|
80
|
-
const name = options.name || (await question('
|
|
70
|
+
const name = options.name || (await question(t('appNameQuestion')));
|
|
81
71
|
const { downloadUrl } = options;
|
|
82
72
|
const platform = checkPlatform(
|
|
83
|
-
options.platform || (await question(
|
|
73
|
+
options.platform || (await question(t('platformQuestion'))),
|
|
84
74
|
);
|
|
85
75
|
const { id } = await post('/app/create', { name, platform, downloadUrl });
|
|
86
|
-
console.log(
|
|
76
|
+
console.log(t('createAppSuccess', { id }));
|
|
87
77
|
await this.selectApp({
|
|
88
78
|
args: [id],
|
|
89
79
|
options: { platform },
|
|
@@ -93,10 +83,10 @@ export const commands = {
|
|
|
93
83
|
const { platform } = options;
|
|
94
84
|
const id = args[0] || chooseApp(platform);
|
|
95
85
|
if (!id) {
|
|
96
|
-
console.log('
|
|
86
|
+
console.log(t('cancelled'));
|
|
97
87
|
}
|
|
98
88
|
await doDelete(`/app/${id}`);
|
|
99
|
-
console.log('
|
|
89
|
+
console.log(t('operationSuccess'));
|
|
100
90
|
},
|
|
101
91
|
apps: async ({ options }: { options: { platform: Platform } }) => {
|
|
102
92
|
const { platform } = options;
|
|
@@ -104,7 +94,7 @@ export const commands = {
|
|
|
104
94
|
},
|
|
105
95
|
selectApp: async ({ args, options }: { args: string[]; options: { platform: Platform } }) => {
|
|
106
96
|
const platform = checkPlatform(
|
|
107
|
-
options.platform || (await question(
|
|
97
|
+
options.platform || (await question(t('platformQuestion'))),
|
|
108
98
|
);
|
|
109
99
|
const id = args[0]
|
|
110
100
|
? Number.parseInt(args[0])
|
|
@@ -115,9 +105,7 @@ export const commands = {
|
|
|
115
105
|
try {
|
|
116
106
|
updateInfo = JSON.parse(fs.readFileSync('update.json', 'utf8'));
|
|
117
107
|
} catch (e) {
|
|
118
|
-
console.error(
|
|
119
|
-
'Failed to parse file `update.json`. Try to remove it manually.',
|
|
120
|
-
);
|
|
108
|
+
console.error(t('failedToParseUpdateJson'));
|
|
121
109
|
throw e;
|
|
122
110
|
}
|
|
123
111
|
}
|
package/src/bundle.ts
CHANGED
|
@@ -102,13 +102,13 @@ async function runReactNativeBundleCommand({
|
|
|
102
102
|
|
|
103
103
|
const getRnCli = () => {
|
|
104
104
|
try {
|
|
105
|
-
// rn
|
|
106
|
-
cliPath = require.resolve('
|
|
105
|
+
// rn < 0.75
|
|
106
|
+
cliPath = require.resolve('react-native/local-cli/cli.js', {
|
|
107
107
|
paths: [process.cwd()],
|
|
108
108
|
});
|
|
109
109
|
} catch (e) {
|
|
110
|
-
// rn
|
|
111
|
-
cliPath = require.resolve('react-native/
|
|
110
|
+
// rn >= 0.75
|
|
111
|
+
cliPath = require.resolve('@react-native-community/cli/build/bin.js', {
|
|
112
112
|
paths: [process.cwd()],
|
|
113
113
|
});
|
|
114
114
|
}
|
package/src/locales/en.ts
CHANGED
|
@@ -14,4 +14,29 @@ Best practices for lock files:
|
|
|
14
14
|
3. Pay attention to changes in the lock file during code review.
|
|
15
15
|
This can reduce the risk of inconsistent dependencies and supply chain attacks.
|
|
16
16
|
`,
|
|
17
|
+
loginExpired:
|
|
18
|
+
'Login information has expired. Please use `cresc login` command to re-login',
|
|
19
|
+
fileSizeExceeded:
|
|
20
|
+
'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}}',
|
|
21
|
+
bundleNotFound:
|
|
22
|
+
'Bundle file not found. Please ensure that this {{packageType}} is a release version and the bundle file name is the default `{{entryFile}}`',
|
|
23
|
+
buildTimeNotFound:
|
|
24
|
+
'Cannot get the build timestamp of this package. Please update `react-native-update` to the latest version and re-package and upload.',
|
|
25
|
+
latestVersionTag: '(latest: {{version}})',
|
|
26
|
+
rnuVersionNotFound:
|
|
27
|
+
'react-native-update: Cannot get the version number. Please run the command in the project directory',
|
|
28
|
+
unsupportedPlatform: 'Unsupported platform `{{platform}}`',
|
|
29
|
+
appId: 'App ID',
|
|
30
|
+
appName: 'App Name',
|
|
31
|
+
platform: 'Platform',
|
|
32
|
+
totalApps: 'Total {{count}} apps',
|
|
33
|
+
appNotSelected:
|
|
34
|
+
'App not selected. run `cresc selectApp --platform {{platform}}` first!',
|
|
35
|
+
enterAppIdQuestion: 'Enter AppId:',
|
|
36
|
+
appNameQuestion: 'App Name:',
|
|
37
|
+
platformQuestion: 'Platform(ios/android/harmony):',
|
|
38
|
+
createAppSuccess: 'App created successfully (id: {{id}})',
|
|
39
|
+
cancelled: 'Cancelled',
|
|
40
|
+
operationSuccess: 'Operation successful',
|
|
41
|
+
failedToParseUpdateJson: 'Failed to parse file `update.json`. Try to remove it manually.',
|
|
17
42
|
};
|
package/src/locales/zh.ts
CHANGED
|
@@ -13,4 +13,28 @@ export default {
|
|
|
13
13
|
`,
|
|
14
14
|
multipleLocksFound:
|
|
15
15
|
'检测到多种不同格式的锁文件({lockFiles}),这可能导致依赖关系不一致而使热更异常。',
|
|
16
|
+
loginExpired: '登录信息已过期,请使用 `pushy login` 命令重新登录',
|
|
17
|
+
fileSizeExceeded:
|
|
18
|
+
'此文件大小 {{fileSize}} , 超出当前额度 {{maxSize}} 。您可以考虑升级付费业务以提升此额度。详情请访问: {{pricingPageUrl}}',
|
|
19
|
+
bundleNotFound:
|
|
20
|
+
'找不到 bundle 文件。请确保此 {{packageType}} 为 release 版本,且 bundle 文件名为默认的 `{{entryFile}}`',
|
|
21
|
+
buildTimeNotFound:
|
|
22
|
+
'无法获取此包的编译时间戳。请更新 `react-native-update` 到最新版本后重新打包上传。',
|
|
23
|
+
latestVersionTag: '(最新:{{version}})',
|
|
24
|
+
rnuVersionNotFound:
|
|
25
|
+
'react-native-update: 无法获取版本号。请在项目目录中运行命令',
|
|
26
|
+
unsupportedPlatform: '无法识别的平台 `{{platform}}`',
|
|
27
|
+
appId: '应用 id',
|
|
28
|
+
appName: '应用名称',
|
|
29
|
+
platform: '平台',
|
|
30
|
+
totalApps: '共 {{count}} 个{{platform}}应用',
|
|
31
|
+
appNotSelected:
|
|
32
|
+
'尚未选择应用。请先运行 `pushy selectApp --platform {{platform}}` 来选择应用',
|
|
33
|
+
enterAppIdQuestion: '输入应用 id:',
|
|
34
|
+
appNameQuestion: '应用名称:',
|
|
35
|
+
platformQuestion: '平台(ios/android/harmony):',
|
|
36
|
+
createAppSuccess: '已成功创建应用(id: {{id}})',
|
|
37
|
+
cancelled: '已取消',
|
|
38
|
+
operationSuccess: '操作成功',
|
|
39
|
+
failedToParseUpdateJson: '无法解析文件 `update.json`。请手动删除它。',
|
|
16
40
|
};
|
|
@@ -4,17 +4,19 @@ const AppParser = require('./app');
|
|
|
4
4
|
const supportFileTypes = ['ipa', 'apk', 'app'];
|
|
5
5
|
|
|
6
6
|
class AppInfoParser {
|
|
7
|
+
file: string | File;
|
|
8
|
+
parser: any;
|
|
7
9
|
/**
|
|
8
10
|
* parser for parsing .ipa or .apk file
|
|
9
|
-
* @param {String | File
|
|
11
|
+
* @param {String | File} file // file's path in Node, instance of File in Browser
|
|
10
12
|
*/
|
|
11
|
-
constructor(file) {
|
|
13
|
+
constructor(file: string | File) {
|
|
12
14
|
if (!file) {
|
|
13
15
|
throw new Error(
|
|
14
|
-
"Param miss: file(file's path in Node, instance of File
|
|
16
|
+
"Param miss: file(file's path in Node, instance of File in browser).",
|
|
15
17
|
);
|
|
16
18
|
}
|
|
17
|
-
const splits = (file
|
|
19
|
+
const splits = (typeof file === 'string' ? file : file.name).split('.');
|
|
18
20
|
const fileType = splits[splits.length - 1].toLowerCase();
|
|
19
21
|
if (!supportFileTypes.includes(fileType)) {
|
|
20
22
|
throw new Error(
|
|
@@ -40,4 +42,4 @@ class AppInfoParser {
|
|
|
40
42
|
}
|
|
41
43
|
}
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
export default AppInfoParser;
|
|
@@ -17,10 +17,10 @@ export async function checkPlugins(): Promise<BundleParams> {
|
|
|
17
17
|
const isEnabled = await plugin.detect();
|
|
18
18
|
if (isEnabled && plugin.bundleParams) {
|
|
19
19
|
Object.assign(params, plugin.bundleParams);
|
|
20
|
-
console.log(
|
|
20
|
+
console.log(`detected ${plugin.name} plugin`);
|
|
21
21
|
}
|
|
22
22
|
} catch (err) {
|
|
23
|
-
console.warn(
|
|
23
|
+
console.warn(`error while detecting ${plugin.name} plugin:`, err);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
package/src/utils/constants.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
|
|
3
|
-
const scriptName
|
|
4
|
-
| 'cresc'
|
|
5
|
-
| 'pushy';
|
|
3
|
+
const scriptName = path.basename(process.argv[1]) as 'cresc' | 'pushy';
|
|
6
4
|
export const IS_CRESC = scriptName === 'cresc';
|
|
7
5
|
|
|
8
6
|
export const credentialFile = IS_CRESC ? '.cresc.token' : '.update';
|
|
@@ -11,3 +9,7 @@ export const tempDir = IS_CRESC ? '.cresc.temp' : '.pushy';
|
|
|
11
9
|
export const pricingPageUrl = IS_CRESC
|
|
12
10
|
? 'https://cresc.dev/pricing'
|
|
13
11
|
: 'https://pushy.reactnative.cn/pricing.html';
|
|
12
|
+
|
|
13
|
+
export const defaultEndpoint = IS_CRESC
|
|
14
|
+
? 'https://api.cresc.dev'
|
|
15
|
+
: 'https://update.reactnative.cn/api';
|
package/src/utils/i18n.ts
CHANGED
|
@@ -2,12 +2,18 @@ import i18next from 'i18next';
|
|
|
2
2
|
import en from '../locales/en';
|
|
3
3
|
import zh from '../locales/zh';
|
|
4
4
|
import { IS_CRESC } from './constants';
|
|
5
|
+
|
|
5
6
|
i18next.init({
|
|
6
7
|
lng: IS_CRESC ? 'en' : 'zh',
|
|
7
8
|
// debug: process.env.NODE_ENV !== 'production',
|
|
9
|
+
// debug: true,
|
|
8
10
|
resources: {
|
|
9
|
-
en
|
|
10
|
-
|
|
11
|
+
en: {
|
|
12
|
+
translation: en,
|
|
13
|
+
},
|
|
14
|
+
zh: {
|
|
15
|
+
translation: zh,
|
|
16
|
+
},
|
|
11
17
|
},
|
|
12
18
|
});
|
|
13
19
|
|
package/src/utils/index.ts
CHANGED
|
@@ -9,8 +9,9 @@ import latestVersion from '@badisi/latest-version';
|
|
|
9
9
|
import { checkPlugins } from './check-plugin';
|
|
10
10
|
|
|
11
11
|
import { read } from 'read';
|
|
12
|
-
import { tempDir } from './constants';
|
|
12
|
+
import { IS_CRESC, tempDir } from './constants';
|
|
13
13
|
import { depVersions } from './dep-versions';
|
|
14
|
+
import { t } from './i18n';
|
|
14
15
|
|
|
15
16
|
export async function question(query: string, password?: boolean) {
|
|
16
17
|
if (NO_INTERACTIVE) {
|
|
@@ -46,7 +47,10 @@ export async function getApkInfo(fn: string) {
|
|
|
46
47
|
);
|
|
47
48
|
if (!bundleFile) {
|
|
48
49
|
throw new Error(
|
|
49
|
-
'
|
|
50
|
+
t('bundleNotFound', {
|
|
51
|
+
packageType: 'apk',
|
|
52
|
+
entryFile: 'index.android.bundle',
|
|
53
|
+
}),
|
|
50
54
|
);
|
|
51
55
|
}
|
|
52
56
|
const updateJsonFile = await appInfoParser.parser.getEntry(
|
|
@@ -66,21 +70,22 @@ export async function getApkInfo(fn: string) {
|
|
|
66
70
|
}
|
|
67
71
|
}
|
|
68
72
|
if (buildTime == 0) {
|
|
69
|
-
throw new Error(
|
|
70
|
-
'无法获取此包的编译时间戳。请更新 react-native-update 到最新版本后重新打包上传。',
|
|
71
|
-
);
|
|
73
|
+
throw new Error(t('buildTimeNotFound'));
|
|
72
74
|
}
|
|
73
75
|
return { versionName, buildTime, ...appCredential };
|
|
74
76
|
}
|
|
75
77
|
|
|
76
|
-
export async function getAppInfo(fn) {
|
|
78
|
+
export async function getAppInfo(fn: string) {
|
|
77
79
|
const appInfoParser = new AppInfoParser(fn);
|
|
78
80
|
const bundleFile = await appInfoParser.parser.getEntryFromHarmonyApp(
|
|
79
81
|
/rawfile\/bundle.harmony.js/,
|
|
80
82
|
);
|
|
81
83
|
if (!bundleFile) {
|
|
82
84
|
throw new Error(
|
|
83
|
-
'
|
|
85
|
+
t('bundleNotFound', {
|
|
86
|
+
packageType: 'app',
|
|
87
|
+
entryFile: 'bundle.harmony.js',
|
|
88
|
+
}),
|
|
84
89
|
);
|
|
85
90
|
}
|
|
86
91
|
const updateJsonFile = await appInfoParser.parser.getEntryFromHarmonyApp(
|
|
@@ -103,9 +108,7 @@ export async function getAppInfo(fn) {
|
|
|
103
108
|
buildTime = pushy_build_time;
|
|
104
109
|
}
|
|
105
110
|
if (buildTime == 0) {
|
|
106
|
-
throw new Error(
|
|
107
|
-
'无法获取此包的编译时间戳。请更新 react-native-update 到最新版本后重新打包上传。',
|
|
108
|
-
);
|
|
111
|
+
throw new Error(t('buildTimeNotFound'));
|
|
109
112
|
}
|
|
110
113
|
return { versionName, buildTime, ...appCredential };
|
|
111
114
|
}
|
|
@@ -117,7 +120,10 @@ export async function getIpaInfo(fn: string) {
|
|
|
117
120
|
);
|
|
118
121
|
if (!bundleFile) {
|
|
119
122
|
throw new Error(
|
|
120
|
-
'
|
|
123
|
+
t('bundleNotFound', {
|
|
124
|
+
packageType: 'ipa',
|
|
125
|
+
entryFile: 'main.jsbundle',
|
|
126
|
+
}),
|
|
121
127
|
);
|
|
122
128
|
}
|
|
123
129
|
const updateJsonFile = await appInfoParser.parser.getEntry(
|
|
@@ -139,9 +145,7 @@ export async function getIpaInfo(fn: string) {
|
|
|
139
145
|
);
|
|
140
146
|
}
|
|
141
147
|
if (!buildTimeTxtBuffer) {
|
|
142
|
-
throw new Error(
|
|
143
|
-
'无法获取此包的编译时间戳。请更新 react-native-update 到最新版本后重新打包上传。',
|
|
144
|
-
);
|
|
148
|
+
throw new Error(t('buildTimeNotFound'));
|
|
145
149
|
}
|
|
146
150
|
const buildTime = buildTimeTxtBuffer.toString().replace('\n', '');
|
|
147
151
|
return { versionName, buildTime, ...appCredential };
|
|
@@ -158,7 +162,7 @@ export function saveToLocal(originPath: string, destName: string) {
|
|
|
158
162
|
|
|
159
163
|
async function getLatestVersion(pkgNames: string[]) {
|
|
160
164
|
return latestVersion(pkgNames, {
|
|
161
|
-
useCache: true,
|
|
165
|
+
// useCache: true,
|
|
162
166
|
requestOptions: {
|
|
163
167
|
timeout: 2000,
|
|
164
168
|
},
|
|
@@ -168,40 +172,51 @@ async function getLatestVersion(pkgNames: string[]) {
|
|
|
168
172
|
}
|
|
169
173
|
|
|
170
174
|
export async function printVersionCommand() {
|
|
171
|
-
let [
|
|
175
|
+
let [latestRnuCliVersion, latestRnuVersion] = await getLatestVersion([
|
|
172
176
|
'react-native-update-cli',
|
|
173
177
|
'react-native-update',
|
|
174
178
|
]);
|
|
175
|
-
|
|
176
|
-
? `
|
|
179
|
+
latestRnuCliVersion = latestRnuCliVersion
|
|
180
|
+
? ` ${t('latestVersionTag', {
|
|
181
|
+
version: chalk.green(latestRnuCliVersion),
|
|
182
|
+
})}`
|
|
177
183
|
: '';
|
|
178
184
|
console.log(
|
|
179
|
-
`react-native-update-cli: ${pkg.version}${
|
|
185
|
+
`react-native-update-cli: ${pkg.version}${latestRnuCliVersion}`,
|
|
180
186
|
);
|
|
181
|
-
let
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
? `
|
|
187
|
+
let rnuVersion = '';
|
|
188
|
+
rnuVersion = depVersions['react-native-update'];
|
|
189
|
+
latestRnuVersion = latestRnuVersion
|
|
190
|
+
? ` ${t('latestVersionTag', { version: chalk.green(latestRnuVersion) })}`
|
|
185
191
|
: '';
|
|
186
|
-
console.log(`react-native-update: ${
|
|
187
|
-
if (
|
|
188
|
-
if (
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
)
|
|
192
|
+
console.log(`react-native-update: ${rnuVersion}${latestRnuVersion}`);
|
|
193
|
+
if (rnuVersion) {
|
|
194
|
+
if (IS_CRESC) {
|
|
195
|
+
if (semverSatisfies(rnuVersion, '<10.27.0')) {
|
|
196
|
+
console.error(
|
|
197
|
+
'Unsupported version, please update to the latest version: npm i react-native-update@latest',
|
|
198
|
+
);
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
} else {
|
|
202
|
+
if (semverSatisfies(rnuVersion, '<8.5.2')) {
|
|
203
|
+
console.warn(
|
|
204
|
+
`当前版本已不再支持,请至少升级到 v8 的最新小版本后重新打包(代码无需改动): npm i react-native-update@8 .
|
|
205
|
+
如有使用安装 apk 的功能,请注意添加所需权限 https://pushy.reactnative.cn/docs/api#async-function-downloadandinstallapkurl`,
|
|
206
|
+
);
|
|
207
|
+
} else if (semverSatisfies(rnuVersion, '9.0.0 - 9.2.1')) {
|
|
208
|
+
console.warn(
|
|
209
|
+
`当前版本已不再支持,请至少升级到 v9 的最新小版本后重新打包(代码无需改动,可直接热更): npm i react-native-update@9 .
|
|
210
|
+
如有使用安装 apk 的功能,请注意添加所需权限 https://pushy.reactnative.cn/docs/api#async-function-downloadandinstallapkurl`,
|
|
211
|
+
);
|
|
212
|
+
} else if (semverSatisfies(rnuVersion, '10.0.0 - 10.17.0')) {
|
|
213
|
+
console.warn(
|
|
214
|
+
'当前版本已不再支持,请升级到 v10 的最新小版本(代码无需改动,可直接热更): npm i react-native-update@10',
|
|
215
|
+
);
|
|
216
|
+
}
|
|
202
217
|
}
|
|
203
218
|
} else {
|
|
204
|
-
console.log('
|
|
219
|
+
console.log(t('rnuVersionNotFound'));
|
|
205
220
|
}
|
|
206
221
|
}
|
|
207
222
|
|
package/src/versions.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { choosePackage } from './package';
|
|
|
6
6
|
import { compare } from 'compare-versions';
|
|
7
7
|
import { depVersions } from './utils/dep-versions';
|
|
8
8
|
import { getCommitInfo } from './utils/git';
|
|
9
|
+
import { Platform } from 'types';
|
|
9
10
|
|
|
10
11
|
async function showVersion(appId: string, offset: number) {
|
|
11
12
|
const { data, count } = await get(`/app/${appId}/version/list`);
|
|
@@ -61,7 +62,7 @@ async function chooseVersion(appId: string) {
|
|
|
61
62
|
const cmd = await question(
|
|
62
63
|
'Enter versionId or page Up/page Down/Begin(U/D/B)',
|
|
63
64
|
);
|
|
64
|
-
switch (cmd.
|
|
65
|
+
switch (cmd.toUpperCase()) {
|
|
65
66
|
case 'U':
|
|
66
67
|
offset = Math.max(0, offset - 10);
|
|
67
68
|
break;
|
|
@@ -82,7 +83,12 @@ async function chooseVersion(appId: string) {
|
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
export const commands = {
|
|
85
|
-
publish: async function ({ args, options }
|
|
86
|
+
publish: async function ({ args, options }: { args: string[]; options: {
|
|
87
|
+
name: string;
|
|
88
|
+
description?: string;
|
|
89
|
+
metaInfo?: string;
|
|
90
|
+
platform?: Platform;
|
|
91
|
+
} }) {
|
|
86
92
|
const fn = args[0];
|
|
87
93
|
const { name, description, metaInfo } = options;
|
|
88
94
|
|
|
@@ -136,7 +142,7 @@ export const commands = {
|
|
|
136
142
|
versionId = null;
|
|
137
143
|
}
|
|
138
144
|
|
|
139
|
-
let pkgId;
|
|
145
|
+
let pkgId: string | undefined;
|
|
140
146
|
let pkgVersion = options.packageVersion;
|
|
141
147
|
let minPkgVersion = options.minPackageVersion;
|
|
142
148
|
let maxPkgVersion = options.maxPackageVersion;
|