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.
Files changed (44) hide show
  1. package/cli.json +1 -0
  2. package/lib/esm/api..mjs +183 -0
  3. package/lib/esm/app..mjs +130 -0
  4. package/lib/esm/bundle..mjs +823 -0
  5. package/lib/esm/exports..mjs +11 -0
  6. package/lib/esm/index..mjs +122 -0
  7. package/lib/esm/install..mjs +18 -0
  8. package/lib/esm/locales/en..mjs +131 -0
  9. package/lib/esm/locales/zh..mjs +130 -0
  10. package/lib/esm/module-manager..mjs +109 -0
  11. package/lib/esm/modules/app-module..mjs +213 -0
  12. package/lib/esm/modules/bundle-module..mjs +178 -0
  13. package/lib/esm/modules/index..mjs +17 -0
  14. package/lib/esm/modules/package-module..mjs +6 -0
  15. package/lib/esm/modules/user-module..mjs +351 -0
  16. package/lib/esm/modules/version-module..mjs +6 -0
  17. package/lib/esm/package..mjs +316 -0
  18. package/lib/esm/provider..mjs +293 -0
  19. package/lib/esm/types..mjs +1 -0
  20. package/lib/esm/user..mjs +36 -0
  21. package/lib/esm/utils/add-gitignore..mjs +32 -0
  22. package/lib/esm/utils/app-info-parser/aab..mjs +215 -0
  23. package/lib/esm/utils/app-info-parser/apk..mjs +75 -0
  24. package/lib/esm/utils/app-info-parser/app..mjs +3 -0
  25. package/lib/esm/utils/app-info-parser/index..mjs +44 -0
  26. package/lib/esm/utils/app-info-parser/ipa..mjs +73 -0
  27. package/lib/esm/utils/app-info-parser/resource-finder..mjs +401 -0
  28. package/lib/esm/utils/app-info-parser/utils..mjs +121 -0
  29. package/lib/esm/utils/app-info-parser/xml-parser/binary..mjs +569 -0
  30. package/lib/esm/utils/app-info-parser/xml-parser/manifest..mjs +200 -0
  31. package/lib/esm/utils/app-info-parser/zip..mjs +65 -0
  32. package/lib/esm/utils/check-lockfile..mjs +78 -0
  33. package/lib/esm/utils/check-plugin..mjs +25 -0
  34. package/lib/esm/utils/constants..mjs +19 -0
  35. package/lib/esm/utils/dep-versions..mjs +33 -0
  36. package/lib/esm/utils/git..mjs +43 -0
  37. package/lib/esm/utils/http-helper..mjs +70 -0
  38. package/lib/esm/utils/i18n..mjs +23 -0
  39. package/lib/esm/utils/index..mjs +316 -0
  40. package/lib/esm/utils/latest-version/cli..mjs +294 -0
  41. package/lib/esm/utils/latest-version/index..mjs +238 -0
  42. package/lib/esm/utils/plugin-config..mjs +23 -0
  43. package/lib/esm/versions..mjs +290 -0
  44. package/package.json +19 -2
package/cli.json CHANGED
@@ -254,6 +254,7 @@
254
254
  "default": false
255
255
  },
256
256
  "hermes": {
257
+ "hasValue": true,
257
258
  "default": false
258
259
  },
259
260
  "name": {
@@ -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
+ };
@@ -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
+ };