react-native-update-cli 2.7.1 → 2.7.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/cli.json +1 -0
- package/lib/esm/api..mjs +183 -0
- package/lib/esm/app..mjs +130 -0
- package/lib/esm/bundle..mjs +823 -0
- package/lib/esm/exports..mjs +11 -0
- package/lib/esm/index..mjs +122 -0
- package/lib/esm/install..mjs +18 -0
- package/lib/esm/locales/en..mjs +131 -0
- package/lib/esm/locales/zh..mjs +130 -0
- package/lib/esm/module-manager..mjs +109 -0
- package/lib/esm/modules/app-module..mjs +213 -0
- package/lib/esm/modules/bundle-module..mjs +178 -0
- package/lib/esm/modules/index..mjs +17 -0
- package/lib/esm/modules/package-module..mjs +6 -0
- package/lib/esm/modules/user-module..mjs +351 -0
- package/lib/esm/modules/version-module..mjs +6 -0
- package/lib/esm/package..mjs +316 -0
- package/lib/esm/provider..mjs +293 -0
- package/lib/esm/types..mjs +1 -0
- package/lib/esm/user..mjs +36 -0
- package/lib/esm/utils/add-gitignore..mjs +32 -0
- package/lib/esm/utils/app-info-parser/aab..mjs +215 -0
- package/lib/esm/utils/app-info-parser/apk..mjs +75 -0
- package/lib/esm/utils/app-info-parser/app..mjs +3 -0
- package/lib/esm/utils/app-info-parser/index..mjs +44 -0
- package/lib/esm/utils/app-info-parser/ipa..mjs +73 -0
- package/lib/esm/utils/app-info-parser/resource-finder..mjs +401 -0
- package/lib/esm/utils/app-info-parser/utils..mjs +121 -0
- package/lib/esm/utils/app-info-parser/xml-parser/binary..mjs +569 -0
- package/lib/esm/utils/app-info-parser/xml-parser/manifest..mjs +200 -0
- package/lib/esm/utils/app-info-parser/zip..mjs +65 -0
- package/lib/esm/utils/check-lockfile..mjs +78 -0
- package/lib/esm/utils/check-plugin..mjs +25 -0
- package/lib/esm/utils/constants..mjs +19 -0
- package/lib/esm/utils/dep-versions..mjs +33 -0
- package/lib/esm/utils/git..mjs +43 -0
- package/lib/esm/utils/http-helper..mjs +70 -0
- package/lib/esm/utils/i18n..mjs +23 -0
- package/lib/esm/utils/index..mjs +316 -0
- package/lib/esm/utils/latest-version/cli..mjs +294 -0
- package/lib/esm/utils/latest-version/index..mjs +238 -0
- package/lib/esm/utils/plugin-config..mjs +23 -0
- package/lib/esm/versions..mjs +290 -0
- package/package.json +19 -2
package/cli.json
CHANGED
package/lib/esm/api..mjs
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import util from "util";
|
|
4
|
+
import filesizeParser from "filesize-parser";
|
|
5
|
+
import FormData from "form-data";
|
|
6
|
+
import fetch from "node-fetch";
|
|
7
|
+
import ProgressBar from "progress";
|
|
8
|
+
import tcpp from "tcp-ping";
|
|
9
|
+
import { getBaseUrl } from "./utils/http-helper";
|
|
10
|
+
import packageJson from "../package.json";
|
|
11
|
+
import { credentialFile, pricingPageUrl, IS_CRESC } from "./utils/constants";
|
|
12
|
+
import { t } from "./utils/i18n";
|
|
13
|
+
const tcpPing = util.promisify(tcpp.ping);
|
|
14
|
+
let session;
|
|
15
|
+
let savedSession;
|
|
16
|
+
let apiToken;
|
|
17
|
+
const userAgent = `react-native-update-cli/${packageJson.version}`;
|
|
18
|
+
export const getSession = ()=>session;
|
|
19
|
+
export const getApiToken = ()=>apiToken;
|
|
20
|
+
export const setApiToken = (token)=>{
|
|
21
|
+
apiToken = token;
|
|
22
|
+
};
|
|
23
|
+
const loadApiTokenFromEnv = ()=>{
|
|
24
|
+
// Use CRESC_API_TOKEN for cresc, PUSHY_API_TOKEN for pushy
|
|
25
|
+
const envToken = IS_CRESC ? process.env.CRESC_API_TOKEN : process.env.PUSHY_API_TOKEN;
|
|
26
|
+
if (envToken) {
|
|
27
|
+
apiToken = envToken;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
export const replaceSession = (newSession)=>{
|
|
31
|
+
session = newSession;
|
|
32
|
+
};
|
|
33
|
+
export const loadSession = async ()=>{
|
|
34
|
+
loadApiTokenFromEnv();
|
|
35
|
+
if (fs.existsSync(credentialFile)) {
|
|
36
|
+
try {
|
|
37
|
+
replaceSession(JSON.parse(fs.readFileSync(credentialFile, 'utf8')));
|
|
38
|
+
savedSession = session;
|
|
39
|
+
} catch (e) {
|
|
40
|
+
console.error(`Failed to parse file ${credentialFile}. Try to remove it manually.`);
|
|
41
|
+
throw e;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
export const saveSession = ()=>{
|
|
46
|
+
// Only save on change.
|
|
47
|
+
if (session !== savedSession) {
|
|
48
|
+
const current = session;
|
|
49
|
+
const data = JSON.stringify(current, null, 4);
|
|
50
|
+
fs.writeFileSync(credentialFile, data, 'utf8');
|
|
51
|
+
savedSession = current;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
export const closeSession = ()=>{
|
|
55
|
+
if (fs.existsSync(credentialFile)) {
|
|
56
|
+
fs.unlinkSync(credentialFile);
|
|
57
|
+
savedSession = undefined;
|
|
58
|
+
}
|
|
59
|
+
session = undefined;
|
|
60
|
+
};
|
|
61
|
+
async function query(url, options) {
|
|
62
|
+
const baseUrl = await getBaseUrl;
|
|
63
|
+
const fullUrl = `${baseUrl}${url}`;
|
|
64
|
+
const resp = await fetch(fullUrl, options);
|
|
65
|
+
const text = await resp.text();
|
|
66
|
+
let json;
|
|
67
|
+
try {
|
|
68
|
+
json = JSON.parse(text);
|
|
69
|
+
} catch (e) {}
|
|
70
|
+
if (resp.status !== 200) {
|
|
71
|
+
const message = (json == null ? void 0 : json.message) || resp.statusText;
|
|
72
|
+
if (resp.status === 401) {
|
|
73
|
+
throw new Error(t('loginExpired'));
|
|
74
|
+
}
|
|
75
|
+
throw new Error(message);
|
|
76
|
+
}
|
|
77
|
+
return json;
|
|
78
|
+
}
|
|
79
|
+
function queryWithoutBody(method) {
|
|
80
|
+
return (api)=>{
|
|
81
|
+
const headers = {
|
|
82
|
+
'User-Agent': userAgent
|
|
83
|
+
};
|
|
84
|
+
if (apiToken) {
|
|
85
|
+
headers['x-api-token'] = apiToken;
|
|
86
|
+
} else if (session == null ? void 0 : session.token) {
|
|
87
|
+
headers['X-AccessToken'] = session.token;
|
|
88
|
+
}
|
|
89
|
+
return query(api, {
|
|
90
|
+
method,
|
|
91
|
+
headers
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function queryWithBody(method) {
|
|
96
|
+
return (api, body)=>{
|
|
97
|
+
const headers = {
|
|
98
|
+
'User-Agent': userAgent,
|
|
99
|
+
'Content-Type': 'application/json'
|
|
100
|
+
};
|
|
101
|
+
if (apiToken) {
|
|
102
|
+
headers['x-api-token'] = apiToken;
|
|
103
|
+
} else if (session == null ? void 0 : session.token) {
|
|
104
|
+
headers['X-AccessToken'] = session.token;
|
|
105
|
+
}
|
|
106
|
+
return query(api, {
|
|
107
|
+
method,
|
|
108
|
+
headers,
|
|
109
|
+
body: JSON.stringify(body)
|
|
110
|
+
});
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
export const get = queryWithoutBody('GET');
|
|
114
|
+
export const post = queryWithBody('POST');
|
|
115
|
+
export const put = queryWithBody('PUT');
|
|
116
|
+
export const doDelete = queryWithBody('DELETE');
|
|
117
|
+
export async function uploadFile(fn, key) {
|
|
118
|
+
const { url, backupUrl, formData, maxSize } = await post('/upload', {
|
|
119
|
+
ext: path.extname(fn)
|
|
120
|
+
});
|
|
121
|
+
let realUrl = url;
|
|
122
|
+
if (backupUrl) {
|
|
123
|
+
// @ts-ignore
|
|
124
|
+
if (global.USE_ACC_OSS) {
|
|
125
|
+
realUrl = backupUrl;
|
|
126
|
+
} else {
|
|
127
|
+
const pingResult = await tcpPing({
|
|
128
|
+
address: url.replace('https://', ''),
|
|
129
|
+
attempts: 4,
|
|
130
|
+
timeout: 1000
|
|
131
|
+
});
|
|
132
|
+
// console.log({pingResult});
|
|
133
|
+
if (Number.isNaN(pingResult.avg) || pingResult.avg > 150) {
|
|
134
|
+
realUrl = backupUrl;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// console.log({realUrl});
|
|
138
|
+
}
|
|
139
|
+
const fileSize = fs.statSync(fn).size;
|
|
140
|
+
if (maxSize && fileSize > filesizeParser(maxSize)) {
|
|
141
|
+
const readableFileSize = `${(fileSize / 1048576).toFixed(1)}m`;
|
|
142
|
+
throw new Error(t('fileSizeExceeded', {
|
|
143
|
+
fileSize: readableFileSize,
|
|
144
|
+
maxSize,
|
|
145
|
+
pricingPageUrl
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
148
|
+
const bar = new ProgressBar(' Uploading [:bar] :percent :etas', {
|
|
149
|
+
complete: '=',
|
|
150
|
+
incomplete: ' ',
|
|
151
|
+
total: fileSize
|
|
152
|
+
});
|
|
153
|
+
const form = new FormData();
|
|
154
|
+
for (const [k, v] of Object.entries(formData)){
|
|
155
|
+
form.append(k, v);
|
|
156
|
+
}
|
|
157
|
+
const fileStream = fs.createReadStream(fn);
|
|
158
|
+
fileStream.on('data', (data)=>{
|
|
159
|
+
bar.tick(data.length);
|
|
160
|
+
});
|
|
161
|
+
if (key) {
|
|
162
|
+
form.append('key', key);
|
|
163
|
+
}
|
|
164
|
+
form.append('file', fileStream);
|
|
165
|
+
// form.append('file', fileStream, {
|
|
166
|
+
// contentType: 'application/octet-stream',
|
|
167
|
+
// });
|
|
168
|
+
const res = await fetch(realUrl, {
|
|
169
|
+
method: 'POST',
|
|
170
|
+
body: form
|
|
171
|
+
});
|
|
172
|
+
if (res.status > 299) {
|
|
173
|
+
throw new Error(`${res.status}: ${res.statusText}`);
|
|
174
|
+
}
|
|
175
|
+
// const body = await response.json();
|
|
176
|
+
return {
|
|
177
|
+
hash: key || formData.key
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
export const getAllPackages = async (appId)=>{
|
|
181
|
+
const { data } = await get(`/app/${appId}/package/list?limit=1000`);
|
|
182
|
+
return data;
|
|
183
|
+
};
|
package/lib/esm/app..mjs
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import Table from "tty-table";
|
|
3
|
+
import { question } from "./utils";
|
|
4
|
+
import { doDelete, get, post } from "./api";
|
|
5
|
+
import { t } from "./utils/i18n";
|
|
6
|
+
const validPlatforms = [
|
|
7
|
+
'ios',
|
|
8
|
+
'android',
|
|
9
|
+
'harmony'
|
|
10
|
+
];
|
|
11
|
+
export async function getPlatform(platform) {
|
|
12
|
+
return assertPlatform(platform || await question(t('platformQuestion')));
|
|
13
|
+
}
|
|
14
|
+
export function assertPlatform(platform) {
|
|
15
|
+
if (!validPlatforms.includes(platform)) {
|
|
16
|
+
throw new Error(t('unsupportedPlatform', {
|
|
17
|
+
platform
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
return platform;
|
|
21
|
+
}
|
|
22
|
+
export function getSelectedApp(platform) {
|
|
23
|
+
assertPlatform(platform);
|
|
24
|
+
if (!fs.existsSync('update.json')) {
|
|
25
|
+
throw new Error(t('appNotSelected', {
|
|
26
|
+
platform
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
const updateInfo = JSON.parse(fs.readFileSync('update.json', 'utf8'));
|
|
30
|
+
if (!updateInfo[platform]) {
|
|
31
|
+
throw new Error(t('appNotSelected', {
|
|
32
|
+
platform
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
return updateInfo[platform];
|
|
36
|
+
}
|
|
37
|
+
export async function listApp(platform = '') {
|
|
38
|
+
const { data } = await get('/app/list');
|
|
39
|
+
const list = platform ? data.filter((v)=>v.platform === platform) : data;
|
|
40
|
+
const header = [
|
|
41
|
+
{
|
|
42
|
+
value: t('appId')
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
value: t('appName')
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
value: t('platform')
|
|
49
|
+
}
|
|
50
|
+
];
|
|
51
|
+
const rows = [];
|
|
52
|
+
for (const app of list){
|
|
53
|
+
rows.push([
|
|
54
|
+
app.id,
|
|
55
|
+
app.name,
|
|
56
|
+
app.platform
|
|
57
|
+
]);
|
|
58
|
+
}
|
|
59
|
+
console.log(Table(header, rows).render());
|
|
60
|
+
console.log(`\n${t('totalApps', {
|
|
61
|
+
count: list.length,
|
|
62
|
+
platform
|
|
63
|
+
})}`);
|
|
64
|
+
return list;
|
|
65
|
+
}
|
|
66
|
+
export async function chooseApp(platform) {
|
|
67
|
+
const list = await listApp(platform);
|
|
68
|
+
while(true){
|
|
69
|
+
const id = await question(t('enterAppIdQuestion'));
|
|
70
|
+
const app = list.find((v)=>v.id === Number(id));
|
|
71
|
+
if (app) {
|
|
72
|
+
return app;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export const appCommands = {
|
|
77
|
+
createApp: async function({ options }) {
|
|
78
|
+
const name = options.name || await question(t('appNameQuestion'));
|
|
79
|
+
const { downloadUrl } = options;
|
|
80
|
+
const platform = await getPlatform(options.platform);
|
|
81
|
+
const { id } = await post('/app/create', {
|
|
82
|
+
name,
|
|
83
|
+
platform,
|
|
84
|
+
downloadUrl
|
|
85
|
+
});
|
|
86
|
+
console.log(t('createAppSuccess', {
|
|
87
|
+
id
|
|
88
|
+
}));
|
|
89
|
+
await this.selectApp({
|
|
90
|
+
args: [
|
|
91
|
+
id
|
|
92
|
+
],
|
|
93
|
+
options: {
|
|
94
|
+
platform
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
},
|
|
98
|
+
deleteApp: async ({ args, options })=>{
|
|
99
|
+
const { platform } = options;
|
|
100
|
+
const id = args[0] || chooseApp(platform);
|
|
101
|
+
if (!id) {
|
|
102
|
+
console.log(t('cancelled'));
|
|
103
|
+
}
|
|
104
|
+
await doDelete(`/app/${id}`);
|
|
105
|
+
console.log(t('operationSuccess'));
|
|
106
|
+
},
|
|
107
|
+
apps: async ({ options })=>{
|
|
108
|
+
const { platform } = options;
|
|
109
|
+
listApp(platform);
|
|
110
|
+
},
|
|
111
|
+
selectApp: async ({ args, options })=>{
|
|
112
|
+
const platform = await getPlatform(options.platform);
|
|
113
|
+
const id = args[0] ? Number.parseInt(args[0]) : (await chooseApp(platform)).id;
|
|
114
|
+
let updateInfo = {};
|
|
115
|
+
if (fs.existsSync('update.json')) {
|
|
116
|
+
try {
|
|
117
|
+
updateInfo = JSON.parse(fs.readFileSync('update.json', 'utf8'));
|
|
118
|
+
} catch (e) {
|
|
119
|
+
console.error(t('failedToParseUpdateJson'));
|
|
120
|
+
throw e;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const { appKey } = await get(`/app/${id}`);
|
|
124
|
+
updateInfo[platform] = {
|
|
125
|
+
appId: id,
|
|
126
|
+
appKey
|
|
127
|
+
};
|
|
128
|
+
fs.writeFileSync('update.json', JSON.stringify(updateInfo, null, 4), 'utf8');
|
|
129
|
+
}
|
|
130
|
+
};
|