react-native-update-cli 1.46.1 → 2.0.0

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 (64) hide show
  1. package/README.md +578 -1
  2. package/README.zh-CN.md +576 -0
  3. package/cli.json +18 -0
  4. package/lib/api.js +5 -5
  5. package/lib/app.js +1 -1
  6. package/lib/bundle.js +43 -29
  7. package/lib/exports.js +65 -0
  8. package/lib/index.js +100 -9
  9. package/lib/module-manager.js +125 -0
  10. package/lib/modules/app-module.js +223 -0
  11. package/lib/modules/bundle-module.js +188 -0
  12. package/lib/modules/index.js +42 -0
  13. package/lib/modules/package-module.js +16 -0
  14. package/lib/modules/user-module.js +402 -0
  15. package/lib/modules/version-module.js +16 -0
  16. package/lib/package.js +16 -6
  17. package/lib/provider.js +340 -0
  18. package/lib/user.js +3 -3
  19. package/lib/utils/app-info-parser/apk.js +1 -1
  20. package/lib/utils/app-info-parser/ipa.js +2 -2
  21. package/lib/utils/app-info-parser/resource-finder.js +35 -35
  22. package/lib/utils/app-info-parser/xml-parser/manifest.js +2 -2
  23. package/lib/utils/app-info-parser/zip.js +3 -6
  24. package/lib/utils/check-plugin.js +1 -1
  25. package/lib/utils/git.js +1 -1
  26. package/lib/utils/i18n.js +3 -1
  27. package/lib/utils/index.js +4 -4
  28. package/lib/utils/latest-version/cli.js +3 -3
  29. package/lib/utils/latest-version/index.js +4 -4
  30. package/lib/versions.js +2 -2
  31. package/package.json +4 -4
  32. package/src/api.ts +7 -7
  33. package/src/app.ts +2 -2
  34. package/src/bundle.ts +57 -32
  35. package/src/exports.ts +30 -0
  36. package/src/index.ts +118 -16
  37. package/src/module-manager.ts +149 -0
  38. package/src/modules/app-module.ts +205 -0
  39. package/src/modules/bundle-module.ts +202 -0
  40. package/src/modules/index.ts +19 -0
  41. package/src/modules/package-module.ts +11 -0
  42. package/src/modules/user-module.ts +406 -0
  43. package/src/modules/version-module.ts +8 -0
  44. package/src/package.ts +29 -16
  45. package/src/provider.ts +341 -0
  46. package/src/types.ts +125 -0
  47. package/src/user.ts +4 -3
  48. package/src/utils/app-info-parser/apk.js +62 -52
  49. package/src/utils/app-info-parser/app.js +5 -5
  50. package/src/utils/app-info-parser/ipa.js +69 -57
  51. package/src/utils/app-info-parser/resource-finder.js +50 -54
  52. package/src/utils/app-info-parser/utils.js +59 -54
  53. package/src/utils/app-info-parser/xml-parser/binary.js +366 -354
  54. package/src/utils/app-info-parser/xml-parser/manifest.js +145 -137
  55. package/src/utils/app-info-parser/zip.js +1 -1
  56. package/src/utils/check-plugin.ts +4 -2
  57. package/src/utils/dep-versions.ts +13 -6
  58. package/src/utils/git.ts +1 -1
  59. package/src/utils/i18n.ts +3 -1
  60. package/src/utils/index.ts +8 -10
  61. package/src/utils/latest-version/cli.ts +4 -4
  62. package/src/utils/latest-version/index.ts +17 -17
  63. package/src/utils/plugin-config.ts +3 -3
  64. package/src/versions.ts +3 -3
@@ -0,0 +1,576 @@
1
+ # React Native Update CLI
2
+
3
+ 这是一个统一的React Native Update CLI,同时支持传统命令和模块化架构以及自定义发布流程。
4
+
5
+ ## 🚀 特性
6
+
7
+ - **统一CLI**: 使用单个`pushy`命令提供所有功能
8
+ - **向后兼容**: 所有现有命令都能正常工作
9
+ - **模块化架构**: 将CLI功能拆分为独立的模块
10
+ - **自定义工作流**: 支持创建自定义的发布流程
11
+ - **可扩展性**: 用户可以导入和注册自定义模块
12
+ - **类型安全**: 完整的TypeScript类型支持
13
+
14
+ ## 📦 安装
15
+
16
+ ```bash
17
+ npm install react-native-update-cli
18
+ ```
19
+
20
+ ## 🎯 快速开始
21
+
22
+ ### 基本使用
23
+
24
+ ```bash
25
+ # 使用统一CLI
26
+ npx pushy help
27
+
28
+ # 列出所有可用命令和工作流
29
+ npx pushy list
30
+
31
+ # 执行内置的工作流
32
+ npx pushy workflow setup-app
33
+
34
+ # 执行自定义工作流
35
+ npx pushy workflow custom-publish
36
+ ```
37
+
38
+ ### 编程方式使用
39
+
40
+ ```typescript
41
+ import { moduleManager, CLIProviderImpl } from 'react-native-update-cli';
42
+
43
+ // 获取CLI提供者
44
+ const provider = moduleManager.getProvider();
45
+
46
+ // 执行打包
47
+ const bundleResult = await provider.bundle({
48
+ platform: 'ios',
49
+ dev: false,
50
+ sourcemap: true
51
+ });
52
+
53
+ // 发布版本
54
+ const publishResult = await provider.publish({
55
+ name: 'v1.2.3',
56
+ description: 'Bug fixes and improvements',
57
+ rollout: 100
58
+ });
59
+ ```
60
+
61
+ ## 🔧 创建自定义模块
62
+
63
+ ### 1. 定义模块
64
+
65
+ ```typescript
66
+ import type { CLIModule, CommandDefinition, CustomWorkflow } from 'react-native-update-cli';
67
+
68
+ export const myCustomModule: CLIModule = {
69
+ name: 'my-custom',
70
+ version: '1.0.0',
71
+
72
+ commands: [
73
+ {
74
+ name: 'custom-command',
75
+ description: 'My custom command',
76
+ handler: async (context) => {
77
+ console.log('Executing custom command...');
78
+ return {
79
+ success: true,
80
+ data: { message: 'Custom command executed' }
81
+ };
82
+ },
83
+ options: {
84
+ param: { hasValue: true, description: 'Custom parameter' }
85
+ }
86
+ }
87
+ ],
88
+
89
+ workflows: [
90
+ {
91
+ name: 'my-workflow',
92
+ description: 'My custom workflow',
93
+ steps: [
94
+ {
95
+ name: 'step1',
96
+ description: 'First step',
97
+ execute: async (context, previousResult) => {
98
+ console.log('Executing step 1...');
99
+ return { step1Completed: true };
100
+ }
101
+ },
102
+ {
103
+ name: 'step2',
104
+ description: 'Second step',
105
+ execute: async (context, previousResult) => {
106
+ console.log('Executing step 2...');
107
+ return { ...previousResult, step2Completed: true };
108
+ }
109
+ }
110
+ ]
111
+ }
112
+ ],
113
+
114
+ init: (provider) => {
115
+ console.log('Custom module initialized');
116
+ },
117
+
118
+ cleanup: () => {
119
+ console.log('Custom module cleanup');
120
+ }
121
+ };
122
+ ```
123
+
124
+ ### 2. 注册模块
125
+
126
+ ```typescript
127
+ import { moduleManager } from 'react-native-update-cli';
128
+ import { myCustomModule } from './my-custom-module';
129
+
130
+ // 注册自定义模块
131
+ moduleManager.registerModule(myCustomModule);
132
+
133
+ // 执行自定义命令
134
+ const result = await moduleManager.executeCommand('custom-command', {
135
+ args: [],
136
+ options: { param: 'value' }
137
+ });
138
+
139
+ // 执行自定义工作流
140
+ const workflowResult = await moduleManager.executeWorkflow('my-workflow', {
141
+ args: [],
142
+ options: {}
143
+ });
144
+ ```
145
+
146
+ ## 🔄 工作流系统
147
+
148
+ ### 工作流步骤
149
+
150
+ 每个工作流步骤包含:
151
+
152
+ - `name`: 步骤名称
153
+ - `description`: 步骤描述
154
+ - `execute`: 执行函数
155
+ - `condition`: 可选的条件函数
156
+
157
+ ### 条件执行
158
+
159
+ ```typescript
160
+ {
161
+ name: 'conditional-step',
162
+ description: 'Only execute in production',
163
+ execute: async (context, previousResult) => {
164
+ // 执行逻辑
165
+ },
166
+ condition: (context) => {
167
+ return context.options.environment === 'production';
168
+ }
169
+ }
170
+ ```
171
+
172
+ ### 工作流验证
173
+
174
+ ```typescript
175
+ {
176
+ name: 'validated-workflow',
177
+ description: 'Workflow with validation',
178
+ steps: [...],
179
+ validate: (context) => {
180
+ if (!context.options.requiredParam) {
181
+ console.error('Required parameter missing');
182
+ return false;
183
+ }
184
+ return true;
185
+ }
186
+ }
187
+ ```
188
+
189
+ ## 📋 内置模块
190
+
191
+ ### Bundle模块 (`bundle`)
192
+ - `bundle`: 打包JavaScript代码并可选发布
193
+ - `diff`: 生成两个PPK文件之间的差异
194
+ - `hdiff`: 生成两个PPK文件之间的hdiff
195
+ - `diffFromApk`: 从APK文件生成差异
196
+ - `hdiffFromApk`: 从APK文件生成hdiff
197
+ - `hdiffFromApp`: 从APP文件生成hdiff
198
+ - `diffFromIpa`: 从IPA文件生成差异
199
+ - `hdiffFromIpa`: 从IPA文件生成hdiff
200
+
201
+ ### Version模块 (`version`)
202
+ - `publish`: 发布新版本
203
+ - `versions`: 列出所有版本
204
+ - `update`: 更新版本信息
205
+ - `updateVersionInfo`: 更新版本元数据
206
+
207
+ ### App模块 (`app`)
208
+ - `createApp`: 创建新应用
209
+ - `apps`: 列出所有应用
210
+ - `selectApp`: 选择应用
211
+ - `deleteApp`: 删除应用
212
+
213
+ ### Package模块 (`package`)
214
+ - `uploadIpa`: 上传IPA文件
215
+ - `uploadApk`: 上传APK文件
216
+ - `uploadApp`: 上传APP文件
217
+ - `parseApp`: 解析APP文件信息
218
+ - `parseIpa`: 解析IPA文件信息
219
+ - `parseApk`: 解析APK文件信息
220
+ - `packages`: 列出包
221
+
222
+ ### User模块 (`user`)
223
+ - `login`: 登录
224
+ - `logout`: 登出
225
+ - `me`: 显示用户信息
226
+
227
+ ## 🛠️ CLI提供者API
228
+
229
+ ### 核心功能
230
+
231
+ ```typescript
232
+ interface CLIProvider {
233
+ // 打包
234
+ bundle(options: BundleOptions): Promise<CommandResult>;
235
+
236
+ // 发布
237
+ publish(options: PublishOptions): Promise<CommandResult>;
238
+
239
+ // 上传
240
+ upload(options: UploadOptions): Promise<CommandResult>;
241
+
242
+ // 应用管理
243
+ getSelectedApp(platform?: Platform): Promise<{ appId: string; platform: Platform }>;
244
+ listApps(platform?: Platform): Promise<CommandResult>;
245
+ createApp(name: string, platform: Platform): Promise<CommandResult>;
246
+
247
+ // 版本管理
248
+ listVersions(appId: string): Promise<CommandResult>;
249
+ getVersion(appId: string, versionId: string): Promise<CommandResult>;
250
+ updateVersion(appId: string, versionId: string, updates: Partial<Version>): Promise<CommandResult>;
251
+
252
+ // 包管理
253
+ listPackages(appId: string, platform?: Platform): Promise<CommandResult>;
254
+ getPackage(appId: string, packageId: string): Promise<CommandResult>;
255
+
256
+ // 工具函数
257
+ getPlatform(platform?: Platform): Promise<Platform>;
258
+ loadSession(): Promise<Session>;
259
+ saveToLocal(key: string, value: string): void;
260
+ question(prompt: string): Promise<string>;
261
+
262
+ // 工作流
263
+ registerWorkflow(workflow: CustomWorkflow): void;
264
+ executeWorkflow(workflowName: string, context: CommandContext): Promise<CommandResult>;
265
+ }
266
+ ```
267
+
268
+ ### 自定义命令
269
+
270
+ ```typescript
271
+ // 执行自定义打包命令
272
+ const bundleResult = await moduleManager.executeCommand('custom-bundle', {
273
+ args: [],
274
+ options: {
275
+ platform: 'android',
276
+ validate: true,
277
+ optimize: true
278
+ }
279
+ });
280
+
281
+ // 生成差异文件
282
+ const diffResult = await moduleManager.executeCommand('diff', {
283
+ args: [],
284
+ options: {
285
+ origin: './build/v1.0.0.ppk',
286
+ next: './build/v1.1.0.ppk',
287
+ output: './build/diff.patch'
288
+ }
289
+ });
290
+
291
+ // 从APK文件生成差异
292
+ const apkDiffResult = await moduleManager.executeCommand('diffFromApk', {
293
+ args: [],
294
+ options: {
295
+ origin: './build/app-v1.0.0.apk',
296
+ next: './build/app-v1.1.0.apk',
297
+ output: './build/apk-diff.patch'
298
+ }
299
+ });
300
+ ```
301
+
302
+ ## 🔧 配置
303
+
304
+ ### 环境变量
305
+
306
+ ```bash
307
+ # 设置API端点
308
+ export PUSHY_REGISTRY=https://your-api-endpoint.com
309
+
310
+ # 设置非交互模式
311
+ export NO_INTERACTIVE=true
312
+ ```
313
+
314
+ ### 配置文件
315
+
316
+ 创建 `update.json` 文件:
317
+
318
+ ```json
319
+ {
320
+ "ios": {
321
+ "appId": "your-ios-app-id",
322
+ "appKey": "your-ios-app-key"
323
+ },
324
+ "android": {
325
+ "appId": "your-android-app-id",
326
+ "appKey": "your-android-app-key"
327
+ }
328
+ }
329
+ ```
330
+
331
+ ## 🚨 注意事项
332
+
333
+ 1. **向后兼容**: 新的模块化CLI保持与现有CLI的兼容性
334
+ 2. **类型安全**: 所有API都有完整的TypeScript类型定义
335
+ 3. **错误处理**: 所有操作都返回标准化的结果格式
336
+ 4. **资源清理**: 模块支持清理函数来释放资源
337
+ 5. **模块分离**: 功能按逻辑分离到不同模块中,便于维护和扩展
338
+
339
+ ## 🤝 贡献
340
+
341
+ 欢迎提交Issue和Pull Request来改进这个项目!
342
+
343
+ ## 🚀 Provider API 使用指南
344
+
345
+ Provider提供了简洁的编程接口,适合在应用程序中集成React Native Update CLI功能。
346
+
347
+ ### 📋 核心API方法
348
+
349
+ #### 核心业务功能
350
+ ```typescript
351
+ // 打包应用
352
+ await provider.bundle({
353
+ platform: 'ios',
354
+ dev: false,
355
+ sourcemap: true
356
+ });
357
+
358
+ // 发布版本
359
+ await provider.publish({
360
+ name: 'v1.0.0',
361
+ description: 'Bug fixes',
362
+ rollout: 100
363
+ });
364
+
365
+ // 上传文件
366
+ await provider.upload({
367
+ filePath: 'app.ipa',
368
+ platform: 'ios'
369
+ });
370
+ ```
371
+
372
+ #### 应用管理
373
+ ```typescript
374
+ // 创建应用
375
+ await provider.createApp('MyApp', 'ios');
376
+
377
+ // 列出应用
378
+ await provider.listApps('ios');
379
+
380
+ // 获取当前应用
381
+ const { appId, platform } = await provider.getSelectedApp('ios');
382
+ ```
383
+
384
+ #### 版本管理
385
+ ```typescript
386
+ // 列出版本
387
+ await provider.listVersions('app123');
388
+
389
+ // 更新版本
390
+ await provider.updateVersion('app123', 'version456', {
391
+ name: 'v1.1.0',
392
+ description: 'New features'
393
+ });
394
+ ```
395
+
396
+ #### 工具函数
397
+ ```typescript
398
+ // 获取平台
399
+ const platform = await provider.getPlatform('ios');
400
+
401
+ // 加载会话
402
+ const session = await provider.loadSession();
403
+ ```
404
+
405
+ ### 🎯 使用场景
406
+
407
+ #### 1. 自动化构建脚本
408
+ ```typescript
409
+ import { moduleManager } from 'react-native-update-cli';
410
+
411
+ async function buildAndPublish() {
412
+ const provider = moduleManager.getProvider();
413
+
414
+ // 1. 打包
415
+ const bundleResult = await provider.bundle({
416
+ platform: 'ios',
417
+ dev: false,
418
+ sourcemap: true
419
+ });
420
+
421
+ if (!bundleResult.success) {
422
+ throw new Error(`打包失败: ${bundleResult.error}`);
423
+ }
424
+
425
+ // 2. 发布
426
+ const publishResult = await provider.publish({
427
+ name: 'v1.2.3',
428
+ description: 'Bug fixes and performance improvements',
429
+ rollout: 100
430
+ });
431
+
432
+ if (!publishResult.success) {
433
+ throw new Error(`发布失败: ${publishResult.error}`);
434
+ }
435
+
436
+ console.log('构建和发布完成!');
437
+ }
438
+ ```
439
+
440
+ #### 2. CI/CD集成
441
+ ```typescript
442
+ async function ciBuild() {
443
+ const provider = moduleManager.getProvider();
444
+
445
+ const result = await provider.bundle({
446
+ platform: process.env.PLATFORM as 'ios' | 'android',
447
+ dev: process.env.NODE_ENV !== 'production',
448
+ sourcemap: process.env.NODE_ENV === 'production'
449
+ });
450
+
451
+ return result;
452
+ }
453
+ ```
454
+
455
+ #### 3. 应用管理服务
456
+ ```typescript
457
+ class AppManagementService {
458
+ private provider = moduleManager.getProvider();
459
+
460
+ async setupNewApp(name: string, platform: Platform) {
461
+ // 创建应用
462
+ const createResult = await this.provider.createApp(name, platform);
463
+
464
+ if (createResult.success) {
465
+ // 获取应用信息
466
+ const { appId } = await this.provider.getSelectedApp(platform);
467
+
468
+ // 列出版本
469
+ await this.provider.listVersions(appId);
470
+
471
+ return { appId, success: true };
472
+ }
473
+
474
+ return { success: false, error: createResult.error };
475
+ }
476
+ }
477
+ ```
478
+
479
+ ### ⚠️ 注意事项
480
+
481
+ 1. **错误处理**: 所有Provider方法都返回`CommandResult`,需要检查`success`字段
482
+ 2. **类型安全**: Provider提供完整的TypeScript类型支持
483
+ 3. **会话管理**: 使用前确保已登录,可通过`loadSession()`检查
484
+ 4. **平台支持**: 支持`'ios' | 'android' | 'harmony'`三个平台
485
+
486
+ ### 🔧 高级功能
487
+
488
+ #### 自定义工作流
489
+ ```typescript
490
+ // 注册自定义工作流
491
+ provider.registerWorkflow({
492
+ name: 'quick-release',
493
+ description: '快速发布流程',
494
+ steps: [
495
+ {
496
+ name: 'bundle',
497
+ execute: async () => {
498
+ return await provider.bundle({ platform: 'ios', dev: false });
499
+ }
500
+ },
501
+ {
502
+ name: 'publish',
503
+ execute: async (context, bundleResult) => {
504
+ if (!bundleResult.success) {
505
+ throw new Error('打包失败,无法发布');
506
+ }
507
+ return await provider.publish({ name: 'auto-release', rollout: 50 });
508
+ }
509
+ }
510
+ ]
511
+ });
512
+
513
+ // 执行工作流
514
+ await provider.executeWorkflow('quick-release', { args: [], options: {} });
515
+ ```
516
+
517
+ ### 📚 完整示例
518
+
519
+ ```typescript
520
+ import { moduleManager } from 'react-native-update-cli';
521
+
522
+ class ReactNativeUpdateService {
523
+ private provider = moduleManager.getProvider();
524
+
525
+ async initialize() {
526
+ // 加载会话
527
+ await this.provider.loadSession();
528
+ }
529
+
530
+ async buildAndDeploy(platform: Platform, version: string) {
531
+ try {
532
+ // 1. 打包
533
+ const bundleResult = await this.provider.bundle({
534
+ platform,
535
+ dev: false,
536
+ sourcemap: true
537
+ });
538
+
539
+ if (!bundleResult.success) {
540
+ throw new Error(`打包失败: ${bundleResult.error}`);
541
+ }
542
+
543
+ // 2. 发布
544
+ const publishResult = await this.provider.publish({
545
+ name: version,
546
+ description: `Release ${version}`,
547
+ rollout: 100
548
+ });
549
+
550
+ if (!publishResult.success) {
551
+ throw new Error(`发布失败: ${publishResult.error}`);
552
+ }
553
+
554
+ return { success: true, data: publishResult.data };
555
+
556
+ } catch (error) {
557
+ return {
558
+ success: false,
559
+ error: error instanceof Error ? error.message : 'Unknown error'
560
+ };
561
+ }
562
+ }
563
+
564
+ async getAppInfo(platform: Platform) {
565
+ const { appId } = await this.provider.getSelectedApp(platform);
566
+ const versions = await this.provider.listVersions(appId);
567
+
568
+ return { appId, versions };
569
+ }
570
+ }
571
+
572
+ // 使用示例
573
+ const service = new ReactNativeUpdateService();
574
+ await service.initialize();
575
+ await service.buildAndDeploy('ios', 'v1.0.0');
576
+ ```
package/cli.json CHANGED
@@ -294,6 +294,24 @@
294
294
  "hasValue": true
295
295
  }
296
296
  }
297
+ },
298
+ "list": {
299
+ "description": "List all bundles",
300
+ "options": {
301
+ "output": {
302
+ "default": "${tempDir}/output/list",
303
+ "hasValue": true
304
+ }
305
+ }
306
+ },
307
+ "workflow": {
308
+ "description": "List all workflows",
309
+ "options": {
310
+ "output": {
311
+ "default": "${tempDir}/output/workflow",
312
+ "hasValue": true
313
+ }
314
+ }
297
315
  }
298
316
  },
299
317
  "globalOptions": {
package/lib/api.js CHANGED
@@ -43,16 +43,16 @@ _export(exports, {
43
43
  return uploadFile;
44
44
  }
45
45
  });
46
- const _nodefetch = /*#__PURE__*/ _interop_require_default(require("node-fetch"));
47
46
  const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
48
- const _util = /*#__PURE__*/ _interop_require_default(require("util"));
49
47
  const _path = /*#__PURE__*/ _interop_require_default(require("path"));
48
+ const _util = /*#__PURE__*/ _interop_require_default(require("util"));
49
+ const _filesizeparser = /*#__PURE__*/ _interop_require_default(require("filesize-parser"));
50
+ const _formdata = /*#__PURE__*/ _interop_require_default(require("form-data"));
51
+ const _nodefetch = /*#__PURE__*/ _interop_require_default(require("node-fetch"));
50
52
  const _progress = /*#__PURE__*/ _interop_require_default(require("progress"));
51
- const _packagejson = /*#__PURE__*/ _interop_require_default(require("../package.json"));
52
53
  const _tcpping = /*#__PURE__*/ _interop_require_default(require("tcp-ping"));
53
- const _filesizeparser = /*#__PURE__*/ _interop_require_default(require("filesize-parser"));
54
+ const _packagejson = /*#__PURE__*/ _interop_require_default(require("../package.json"));
54
55
  const _constants = require("./utils/constants");
55
- const _formdata = /*#__PURE__*/ _interop_require_default(require("form-data"));
56
56
  const _i18n = require("./utils/i18n");
57
57
  function _interop_require_default(obj) {
58
58
  return obj && obj.__esModule ? obj : {
package/lib/app.js CHANGED
@@ -28,9 +28,9 @@ _export(exports, {
28
28
  return listApp;
29
29
  }
30
30
  });
31
- const _utils = require("./utils");
32
31
  const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
33
32
  const _ttytable = /*#__PURE__*/ _interop_require_default(require("tty-table"));
33
+ const _utils = require("./utils");
34
34
  const _api = require("./api");
35
35
  const _i18n = require("./utils/i18n");
36
36
  function _interop_require_default(obj) {