rn-update-cli 1.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 (117) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +167 -0
  3. package/README.zh-CN.md +167 -0
  4. package/cli.json +525 -0
  5. package/lib/api.d.ts +56 -0
  6. package/lib/api.js +671 -0
  7. package/lib/app.d.ts +107 -0
  8. package/lib/app.js +329 -0
  9. package/lib/auto-update.d.ts +35 -0
  10. package/lib/auto-update.js +507 -0
  11. package/lib/bin.d.ts +2 -0
  12. package/lib/bin.js +133 -0
  13. package/lib/bundle-pack.d.ts +6 -0
  14. package/lib/bundle-pack.js +91 -0
  15. package/lib/bundle-runner.d.ts +168 -0
  16. package/lib/bundle-runner.js +1305 -0
  17. package/lib/bundle.d.ts +45 -0
  18. package/lib/bundle.js +226 -0
  19. package/lib/cache.d.ts +10 -0
  20. package/lib/cache.js +25 -0
  21. package/lib/commands.d.ts +11 -0
  22. package/lib/commands.js +72 -0
  23. package/lib/diff.d.ts +18 -0
  24. package/lib/diff.js +690 -0
  25. package/lib/exports.d.ts +11 -0
  26. package/lib/exports.js +20 -0
  27. package/lib/install.d.ts +9 -0
  28. package/lib/install.js +51 -0
  29. package/lib/locales/en.d.ts +187 -0
  30. package/lib/locales/en.js +194 -0
  31. package/lib/locales/zh.d.ts +187 -0
  32. package/lib/locales/zh.js +194 -0
  33. package/lib/native-package.d.ts +21 -0
  34. package/lib/native-package.js +298 -0
  35. package/lib/package.d.ts +68 -0
  36. package/lib/package.js +487 -0
  37. package/lib/provider.d.ts +24 -0
  38. package/lib/provider.js +244 -0
  39. package/lib/standalone-publish.d.ts +17 -0
  40. package/lib/standalone-publish.js +433 -0
  41. package/lib/symbolicate.d.ts +35 -0
  42. package/lib/symbolicate.js +130 -0
  43. package/lib/types.d.ts +152 -0
  44. package/lib/types.js +2 -0
  45. package/lib/user.d.ts +8 -0
  46. package/lib/user.js +50 -0
  47. package/lib/utils/add-gitignore.d.ts +6 -0
  48. package/lib/utils/add-gitignore.js +44 -0
  49. package/lib/utils/app-info-parser/aab.d.ts +27 -0
  50. package/lib/utils/app-info-parser/aab.js +256 -0
  51. package/lib/utils/app-info-parser/apk.d.ts +19 -0
  52. package/lib/utils/app-info-parser/apk.js +95 -0
  53. package/lib/utils/app-info-parser/app.d.ts +9 -0
  54. package/lib/utils/app-info-parser/app.js +15 -0
  55. package/lib/utils/app-info-parser/index.d.ts +21 -0
  56. package/lib/utils/app-info-parser/index.js +51 -0
  57. package/lib/utils/app-info-parser/ipa.d.ts +19 -0
  58. package/lib/utils/app-info-parser/ipa.js +101 -0
  59. package/lib/utils/app-info-parser/resource-finder.d.ts +49 -0
  60. package/lib/utils/app-info-parser/resource-finder.js +429 -0
  61. package/lib/utils/app-info-parser/utils.d.ts +36 -0
  62. package/lib/utils/app-info-parser/utils.js +140 -0
  63. package/lib/utils/app-info-parser/xml-parser/binary.d.ts +61 -0
  64. package/lib/utils/app-info-parser/xml-parser/binary.js +577 -0
  65. package/lib/utils/app-info-parser/xml-parser/manifest.d.ts +15 -0
  66. package/lib/utils/app-info-parser/xml-parser/manifest.js +207 -0
  67. package/lib/utils/app-info-parser/zip.d.ts +29 -0
  68. package/lib/utils/app-info-parser/zip.js +97 -0
  69. package/lib/utils/check-lockfile.d.ts +6 -0
  70. package/lib/utils/check-lockfile.js +93 -0
  71. package/lib/utils/check-plugin.d.ts +12 -0
  72. package/lib/utils/check-plugin.js +36 -0
  73. package/lib/utils/command-result.d.ts +8 -0
  74. package/lib/utils/command-result.js +27 -0
  75. package/lib/utils/constants.d.ts +10 -0
  76. package/lib/utils/constants.js +39 -0
  77. package/lib/utils/dep-versions.d.ts +20 -0
  78. package/lib/utils/dep-versions.js +129 -0
  79. package/lib/utils/git.d.ts +14 -0
  80. package/lib/utils/git.js +64 -0
  81. package/lib/utils/hbcTransform.d.ts +111 -0
  82. package/lib/utils/hbcTransform.js +561 -0
  83. package/lib/utils/hermes-base.d.ts +227 -0
  84. package/lib/utils/hermes-base.js +1287 -0
  85. package/lib/utils/hermes-literals.d.ts +64 -0
  86. package/lib/utils/hermes-literals.js +260 -0
  87. package/lib/utils/http-helper.d.ts +10 -0
  88. package/lib/utils/http-helper.js +150 -0
  89. package/lib/utils/i18n.d.ts +22 -0
  90. package/lib/utils/i18n.js +46 -0
  91. package/lib/utils/index.d.ts +67 -0
  92. package/lib/utils/index.js +545 -0
  93. package/lib/utils/latest-version/index.d.ts +154 -0
  94. package/lib/utils/latest-version/index.js +331 -0
  95. package/lib/utils/options.d.ts +10 -0
  96. package/lib/utils/options.js +68 -0
  97. package/lib/utils/plugin-config.d.ts +14 -0
  98. package/lib/utils/plugin-config.js +66 -0
  99. package/lib/utils/runtime.d.ts +54 -0
  100. package/lib/utils/runtime.js +263 -0
  101. package/lib/utils/slim-sourcemap.d.ts +28 -0
  102. package/lib/utils/slim-sourcemap.js +106 -0
  103. package/lib/utils/zip-entries.d.ts +10 -0
  104. package/lib/utils/zip-entries.js +211 -0
  105. package/lib/utils/zip-options.d.ts +17 -0
  106. package/lib/utils/zip-options.js +190 -0
  107. package/lib/utils/zip-range.d.ts +148 -0
  108. package/lib/utils/zip-range.js +581 -0
  109. package/lib/utils/zip-raw-writer.d.ts +52 -0
  110. package/lib/utils/zip-raw-writer.js +209 -0
  111. package/lib/version-operations.d.ts +21 -0
  112. package/lib/version-operations.js +320 -0
  113. package/lib/versions.d.ts +66 -0
  114. package/lib/versions.js +402 -0
  115. package/package.json +113 -0
  116. package/proto/Configuration.proto +183 -0
  117. package/proto/Resources.proto +569 -0
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * [INPUT]: 依赖 CLI i18n 键与中文产品术语
5
+ * [OUTPUT]: 对外提供 pakta 默认中文文案,含渠道自动创建、原生版本组重复与 JS 冲突提示
6
+ * [POS]: locales 中文资源事实源,只表达交互语义,不参与上传裁决
7
+ */
8
+ exports.default = {
9
+ addedToGitignore: '已将 {{line}} 添加到 .gitignore',
10
+ androidCrunchPngsWarning: 'android 的 crunchPngs 选项似乎尚未禁用(如已禁用则请忽略此提示),这可能导致热更包体积异常增大,具体请参考 https://pakta.reactnative.cn/docs/getting-started.html#%E7%A6%81%E7%94%A8-android-%E7%9A%84-crunch-%E4%BC%98%E5%8C%96 \n',
11
+ aabOpenApksFailed: '无法打开生成的 .apks 文件',
12
+ aabReadUniversalApkFailed: '无法读取 universal.apk',
13
+ aabUniversalApkNotFound: '在生成的 .apks 中未找到 universal.apk',
14
+ aabBundletoolDownloadHint: '未找到 bundletool,正在通过 npx 下载 node-bundletool(首次下载可能需要一些时间)。',
15
+ aabManifestNotFound: '在 AAB 的 base/manifest/ 中找不到 AndroidManifest.xml',
16
+ aabParseResourcesWarning: '[警告] 解析 resources.arsc 失败:{{error}}',
17
+ aabParseFailed: '解析 AAB 失败:{{error}}',
18
+ aabParseManifestError: '解析 AndroidManifest.xml 出错:{{error}}',
19
+ aabParseResourcesError: '解析 resources.arsc 出错:{{error}}',
20
+ appId: '应用 id',
21
+ appIdMismatchApk: 'appId不匹配!当前apk: {{appIdInPkg}}, 当前{{- source}}: {{appId}}',
22
+ appIdMismatchApp: 'appId不匹配!当前app: {{appIdInPkg}}, 当前{{- source}}: {{appId}}',
23
+ appIdMismatchIpa: 'appId不匹配!当前ipa: {{appIdInPkg}}, 当前{{- source}}: {{appId}}',
24
+ appKeyMismatchApk: 'appKey不匹配!当前apk: {{appKeyInPkg}}, 当前{{- source}}: {{appKey}}',
25
+ appKeyMismatchApp: 'appKey不匹配!当前app: {{appKeyInPkg}}, 当前{{- source}}: {{appKey}}',
26
+ appKeyMismatchIpa: 'appKey不匹配!当前ipa: {{appKeyInPkg}}, 当前{{- source}}: {{appKey}}',
27
+ appName: '应用名称',
28
+ appNameQuestion: '应用名称:',
29
+ appPlatformMismatch: '应用 {{appId}} 是 {{appPlatform}} 平台的应用,但当前命令的平台是 {{platform}}',
30
+ appNotSelected: '尚未选择应用。请先运行 `pakta selectApp --platform {{platform}}` 来选择应用',
31
+ appUploadSuccess: '已成功上传app原生包(id: {{id}}, version: {{version}}, buildTime: {{buildTime}})',
32
+ autoUpdatePermission: 'CLI 自动更新已跳过:全局包目录不可写。请修复包管理器的全局目录权限后运行:{{- command}}',
33
+ autoUpdateSuccess: 'CLI 已在后台自动更新:{{from}} -> {{to}}',
34
+ apkUploadSuccess: '已成功上传apk原生包(id: {{id}}, version: {{version}}, buildTime: {{buildTime}})',
35
+ boundTo: ', 已绑定:{{name}} ({{id}})',
36
+ buildTimeNotFound: '无法获取此包的编译时间戳。请更新 `rn-update` 到最新版本后重新打包上传。',
37
+ bundleCommandError: '"react-native bundle" 命令退出,代码为 {{code}}。',
38
+ bundleNotFound: '找不到 bundle 文件。请确保此 {{packageType}} 为 release 版本,且 bundle 文件名为默认的 `{{entryFile}}`',
39
+ bundlingWithRN: '正在使用 react-native {{version}} 打包',
40
+ cancelled: '已取消',
41
+ composingSourceMap: '正在生成 source map',
42
+ copyingDebugId: '正在复制 debugid',
43
+ createAppSuccess: '已成功创建应用(id: {{id}})',
44
+ channelAutoCreated: '渠道 {{channel}} 不存在,已自动创建',
45
+ deleteFile: '删除 {{- file}}',
46
+ enterAppIdQuestion: '输入应用 id:',
47
+ enterNativePackageId: '输入原生包 id:',
48
+ expiredStatus: '(已过期)',
49
+ failedToParseUpdateJson: '无法解析文件 `{{- configPath}}`。请手动删除它。',
50
+ fileGenerated: '已生成 {{- file}}',
51
+ fileSizeExceeded: '此文件大小 {{fileSize}} , 超出当前额度 {{maxSize}} 。您可以考虑升级付费业务以提升此额度。详情请访问: {{- pricingPageUrl}}',
52
+ forceHermes: '强制启用 Hermes 编译',
53
+ hermesEnabledCompiling: 'Hermes 已启用,正在编译为 hermes 字节码:\n',
54
+ ipaUploadSuccess: '已成功上传ipa原生包(id: {{id}}, version: {{version}}, buildTime: {{buildTime}})',
55
+ latestVersionTag: '(最新:{{version}})',
56
+ lockBestPractice: `
57
+ 关于 lock 文件的最佳实践:
58
+ 1. 开发团队中的所有成员应该使用相同的包管理器,维护同一份 lock 文件。
59
+ 2. 将 lock 文件添加到版本控制中(但不要同时提交多种不同格式的 lock 文件)。
60
+ 3. 代码审核时应关注 lock 文件的变化。
61
+ 这样可以最大限度避免因依赖关系不一致而导致的热更异常,也降低供应链攻击等安全隐患。
62
+ `,
63
+ lockNotFound: '没有检测到任何 lock 文件,这可能导致依赖关系不一致而使热更异常。',
64
+ loggedOut: '已退出登录',
65
+ loginExpired: '登录信息已过期,请使用 `pakta login` 命令重新登录',
66
+ loginFirst: '尚未登录。\n请在项目目录中运行`pakta login`命令来登录',
67
+ multipleLocksFound: '检测到多种不同格式的锁文件({{- lockFiles}}),这可能导致依赖关系不一致而使热更异常。',
68
+ nativePackageId: '原生包 Id',
69
+ nativeVersion: '原生版本',
70
+ nativeVersionNotFoundGte: '未查询到 >= {{version}} 的原生版本',
71
+ nativeVersionNotFoundLte: '未查询到 <= {{version}} 的原生版本',
72
+ nativeVersionNotFoundBetween: '未查询到 {{min}} 至 {{max}} 之间的原生版本',
73
+ conflictingPackageSelectors: 'packageId / packageVersion / packageVersionRange / minPackageVersion+maxPackageVersion 只能使用其中一组,不能混用',
74
+ nativeVersionNotFoundMatch: '未查询到匹配原生版本:{{version}}',
75
+ nativeVersionAlreadyRegistered: '原生包 {{version}} 已登记且内嵌 JS 内容一致,无需重复上传(id: {{id}})',
76
+ nativeVersionBundleConflict: '原生包 {{version}} 已登记但内嵌 JS 内容不同。请提升原生版本号后再上传,否则该版本的增量更新判定会失准',
77
+ nativePackageIdNotFound: '未查询到原生包 id: {{id}}',
78
+ noPackagesFound: '未查询到任何原生包(appId: {{appId}})',
79
+ offset: '偏移量 {{offset}}',
80
+ operationComplete: '操作完成,共已绑定 {{count}} 个原生版本',
81
+ operationSuccess: '操作成功',
82
+ packageIdRequired: '请提供 packageId 或 packageVersion 参数',
83
+ standaloneTargetRequired: '独立服务非交互发布必须提供 --targets、--packageId 或 --packageVersion。',
84
+ packageUploadSuccess: '已成功上传新热更包(id: {{id}})',
85
+ depsChangeWarningTitle: '检测到依赖变化',
86
+ depsChangeSummary: '依赖变化:新增 {{added}} 项,移除 {{removed}} 项,版本变更 {{changed}} 项。',
87
+ depsChangeTargetPackage: '目标原生包:{{packageName}} (id: {{packageId}})',
88
+ depsChangeDependencyHeader: '依赖',
89
+ depsChangeVersionHeader: '版本变化',
90
+ depsChangeAddedLabel: '新增',
91
+ depsChangeRemovedLabel: '移除',
92
+ depsChangeChangedLabel: '变更',
93
+ depsChangeArrow: '->',
94
+ depsChangeRiskWarning: '警告:如果变更依赖是纯 JS 模块,则一般没有影响;若包含原生代码新增或变化,热更可能导致功能不正常甚至闪退,建议发布前使用扫码功能完整测试。',
95
+ depsChangeFetchFailed: '获取热更依赖信息失败:{{error}}',
96
+ depsChangeNonBlockingHint: '以上仅为依赖变化提示,不会阻止本次发布。',
97
+ packing: '正在打包',
98
+ pausedStatus: '(已暂停)',
99
+ platform: '平台',
100
+ platformQuestion: '平台(ios/android/harmony):',
101
+ pluginDetectionError: '检测 {{name}} 插件时出错:{{error}}',
102
+ pluginDetected: '检测到 {{name}} 插件',
103
+ sourceMapNotFound: '找不到 source map:{{path}}',
104
+ sourceMapMissingWarning: '本版本没有归档 source map,之后的崩溃堆栈将无法还原。请用默认的 --sourcemap 打包,或在 publish 时传 --sourcemap <文件>。',
105
+ sourceMapArchived: 'source map 已随版本 {{id}} 归档',
106
+ sourceMapAlreadyArchivedWarning: '此热更 hash 已经登记,本次新的 source map 未附加到已有包。',
107
+ sourceMapUploadFailedWarning: 'source map 上传失败({{error}}),本次发布不归档 map。升级更新服务端后可归档 source map。',
108
+ symbolicateUsage: '用法:pakta symbolicate <堆栈文件 | -> --hash <热更 hash> [--platform ios|android|harmony] [--output <文件>]',
109
+ symbolicateVersionNotFound: '当前应用下找不到 hash 为 {{hash}} 的已发布版本',
110
+ symbolicateNoSourceMap: '版本 {{id}} 发布时未归档 source map,无法还原',
111
+ symbolicateDone: '已按版本 {{id}}({{hash}})还原 {{count}} 个堆栈帧',
112
+ publishUsage: '使用方法: pakta publish ppk后缀文件 --platform ios|android|harmony',
113
+ rnuVersionNotFound: 'rn-update: 无法获取版本号。请在项目目录中运行命令',
114
+ rolloutConfigSet: '已在原生版本 {{versions}} 上设置灰度发布 {{rollout}}% 热更包 {{version}}',
115
+ rolloutRangeError: 'rollout 必须是 1-100 的整数',
116
+ runningHermesc: '运行 hermesc:{{- command}} {{- args}}',
117
+ hermesSourcemapKept: '字节码已剥离 debug info(与 RN release 构建一致);Hermes sourcemap 保留在 {{- file}},可用于事后符号化崩溃堆栈。',
118
+ sentryReactNativeNotFound: '无法找到 @sentry/react-native,请确保已正确安装',
119
+ sentryCliNotFound: '无法找到 Sentry CLI 工具,请确保已正确安装 @sentry/cli',
120
+ sentryReleaseCreated: '已为版本 {{version}} 创建 Sentry release',
121
+ totalApps: '共 {{count}} 个 {{platform}} 应用',
122
+ totalPackages: '共 {{count}} 个包',
123
+ unsupportedPlatform: '无法识别的平台 `{{platform}}`',
124
+ uploadBundlePrompt: '是否现在上传此热更包?(Y/N)',
125
+ uploadingSourcemap: '正在上传 sourcemap',
126
+ usageDiff: '用法:pakta {{command}} <origin> <next>',
127
+ usageParseApk: '使用方法: pakta parseApk apk后缀文件',
128
+ usageParseAab: '使用方法: pakta parseAab aab后缀文件',
129
+ usageExtractApk: '使用方法: pakta extractApk aab后缀文件 [--output apk文件] [--includeAllSplits] [--splits 分包名列表]',
130
+ usageParseApp: '使用方法: pakta parseApp app后缀文件',
131
+ usageParseIpa: '使用方法: pakta parseIpa ipa后缀文件',
132
+ usageUploadApk: '使用方法: pakta uploadApk apk后缀文件',
133
+ usageUploadAab: '使用方法: pakta uploadAab aab后缀文件 [--includeAllSplits] [--splits 分包名列表]',
134
+ usageUploadApp: '使用方法: pakta uploadApp app后缀文件',
135
+ usageUploadIpa: '使用方法: pakta uploadIpa ipa后缀文件',
136
+ versionBind: '已将热更包 {{version}} 绑定到原生版本 {{nativeVersion}} (id: {{id}})',
137
+ versionIdRequired: '非交互模式下请提供 versionId。',
138
+ welcomeMessage: '欢迎使用 pakta 热更新服务,{{name}}。',
139
+ versionNameQuestion: '输入版本名称:',
140
+ versionDescriptionQuestion: '输入版本描述:',
141
+ versionMetaInfoQuestion: '输入自定义的 meta info:',
142
+ updateNativePackageQuestion: '是否现在将此热更应用到原生包上?(Y/N)',
143
+ unnamed: '(未命名)',
144
+ dryRun: '以下是 dry-run 模拟运行结果,不会实际执行任何操作:',
145
+ usingCustomVersion: '使用自定义版本:{{version}}',
146
+ confirmDeletePackage: '确认删除原生包 {{packageId}}? 此操作不可撤销 (Y/N):',
147
+ deletePackageSuccess: '原生包 {{packageId}} 删除成功',
148
+ deletePackagesSuccess: '已删除 {{count}} 个原生包:{{packageIds}}',
149
+ deletePackageError: '删除原生包 {{packageId}} 失败: {{error}}',
150
+ usageDeletePackage: '使用方法: pakta deletePackage [packageId] --packageIds [packageIds] --appId [appId]',
151
+ deleteVersionSuccess: '热更包 {{versionId}} 删除成功',
152
+ deleteVersionsSuccess: '已删除 {{count}} 个热更包:{{versionIds}}',
153
+ deleteVersionError: '删除热更包 {{versionId}} 失败: {{error}}',
154
+ bundleFileNotFound: '未找到 bundle 文件!请使用默认的 bundle 文件名和路径。',
155
+ diffPackageGenerated: '{{- output}} 已生成。',
156
+ nodeHdiffpatchRequired: '此功能需要 "node-hdiffpatch"。请运行 "{{scriptName}} install node-hdiffpatch" 来安装',
157
+ hbcTransformRoundTripFailed: 'HBC 变换 round-trip 自检未通过,已回退普通 diff。',
158
+ hbcTransformNeedsPatch: 'hbcTransform 需要 node-hdiffpatch 的 patch 能力,选项已忽略。',
159
+ bundleStreamNeedsHdiffpatch: 'bundleStreamThreshold 需要 node-hdiffpatch 的 diffStream/patchStream 能力,选项已忽略。',
160
+ apkExtracted: 'APK 已提取到 {{output}}',
161
+ composeSourceMapsNotFound: '找不到 react-native/scripts/compose-source-maps.js,跳过 hermes sourcemap 合成。上传的 sourcemap 可能与编译后的 bundle 不匹配。',
162
+ installPackageRequired: '请指定要安装的包,例如 "{{scriptName}} install node-hdiffpatch"',
163
+ installFailed: '安装 {{packages}} 失败: {{error}}',
164
+ proxyNetworkError: '网络连接异常,可能是代理/VPN 导致。请尝试关闭代理后重试。',
165
+ proxyNetworkErrorTips: '常见解决方法:\n1. 关闭系统代理或 VPN\n2. 检查 HTTP_PROXY / HTTPS_PROXY 环境变量\n3. 检查 .npmrc 中的 proxy 配置',
166
+ invalidId: '无效的 id:{{id}}',
167
+ outputPathRequired: '必须指定输出路径。',
168
+ unsupportedFileType: '不支持的文件类型:{{fileType}}',
169
+ failedToLoadSession: '加载登录状态失败',
170
+ appIdRequired: '必须指定 appId',
171
+ unknownCommand: '未知命令:{{command}}',
172
+ unsupportedPlatformForHermes: 'Hermes 不支持当前系统平台:{{platform}}',
173
+ invalidManifest: '无效的 manifest',
174
+ failedToResolveResource: '资源解析失败:{{error}}',
175
+ hermesBaseNone: 'Hermes base:未使用({{- reason}}),按普通方式编译',
176
+ hermesBaseUsing: 'Hermes base:{{- source}}(HBC v{{version}})',
177
+ hermesBaseDownloading: 'Hermes base:下载 {{- url}}',
178
+ hermesBaseRangeFetched: 'Hermes base:已通过 HTTP Range 仅下载 bundle({{fetchedKb}} KB / 整包 {{totalKb}} KB)',
179
+ hermesBaseRangeFallback: 'Hermes base:无法按需下载({{- reason}}),改为下载整包',
180
+ hermesBaseCompileFailed: 'Hermes base 编译失败({{- reason}}),改为不带 -base-bytecode 重编',
181
+ hermesBaseCompileFailedLog: 'Hermes base:完整编译错误已写入 {{- file}}',
182
+ hermesBasePlainCompileFailed: 'Hermes base:用于校验的普通编译失败({{- reason}}),放弃 base,不带 base 重新编译',
183
+ hermesBaseVerified: 'Hermes base:字节码与普通编译等价,校验通过({{functions}} 个函数)',
184
+ hermesBaseVerifyFailed: 'Hermes base:字节码与普通编译不等价({{- detail}}),放弃 base',
185
+ hermesBaseVerifyDumpFailed: 'Hermes base:无法比对字节码({{- detail}}),放弃 base',
186
+ hermesBaseVerifyDumpsWritten: 'Hermes base:两份反汇编已写入 {{- withBase}} 与 {{- plain}}',
187
+ cacheCleaned: '已清理 {{count}} 个缓存 bundle',
188
+ cacheStats: 'bundle 缓存:{{- dir}} — {{files}} 个文件,{{mb}} MB',
189
+ loginCredentialsRequired: '需要提供邮箱和密码。用法:{{scriptName}} login <邮箱> <密码>',
190
+ bundleUnexpectedArgs: 'bundle 不接受位置参数,收到:{{- args}}。布尔选项不带值,关闭请使用 --no-<选项>(例如 --no-sourcemap)。',
191
+ unsafeIntermediateDir: '拒绝清空中间目录 {{- dir}}:该路径指向受保护目录或包含符号链接。请用 --intermediaDir 指定一个专用的构建目录。',
192
+ appKeyMissing: '应用 {{appId}} 未返回有效的 appKey。',
193
+ errorStackHint: '(设置 RNU_DEBUG=1 可打印完整堆栈)',
194
+ };
@@ -0,0 +1,21 @@
1
+ import type { Platform } from './types';
2
+ export type NativePackageEntry = {
3
+ diffPath: string;
4
+ kind: 'bundle' | 'resource';
5
+ };
6
+ /**
7
+ * Resolve an archive entry that can be used as a native-package diff origin.
8
+ * Upload extraction and diff indexing deliberately share this function so a
9
+ * file cannot be removed from the uploaded baseline while still being
10
+ * considered by the local diff implementation (or vice versa).
11
+ */
12
+ export declare function resolveNativePackageEntry(platform: Platform, entryName: string): NativePackageEntry | undefined;
13
+ export interface SlimPackageOptions {
14
+ /** re-deflate through yazl even when a raw copy would do (tests) */
15
+ repack?: boolean;
16
+ }
17
+ /**
18
+ * Repack a native package with only the bundle and resources required by
19
+ * package-origin diffs. Entry names and nested Harmony HAP structure are kept.
20
+ */
21
+ export declare function createSlimNativePackage(source: string, output: string, platform: Platform, options?: SlimPackageOptions): Promise<void>;
@@ -0,0 +1,298 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.resolveNativePackageEntry = resolveNativePackageEntry;
40
+ exports.createSlimNativePackage = createSlimNativePackage;
41
+ /**
42
+ * [INPUT]: 依赖 APK/IPA/Harmony 原生归档、平台保留规则与底层 ZIP 写入器
43
+ * [OUTPUT]: 对外提供原生包差分条目解析及上传前的精简归档生成
44
+ * [POS]: CLI 原生制品预处理层,只保留热更新基线所需的 JS bundle 与资源,供 package 登记和 pdiff 使用
45
+ */
46
+ const fs = __importStar(require("fs-extra"));
47
+ const os_1 = __importDefault(require("os"));
48
+ const path_1 = __importDefault(require("path"));
49
+ const yauzl_1 = require("yauzl");
50
+ const yazl_1 = require("yazl");
51
+ const zip_raw_writer_1 = require("./utils/zip-raw-writer");
52
+ const nativePackageRules = {
53
+ android: {
54
+ resolveEntry: (entryName) => {
55
+ if (entryName === 'assets/index.android.bundle') {
56
+ return { diffPath: entryName, kind: 'bundle' };
57
+ }
58
+ if (entryName.startsWith('assets/') || entryName.startsWith('res/')) {
59
+ return { diffPath: entryName, kind: 'resource' };
60
+ }
61
+ },
62
+ },
63
+ ios: {
64
+ resolveEntry: (entryName) => {
65
+ const match = /^Payload\/[^/]+\.app\/(.+)$/.exec(entryName);
66
+ const appPath = match?.[1];
67
+ if (appPath === 'main.jsbundle') {
68
+ return { diffPath: appPath, kind: 'bundle' };
69
+ }
70
+ if (appPath?.startsWith('assets/')) {
71
+ return { diffPath: appPath, kind: 'resource' };
72
+ }
73
+ },
74
+ },
75
+ harmony: {
76
+ resolveEntry: (entryName) => {
77
+ if (entryName === 'resources/rawfile/bundle.harmony.js') {
78
+ return { diffPath: entryName, kind: 'bundle' };
79
+ }
80
+ if (entryName.startsWith('resources/rawfile/assets/')) {
81
+ return { diffPath: entryName, kind: 'resource' };
82
+ }
83
+ },
84
+ },
85
+ };
86
+ /**
87
+ * Resolve an archive entry that can be used as a native-package diff origin.
88
+ * Upload extraction and diff indexing deliberately share this function so a
89
+ * file cannot be removed from the uploaded baseline while still being
90
+ * considered by the local diff implementation (or vice versa).
91
+ */
92
+ function resolveNativePackageEntry(platform, entryName) {
93
+ return nativePackageRules[platform].resolveEntry(entryName);
94
+ }
95
+ /**
96
+ * Copies each entry's stored bytes, CRC and sizes verbatim (yauzl hands out
97
+ * the raw file data with `decodeFileData: false`), so slimming a package is
98
+ * bound by disk I/O rather than by deflating every asset again.
99
+ */
100
+ class RawCopySink {
101
+ writer;
102
+ constructor(output) {
103
+ this.writer = new zip_raw_writer_1.RawZipWriter(output);
104
+ }
105
+ copyEntry(sourceZip, entry) {
106
+ return new Promise((resolve, reject) => {
107
+ sourceZip.openReadStream(entry, { decodeFileData: false }, (error, readStream) => {
108
+ if (error || !readStream) {
109
+ reject(error ?? new Error(`Unable to read zip entry: ${entry.fileName}`));
110
+ return;
111
+ }
112
+ this.writer.addRawEntry(entry, readStream).then(resolve, reject);
113
+ });
114
+ });
115
+ }
116
+ addFile(filePath, fileName, like) {
117
+ // a nested slim archive is a zip of deflated entries: storing it as-is
118
+ // loses nothing and skips another pass over its bytes
119
+ return this.writer.addStoredFile(filePath, fileName, like);
120
+ }
121
+ end() {
122
+ return this.writer.end();
123
+ }
124
+ abort() {
125
+ return this.writer.abort();
126
+ }
127
+ }
128
+ /** Re-deflates every kept entry through yazl; only for sources that need zip64. */
129
+ class RepackSink {
130
+ output;
131
+ outputZip = new yazl_1.ZipFile();
132
+ writePromise;
133
+ constructor(output) {
134
+ this.output = output;
135
+ this.writePromise = new Promise((resolve, reject) => {
136
+ this.outputZip.outputStream.once('error', reject);
137
+ this.outputZip.outputStream
138
+ .pipe(fs.createWriteStream(output))
139
+ .once('error', reject)
140
+ .once('close', () => resolve());
141
+ });
142
+ }
143
+ copyEntry(sourceZip, entry) {
144
+ return new Promise((resolve, reject) => {
145
+ sourceZip.openReadStream(entry, (error, readStream) => {
146
+ if (error || !readStream) {
147
+ reject(error ?? new Error(`Unable to read zip entry: ${entry.fileName}`));
148
+ return;
149
+ }
150
+ readStream.once('error', reject);
151
+ readStream.once('end', () => resolve());
152
+ this.outputZip.addReadStream(readStream, entry.fileName, {
153
+ compress: entry.compressionMethod !== 0,
154
+ mtime: entry.getLastModDate(),
155
+ });
156
+ });
157
+ });
158
+ }
159
+ async addFile(filePath, fileName, like) {
160
+ this.outputZip.addFile(filePath, fileName, {
161
+ compress: like.compressionMethod !== 0,
162
+ mtime: like.getLastModDate(),
163
+ });
164
+ }
165
+ async end() {
166
+ this.outputZip.end();
167
+ await this.writePromise;
168
+ }
169
+ async abort() {
170
+ this.outputZip.end();
171
+ await this.writePromise.catch(() => { });
172
+ await fs.remove(this.output).catch(() => { });
173
+ }
174
+ }
175
+ function openZip(source) {
176
+ return new Promise((resolve, reject) => {
177
+ (0, yauzl_1.open)(source, { lazyEntries: true }, (error, zipFile) => {
178
+ if (error || !zipFile) {
179
+ reject(error ?? new Error(`Unable to open zip file: ${source}`));
180
+ return;
181
+ }
182
+ resolve(zipFile);
183
+ });
184
+ });
185
+ }
186
+ function extractEntryToFile(sourceZip, entry, outputPath) {
187
+ return new Promise((resolve, reject) => {
188
+ sourceZip.openReadStream(entry, (error, readStream) => {
189
+ if (error) {
190
+ reject(error);
191
+ return;
192
+ }
193
+ if (!readStream) {
194
+ reject(new Error(`Unable to read zip entry: ${entry.fileName}`));
195
+ return;
196
+ }
197
+ const writeStream = fs.createWriteStream(outputPath);
198
+ readStream.once('error', reject);
199
+ writeStream.once('error', reject);
200
+ writeStream.once('close', () => resolve());
201
+ readStream.pipe(writeStream);
202
+ });
203
+ });
204
+ }
205
+ async function filterNativePackageArchive(source, output, platform, options) {
206
+ await fs.ensureDir(path_1.default.dirname(output));
207
+ const scratchDir = await fs.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'rnu-native-package-entry-'));
208
+ const sourceZip = await openZip(source);
209
+ // a subset of the source never outgrows it, so the source's own size and
210
+ // entry count decide whether plain (non-zip64) headers are enough
211
+ const rawCopy = !options.repack &&
212
+ (0, zip_raw_writer_1.fitsRawZip)((await fs.stat(source)).size, sourceZip.entryCount);
213
+ const sink = rawCopy
214
+ ? new RawCopySink(output)
215
+ : new RepackSink(output);
216
+ let includedEntries = 0;
217
+ let includedBundles = 0;
218
+ let nestedArchiveIndex = 0;
219
+ try {
220
+ await new Promise((resolve, reject) => {
221
+ let settled = false;
222
+ const fail = (error) => {
223
+ if (settled) {
224
+ return;
225
+ }
226
+ settled = true;
227
+ sourceZip.close();
228
+ reject(error);
229
+ };
230
+ sourceZip.once('error', fail);
231
+ sourceZip.once('end', () => {
232
+ if (!settled) {
233
+ settled = true;
234
+ resolve();
235
+ }
236
+ });
237
+ sourceZip.on('entry', async (entry) => {
238
+ try {
239
+ if (entry.fileName.endsWith('/')) {
240
+ sourceZip.readEntry();
241
+ return;
242
+ }
243
+ // Harmony .app packages contain one or more nested .hap archives.
244
+ // Rebuild those archives recursively and keep their outer path so
245
+ // the slim package has the same nesting as the original package.
246
+ if (platform === 'harmony' &&
247
+ entry.fileName.toLowerCase().endsWith('.hap')) {
248
+ const index = nestedArchiveIndex++;
249
+ const nestedSource = path_1.default.join(scratchDir, `${index}.source.hap`);
250
+ const nestedOutput = path_1.default.join(scratchDir, `${index}.slim.hap`);
251
+ await extractEntryToFile(sourceZip, entry, nestedSource);
252
+ const nestedResult = await filterNativePackageArchive(nestedSource, nestedOutput, platform, options);
253
+ if (nestedResult.entries > 0) {
254
+ await sink.addFile(nestedOutput, entry.fileName, entry);
255
+ includedEntries += nestedResult.entries;
256
+ includedBundles += nestedResult.bundles;
257
+ }
258
+ sourceZip.readEntry();
259
+ return;
260
+ }
261
+ const resolvedEntry = resolveNativePackageEntry(platform, entry.fileName);
262
+ if (resolvedEntry) {
263
+ await sink.copyEntry(sourceZip, entry);
264
+ includedEntries += 1;
265
+ if (resolvedEntry.kind === 'bundle') {
266
+ includedBundles += 1;
267
+ }
268
+ }
269
+ sourceZip.readEntry();
270
+ }
271
+ catch (error) {
272
+ fail(error);
273
+ }
274
+ });
275
+ sourceZip.readEntry();
276
+ });
277
+ await sink.end();
278
+ return { bundles: includedBundles, entries: includedEntries };
279
+ }
280
+ catch (error) {
281
+ await sink.abort();
282
+ throw error;
283
+ }
284
+ finally {
285
+ await fs.remove(scratchDir);
286
+ }
287
+ }
288
+ /**
289
+ * Repack a native package with only the bundle and resources required by
290
+ * package-origin diffs. Entry names and nested Harmony HAP structure are kept.
291
+ */
292
+ async function createSlimNativePackage(source, output, platform, options = {}) {
293
+ const result = await filterNativePackageArchive(source, output, platform, options);
294
+ if (result.bundles === 0) {
295
+ await fs.remove(output);
296
+ throw new Error(`Bundle entry not found in native package: ${source}`);
297
+ }
298
+ }
@@ -0,0 +1,68 @@
1
+ import type { Package, Platform } from './types';
2
+ type PackageCommandOptions = Record<string, unknown> & {
3
+ appId?: string;
4
+ appKey?: string;
5
+ config?: string;
6
+ platform?: Platform;
7
+ version?: string;
8
+ packageId?: string;
9
+ packageIds?: string;
10
+ packageVersion?: string;
11
+ /** Assertion only: must equal the immutable channel embedded in the package. */
12
+ channel?: string;
13
+ includeAllSplits?: boolean | string;
14
+ splits?: string;
15
+ output?: string;
16
+ };
17
+ export declare function normalizeUploadBuildTime(value: unknown): string;
18
+ /**
19
+ * Print the app's native packages. Pass `packages` when the caller already
20
+ * fetched them (every page of the list), to skip fetching them again.
21
+ */
22
+ export declare function listPackage(appId: string, packages?: Package[]): Promise<Package[]>;
23
+ export declare function choosePackage(appId: string, packages?: Package[]): Promise<Package>;
24
+ export declare const packageCommands: {
25
+ uploadIpa: ({ args, options, }: {
26
+ args: string[];
27
+ options: PackageCommandOptions;
28
+ }) => Promise<void>;
29
+ uploadApk: ({ args, options, }: {
30
+ args: string[];
31
+ options: PackageCommandOptions;
32
+ }) => Promise<void>;
33
+ uploadAab: ({ args, options, }: {
34
+ args: string[];
35
+ options: PackageCommandOptions;
36
+ }) => Promise<void>;
37
+ uploadApp: ({ args, options, }: {
38
+ args: string[];
39
+ options: PackageCommandOptions;
40
+ }) => Promise<void>;
41
+ parseApp: ({ args }: {
42
+ args: string[];
43
+ }) => Promise<void>;
44
+ parseIpa: ({ args }: {
45
+ args: string[];
46
+ }) => Promise<void>;
47
+ parseApk: ({ args }: {
48
+ args: string[];
49
+ }) => Promise<void>;
50
+ parseAab: ({ args }: {
51
+ args: string[];
52
+ }) => Promise<void>;
53
+ extractApk: ({ args, options, }: {
54
+ args: string[];
55
+ options: PackageCommandOptions;
56
+ }) => Promise<void>;
57
+ packages: ({ options, }: {
58
+ options: {
59
+ platform: Platform;
60
+ appId?: string;
61
+ config?: string;
62
+ };
63
+ }) => Promise<void>;
64
+ deletePackage: ({ options }: {
65
+ options: PackageCommandOptions;
66
+ }) => Promise<void>;
67
+ };
68
+ export {};