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
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { moduleManager } from "./module-manager";
|
|
2
|
+
export { CLIProviderImpl } from "./provider";
|
|
3
|
+
export { builtinModules } from "./modules";
|
|
4
|
+
export { bundleModule } from "./modules/bundle-module";
|
|
5
|
+
export { versionModule } from "./modules/version-module";
|
|
6
|
+
export { appModule } from "./modules/app-module";
|
|
7
|
+
export { userModule } from "./modules/user-module";
|
|
8
|
+
export { packageModule } from "./modules/package-module";
|
|
9
|
+
export { loadSession, getSession } from "./api";
|
|
10
|
+
export { getPlatform, getSelectedApp } from "./app";
|
|
11
|
+
export { question, saveToLocal } from "./utils";
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { loadSession } from "./api";
|
|
3
|
+
import { appCommands } from "./app";
|
|
4
|
+
import { bundleCommands } from "./bundle";
|
|
5
|
+
import { installCommands } from "./install";
|
|
6
|
+
import { moduleManager } from "./module-manager";
|
|
7
|
+
import { builtinModules } from "./modules";
|
|
8
|
+
import { packageCommands } from "./package";
|
|
9
|
+
import { userCommands } from "./user";
|
|
10
|
+
import { printVersionCommand } from "./utils";
|
|
11
|
+
import { t } from "./utils/i18n";
|
|
12
|
+
import { versionCommands } from "./versions";
|
|
13
|
+
function registerBuiltinModules() {
|
|
14
|
+
for (const module of builtinModules){
|
|
15
|
+
try {
|
|
16
|
+
moduleManager.registerModule(module);
|
|
17
|
+
} catch (error) {
|
|
18
|
+
console.error(`Failed to register module ${module.name}:`, error);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function printUsage() {
|
|
23
|
+
console.log('React Native Update CLI');
|
|
24
|
+
console.log('');
|
|
25
|
+
console.log('Traditional commands:');
|
|
26
|
+
const legacyCommands = {
|
|
27
|
+
...userCommands,
|
|
28
|
+
...bundleCommands,
|
|
29
|
+
...appCommands,
|
|
30
|
+
...packageCommands,
|
|
31
|
+
...versionCommands,
|
|
32
|
+
...installCommands
|
|
33
|
+
};
|
|
34
|
+
for (const [name, handler] of Object.entries(legacyCommands)){
|
|
35
|
+
console.log(` ${name}: Legacy command`);
|
|
36
|
+
}
|
|
37
|
+
console.log('');
|
|
38
|
+
console.log('Modular commands:');
|
|
39
|
+
const commands = moduleManager.getRegisteredCommands();
|
|
40
|
+
for (const command of commands){
|
|
41
|
+
console.log(` ${command.name}: ${command.description || 'No description'}`);
|
|
42
|
+
}
|
|
43
|
+
console.log('');
|
|
44
|
+
console.log('Available workflows:');
|
|
45
|
+
const workflows = moduleManager.getRegisteredWorkflows();
|
|
46
|
+
for (const workflow of workflows){
|
|
47
|
+
console.log(` ${workflow.name}: ${workflow.description || 'No description'}`);
|
|
48
|
+
}
|
|
49
|
+
console.log('');
|
|
50
|
+
console.log('Special commands:');
|
|
51
|
+
console.log(' list: List all available commands and workflows');
|
|
52
|
+
console.log(' workflow <name>: Execute a specific workflow');
|
|
53
|
+
console.log(' help: Show this help message');
|
|
54
|
+
console.log('');
|
|
55
|
+
console.log('Visit `https://github.com/reactnativecn/react-native-update` for document.');
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
const legacyCommands = {
|
|
59
|
+
...userCommands,
|
|
60
|
+
...bundleCommands,
|
|
61
|
+
...appCommands,
|
|
62
|
+
...packageCommands,
|
|
63
|
+
...versionCommands,
|
|
64
|
+
...installCommands,
|
|
65
|
+
help: printUsage
|
|
66
|
+
};
|
|
67
|
+
async function run() {
|
|
68
|
+
await printVersionCommand();
|
|
69
|
+
if (process.argv.indexOf('-v') >= 0 || process.argv[2] === 'version') {
|
|
70
|
+
process.exit();
|
|
71
|
+
}
|
|
72
|
+
// Register builtin modules for modular functionality
|
|
73
|
+
registerBuiltinModules();
|
|
74
|
+
const argv = require('cli-arguments').parse(require('../cli.json'));
|
|
75
|
+
global.NO_INTERACTIVE = argv.options['no-interactive'];
|
|
76
|
+
global.USE_ACC_OSS = argv.options.acc;
|
|
77
|
+
const context = {
|
|
78
|
+
args: argv.args || [],
|
|
79
|
+
options: argv.options || {}
|
|
80
|
+
};
|
|
81
|
+
try {
|
|
82
|
+
await loadSession();
|
|
83
|
+
context.session = require('./api').getSession();
|
|
84
|
+
// Handle special modular commands first
|
|
85
|
+
if (argv.command === 'help') {
|
|
86
|
+
printUsage();
|
|
87
|
+
} else if (argv.command === 'list') {
|
|
88
|
+
moduleManager.listAll();
|
|
89
|
+
} else if (argv.command === 'workflow') {
|
|
90
|
+
const workflowName = argv.args[0];
|
|
91
|
+
if (!workflowName) {
|
|
92
|
+
console.error('Workflow name is required');
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
const result = await moduleManager.executeWorkflow(workflowName, context);
|
|
96
|
+
if (!result.success) {
|
|
97
|
+
console.error('Workflow execution failed:', result.error);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
console.log('Workflow completed successfully:', result.data);
|
|
101
|
+
} else if (legacyCommands[argv.command]) {
|
|
102
|
+
await legacyCommands[argv.command](argv);
|
|
103
|
+
} else {
|
|
104
|
+
const result = await moduleManager.executeCommand(argv.command, context);
|
|
105
|
+
if (!result.success) {
|
|
106
|
+
console.error('Command execution failed:', result.error);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
console.log('Command completed successfully:', result.data);
|
|
110
|
+
}
|
|
111
|
+
} catch (err) {
|
|
112
|
+
if (err.status === 401) {
|
|
113
|
+
console.log(t('loginFirst'));
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
console.error(err.stack);
|
|
117
|
+
process.exit(-1);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
export { moduleManager };
|
|
121
|
+
export { CLIProviderImpl } from "./provider";
|
|
122
|
+
run();
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { spawnSync } from "child_process";
|
|
2
|
+
import path from "path";
|
|
3
|
+
export const installCommands = {
|
|
4
|
+
install: async ({ args })=>{
|
|
5
|
+
if (args.length === 0) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const cliDir = path.resolve(__dirname, '..');
|
|
9
|
+
spawnSync('npm', [
|
|
10
|
+
'install',
|
|
11
|
+
...args
|
|
12
|
+
], {
|
|
13
|
+
cwd: cliDir,
|
|
14
|
+
stdio: 'inherit',
|
|
15
|
+
shell: true
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
addedToGitignore: 'Added {{line}} to .gitignore',
|
|
3
|
+
androidCrunchPngsWarning: 'The crunchPngs option of android seems not disabled (Please ignore this warning if already disabled), which may cause abnormal consumption of mobile network traffic. Please refer to https://cresc.dev/docs/getting-started#disable-crunchpngs-on-android \n',
|
|
4
|
+
aabOpenApksFailed: 'Failed to open generated .apks file',
|
|
5
|
+
aabReadUniversalApkFailed: 'Failed to read universal.apk',
|
|
6
|
+
aabUniversalApkNotFound: 'universal.apk not found in generated .apks',
|
|
7
|
+
aabBundletoolDownloadHint: 'bundletool not found. Downloading node-bundletool via npx (first run may take a while).',
|
|
8
|
+
aabManifestNotFound: "AndroidManifest.xml can't be found in AAB base/manifest/",
|
|
9
|
+
aabParseResourcesWarning: '[Warning] Failed to parse resources.arsc: {{error}}',
|
|
10
|
+
aabParseFailed: 'Failed to parse AAB: {{error}}',
|
|
11
|
+
aabParseManifestError: 'Parse AndroidManifest.xml error: {{error}}',
|
|
12
|
+
aabParseResourcesError: 'Parser resources.arsc error: {{error}}',
|
|
13
|
+
appId: 'App ID',
|
|
14
|
+
appIdMismatchApk: 'App ID mismatch! Current APK: {{appIdInPkg}}, current update.json: {{appId}}',
|
|
15
|
+
appIdMismatchApp: 'App ID mismatch! Current APP: {{appIdInPkg}}, current update.json: {{appId}}',
|
|
16
|
+
appIdMismatchIpa: 'App ID mismatch! Current IPA: {{appIdInPkg}}, current update.json: {{appId}}',
|
|
17
|
+
appKeyMismatchApk: 'App Key mismatch! Current APK: {{appKeyInPkg}}, current update.json: {{appKey}}',
|
|
18
|
+
appKeyMismatchApp: 'App Key mismatch! Current APP: {{appKeyInPkg}}, current update.json: {{appKey}}',
|
|
19
|
+
appKeyMismatchIpa: 'App Key mismatch! Current IPA: {{appKeyInPkg}}, current update.json: {{appKey}}',
|
|
20
|
+
appName: 'App Name',
|
|
21
|
+
appNameQuestion: 'App Name:',
|
|
22
|
+
appNotSelected: 'App not selected. run `cresc selectApp --platform {{platform}}` first!',
|
|
23
|
+
appUploadSuccess: 'Successfully uploaded APP native package (id: {{id}}, version: {{version}}, buildTime: {{buildTime}})',
|
|
24
|
+
apkUploadSuccess: 'Successfully uploaded APK native package (id: {{id}}, version: {{version}}, buildTime: {{buildTime}})',
|
|
25
|
+
boundTo: ', bound to: {{name}} ({{id}})',
|
|
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
|
+
bundleCommandError: '"react-native bundle" command exited with code {{code}}.',
|
|
28
|
+
bundleNotFound: 'Bundle file not found. Please ensure that this {{packageType}} is a release version and the bundle file name is the default `{{entryFile}}`',
|
|
29
|
+
bundlingWithRN: 'Bundling with react-native: {{version}}',
|
|
30
|
+
cancelled: 'Cancelled',
|
|
31
|
+
composingSourceMap: 'Composing source map',
|
|
32
|
+
copyFileFailed: 'Failed to copy file: {{error}}',
|
|
33
|
+
copyHarmonyBundleError: 'Error copying Harmony bundle: {{error}}',
|
|
34
|
+
copyingDebugId: 'Copying debugid',
|
|
35
|
+
createAppSuccess: 'App created successfully (id: {{id}})',
|
|
36
|
+
deleteFile: 'Delete {{- file}}',
|
|
37
|
+
deletingFile: 'Delete {{- file}}',
|
|
38
|
+
enterAppIdQuestion: 'Enter AppId:',
|
|
39
|
+
enterNativePackageId: 'Enter native package ID:',
|
|
40
|
+
errorInHarmonyApp: 'Error in getEntryFromHarmonyApp: {{error}}',
|
|
41
|
+
expiredStatus: '(Expired)',
|
|
42
|
+
failedToParseIcon: '[Warning] failed to parse icon: {{error}}',
|
|
43
|
+
failedToParseUpdateJson: 'Failed to parse file `update.json`. Try to remove it manually.',
|
|
44
|
+
fileGenerated: '{{- file}} generated.',
|
|
45
|
+
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}}',
|
|
46
|
+
forceHermes: 'Forcing Hermes enabled for this build',
|
|
47
|
+
hermesEnabledCompiling: 'Hermes enabled, now compiling to hermes bytecode:\n',
|
|
48
|
+
ipaUploadSuccess: 'Successfully uploaded IPA native package (id: {{id}}, version: {{version}}, buildTime: {{buildTime}})',
|
|
49
|
+
keyStrings: 'Key strings:',
|
|
50
|
+
latestVersionTag: '(latest: {{version}})',
|
|
51
|
+
lockBestPractice: `
|
|
52
|
+
Best practices for lock files:
|
|
53
|
+
1. All members of the development team should use the same package manager to maintain a single lock file.
|
|
54
|
+
2. Add the lock file to version control (but do not commit multiple lock files of different formats).
|
|
55
|
+
3. Pay attention to changes in the lock file during code review.
|
|
56
|
+
This can reduce the risk of inconsistent dependencies and supply chain attacks.
|
|
57
|
+
`,
|
|
58
|
+
lockNotFound: 'No lock file detected, which may cause inconsistent dependencies and hot-updating issues.',
|
|
59
|
+
loggedOut: 'Logged out',
|
|
60
|
+
loginExpired: 'Login information has expired. Please use `cresc login` command to re-login',
|
|
61
|
+
loginFirst: 'Not logged in.\nPlease run `cresc login` in the project directory to login.',
|
|
62
|
+
multipleLocksFound: 'Multiple lock files detected ({{- lockFiles}}), which may cause inconsistent dependencies and hot-updating issues.',
|
|
63
|
+
nativePackageId: 'Native Package ID',
|
|
64
|
+
nativeVersion: 'Native Version',
|
|
65
|
+
nativeVersionNotFoundGte: 'No native version found >= {{version}}',
|
|
66
|
+
nativeVersionNotFoundLte: 'No native version found <= {{version}}',
|
|
67
|
+
nativeVersionNotFoundMatch: 'No matching native version found: {{version}}',
|
|
68
|
+
nativePackageIdNotFound: 'No native package id found: {{id}}',
|
|
69
|
+
noPackagesFound: 'No packages found. (appId: {{appId}})',
|
|
70
|
+
offset: 'Offset {{offset}}',
|
|
71
|
+
operationComplete: 'Operation complete, bound to {{count}} native versions',
|
|
72
|
+
operationSuccess: 'Operation successful',
|
|
73
|
+
packageIdRequired: 'Please provide packageId or packageVersion parameter',
|
|
74
|
+
packageUploadSuccess: 'Successfully uploaded new hot update package (id: {{id}})',
|
|
75
|
+
packing: 'Packing',
|
|
76
|
+
pausedStatus: '(Paused)',
|
|
77
|
+
platform: 'Platform',
|
|
78
|
+
platformPrompt: 'Platform (ios/android/harmony):',
|
|
79
|
+
platformQuestion: 'Platform(ios/android/harmony):',
|
|
80
|
+
platformRequired: 'Platform must be specified.',
|
|
81
|
+
pluginDetectionError: 'error while detecting {{name}} plugin: {{error}}',
|
|
82
|
+
pluginDetected: 'detected {{name}} plugin',
|
|
83
|
+
ppkPackageGenerated: 'ppk package generated and saved to: {{- output}}',
|
|
84
|
+
processingError: 'Error processing file: {{error}}',
|
|
85
|
+
processingPackage: 'Processing the package {{count}} ...',
|
|
86
|
+
processingStringPool: 'Processing the string pool ...',
|
|
87
|
+
publishUsage: 'Usage: pushy publish <ppk file> --platform ios|android|harmony',
|
|
88
|
+
rnuVersionNotFound: 'react-native-update: Cannot get the version number. Please run the command in the project directory',
|
|
89
|
+
rolloutConfigSet: 'Set {{rollout}}% rollout for OTA update {{version}} on native version(s) {{versions}}',
|
|
90
|
+
rolloutRangeError: 'rollout must be an integer between 1-100',
|
|
91
|
+
runningHermesc: 'Running hermesc: {{- command}} {{- args}}',
|
|
92
|
+
sentryCliNotFound: 'Cannot find Sentry CLI tool, please make sure @sentry/cli is properly installed',
|
|
93
|
+
sentryReleaseCreated: 'Sentry release created for version: {{version}}',
|
|
94
|
+
totalApps: 'Total {{count}} {{platform}} apps',
|
|
95
|
+
totalPackages: 'Total {{count}} packages',
|
|
96
|
+
typeStrings: 'Type strings:',
|
|
97
|
+
unsupportedPlatform: 'Unsupported platform `{{platform}}`',
|
|
98
|
+
uploadBundlePrompt: 'Upload this bundle now?(Y/N)',
|
|
99
|
+
uploadingSourcemap: 'Uploading sourcemap',
|
|
100
|
+
usageDiff: 'Usage: cresc {{command}} <origin> <next>',
|
|
101
|
+
usageParseApk: 'Usage: cresc parseApk <apk file>',
|
|
102
|
+
usageParseAab: 'Usage: cresc parseAab <aab file>',
|
|
103
|
+
usageExtractApk: 'Usage: cresc extractApk <aab file> [--output <apk file>] [--includeAllSplits] [--splits <split names>]',
|
|
104
|
+
usageParseApp: 'Usage: cresc parseApp <app file>',
|
|
105
|
+
usageParseIpa: 'Usage: cresc parseIpa <ipa file>',
|
|
106
|
+
usageUnderDevelopment: 'Usage is under development now.',
|
|
107
|
+
usageUploadApk: 'Usage: cresc uploadApk <apk file>',
|
|
108
|
+
usageUploadAab: 'Usage: cresc uploadAab <aab file> [--includeAllSplits] [--splits <split names>]',
|
|
109
|
+
usageUploadApp: 'Usage: cresc uploadApp <app file>',
|
|
110
|
+
usageUploadIpa: 'Usage: cresc uploadIpa <ipa file>',
|
|
111
|
+
versionBind: 'Bound hot update {{version}} to native version {{nativeVersion}} (id: {{id}})',
|
|
112
|
+
welcomeMessage: 'Welcome to Cresc hot update service, {{name}}.',
|
|
113
|
+
versionNameQuestion: 'Enter OTA update name:',
|
|
114
|
+
versionDescriptionQuestion: 'Enter OTA update description:',
|
|
115
|
+
versionMetaInfoQuestion: 'Enter custom meta info:',
|
|
116
|
+
updateNativePackageQuestion: 'Bind to native package now?(Y/N)',
|
|
117
|
+
unnamed: '(Unnamed)',
|
|
118
|
+
dryRun: 'Below is the dry-run result, no actual operation will be performed:',
|
|
119
|
+
usingCustomVersion: 'Using custom version: {{version}}',
|
|
120
|
+
confirmDeletePackage: 'Confirm delete native package {{packageId}}? This operation cannot be undone (Y/N):',
|
|
121
|
+
deletePackageSuccess: 'Native package {{packageId}} deleted successfully',
|
|
122
|
+
deletePackageError: 'Failed to delete native package {{packageId}}: {{error}}',
|
|
123
|
+
usageDeletePackage: 'Usage: cresc deletePackage [packageId] --appId [appId]',
|
|
124
|
+
deleteVersionSuccess: 'Version {{versionId}} deleted successfully',
|
|
125
|
+
deleteVersionError: 'Failed to delete version {{versionId}}: {{error}}',
|
|
126
|
+
bundleFileNotFound: 'Bundle file not found! Please use default bundle file name and path.',
|
|
127
|
+
diffPackageGenerated: '{{- output}} generated.',
|
|
128
|
+
nodeBsdiffRequired: 'This function needs "node-bsdiff". Please run "{{scriptName}} install node-bsdiff" to install',
|
|
129
|
+
nodeHdiffpatchRequired: 'This function needs "node-hdiffpatch". Please run "{{scriptName}} install node-hdiffpatch" to install',
|
|
130
|
+
apkExtracted: 'APK extracted to {{output}}'
|
|
131
|
+
};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
addedToGitignore: '已将 {{line}} 添加到 .gitignore',
|
|
3
|
+
androidCrunchPngsWarning: 'android 的 crunchPngs 选项似乎尚未禁用(如已禁用则请忽略此提示),这可能导致热更包体积异常增大,具体请参考 https://pushy.reactnative.cn/docs/getting-started.html#%E7%A6%81%E7%94%A8-android-%E7%9A%84-crunch-%E4%BC%98%E5%8C%96 \n',
|
|
4
|
+
aabOpenApksFailed: '无法打开生成的 .apks 文件',
|
|
5
|
+
aabReadUniversalApkFailed: '无法读取 universal.apk',
|
|
6
|
+
aabUniversalApkNotFound: '在生成的 .apks 中未找到 universal.apk',
|
|
7
|
+
aabBundletoolDownloadHint: '未找到 bundletool,正在通过 npx 下载 node-bundletool(首次下载可能需要一些时间)。',
|
|
8
|
+
aabManifestNotFound: '在 AAB 的 base/manifest/ 中找不到 AndroidManifest.xml',
|
|
9
|
+
aabParseResourcesWarning: '[警告] 解析 resources.arsc 失败:{{error}}',
|
|
10
|
+
aabParseFailed: '解析 AAB 失败:{{error}}',
|
|
11
|
+
aabParseManifestError: '解析 AndroidManifest.xml 出错:{{error}}',
|
|
12
|
+
aabParseResourcesError: '解析 resources.arsc 出错:{{error}}',
|
|
13
|
+
appId: '应用 id',
|
|
14
|
+
appIdMismatchApk: 'appId不匹配!当前apk: {{appIdInPkg}}, 当前update.json: {{appId}}',
|
|
15
|
+
appIdMismatchApp: 'appId不匹配!当前app: {{appIdInPkg}}, 当前update.json: {{appId}}',
|
|
16
|
+
appIdMismatchIpa: 'appId不匹配!当前ipa: {{appIdInPkg}}, 当前update.json: {{appId}}',
|
|
17
|
+
appKeyMismatchApk: 'appKey不匹配!当前apk: {{appKeyInPkg}}, 当前update.json: {{appKey}}',
|
|
18
|
+
appKeyMismatchApp: 'appKey不匹配!当前app: {{appKeyInPkg}}, 当前update.json: {{appKey}}',
|
|
19
|
+
appKeyMismatchIpa: 'appKey不匹配!当前ipa: {{appKeyInPkg}}, 当前update.json: {{appKey}}',
|
|
20
|
+
appName: '应用名称',
|
|
21
|
+
appNameQuestion: '应用名称:',
|
|
22
|
+
appNotSelected: '尚未选择应用。请先运行 `pushy selectApp --platform {{platform}}` 来选择应用',
|
|
23
|
+
appUploadSuccess: '已成功上传app原生包(id: {{id}}, version: {{version}}, buildTime: {{buildTime}})',
|
|
24
|
+
apkUploadSuccess: '已成功上传apk原生包(id: {{id}}, version: {{version}}, buildTime: {{buildTime}})',
|
|
25
|
+
boundTo: ', 已绑定:{{name}} ({{id}})',
|
|
26
|
+
buildTimeNotFound: '无法获取此包的编译时间戳。请更新 `react-native-update` 到最新版本后重新打包上传。',
|
|
27
|
+
bundleCommandError: '"react-native bundle" 命令退出,代码为 {{code}}。',
|
|
28
|
+
bundleNotFound: '找不到 bundle 文件。请确保此 {{packageType}} 为 release 版本,且 bundle 文件名为默认的 `{{entryFile}}`',
|
|
29
|
+
bundlingWithRN: '正在使用 react-native {{version}} 打包',
|
|
30
|
+
cancelled: '已取消',
|
|
31
|
+
composingSourceMap: '正在生成 source map',
|
|
32
|
+
copyFileFailed: '复制文件失败:{{error}}',
|
|
33
|
+
copyHarmonyBundleError: '复制 Harmony bundle 错误:{{error}}',
|
|
34
|
+
copyingDebugId: '正在复制 debugid',
|
|
35
|
+
createAppSuccess: '已成功创建应用(id: {{id}})',
|
|
36
|
+
deleteFile: '删除 {{- file}}',
|
|
37
|
+
deletingFile: '删除 {{- file}}',
|
|
38
|
+
enterAppIdQuestion: '输入应用 id:',
|
|
39
|
+
enterNativePackageId: '输入原生包 id:',
|
|
40
|
+
errorInHarmonyApp: '获取 Harmony 应用入口时出错:{{error}}',
|
|
41
|
+
expiredStatus: '(已过期)',
|
|
42
|
+
failedToParseIcon: '[警告] 解析图标失败:{{error}}',
|
|
43
|
+
failedToParseUpdateJson: '无法解析文件 `update.json`。请手动删除它。',
|
|
44
|
+
fileGenerated: '已生成 {{- file}}',
|
|
45
|
+
fileSizeExceeded: '此文件大小 {{fileSize}} , 超出当前额度 {{maxSize}} 。您可以考虑升级付费业务以提升此额度。详情请访问: {{- pricingPageUrl}}',
|
|
46
|
+
forceHermes: '强制启用 Hermes 编译',
|
|
47
|
+
hermesEnabledCompiling: 'Hermes 已启用,正在编译为 hermes 字节码:\n',
|
|
48
|
+
ipaUploadSuccess: '已成功上传ipa原生包(id: {{id}}, version: {{version}}, buildTime: {{buildTime}})',
|
|
49
|
+
keyStrings: '键字符串:',
|
|
50
|
+
latestVersionTag: '(最新:{{version}})',
|
|
51
|
+
lockBestPractice: `
|
|
52
|
+
关于 lock 文件的最佳实践:
|
|
53
|
+
1. 开发团队中的所有成员应该使用相同的包管理器,维护同一份 lock 文件。
|
|
54
|
+
2. 将 lock 文件添加到版本控制中(但不要同时提交多种不同格式的 lock 文件)。
|
|
55
|
+
3. 代码审核时应关注 lock 文件的变化。
|
|
56
|
+
这样可以最大限度避免因依赖关系不一致而导致的热更异常,也降低供应链攻击等安全隐患。
|
|
57
|
+
`,
|
|
58
|
+
lockNotFound: '没有检测到任何 lock 文件,这可能导致依赖关系不一致而使热更异常。',
|
|
59
|
+
loggedOut: '已退出登录',
|
|
60
|
+
loginExpired: '登录信息已过期,请使用 `pushy login` 命令重新登录',
|
|
61
|
+
loginFirst: '尚未登录。\n请在项目目录中运行`pushy login`命令来登录',
|
|
62
|
+
multipleLocksFound: '检测到多种不同格式的锁文件({{- lockFiles}}),这可能导致依赖关系不一致而使热更异常。',
|
|
63
|
+
nativePackageId: '原生包 Id',
|
|
64
|
+
nativeVersion: '原生版本',
|
|
65
|
+
nativeVersionNotFoundGte: '未查询到 >= {{version}} 的原生版本',
|
|
66
|
+
nativeVersionNotFoundLte: '未查询到 <= {{version}} 的原生版本',
|
|
67
|
+
nativeVersionNotFoundMatch: '未查询到匹配原生版本:{{version}}',
|
|
68
|
+
nativePackageIdNotFound: '未查询到原生包 id: {{id}}',
|
|
69
|
+
noPackagesFound: '未查询到任何原生包(appId: {{appId}})',
|
|
70
|
+
offset: '偏移量 {{offset}}',
|
|
71
|
+
operationComplete: '操作完成,共已绑定 {{count}} 个原生版本',
|
|
72
|
+
operationSuccess: '操作成功',
|
|
73
|
+
packageIdRequired: '请提供 packageId 或 packageVersion 参数',
|
|
74
|
+
packageUploadSuccess: '已成功上传新热更包(id: {{id}})',
|
|
75
|
+
packing: '正在打包',
|
|
76
|
+
pausedStatus: '(已暂停)',
|
|
77
|
+
platform: '平台',
|
|
78
|
+
platformPrompt: '平台(ios/android/harmony):',
|
|
79
|
+
platformQuestion: '平台(ios/android/harmony):',
|
|
80
|
+
platformRequired: '必须指定平台。',
|
|
81
|
+
pluginDetectionError: '检测 {{name}} 插件时出错:{{error}}',
|
|
82
|
+
pluginDetected: '检测到 {{name}} 插件',
|
|
83
|
+
ppkPackageGenerated: 'ppk 热更包已生成并保存到: {{- output}}',
|
|
84
|
+
processingError: '处理文件时出错:{{error}}',
|
|
85
|
+
processingPackage: '正在处理包 {{count}}...',
|
|
86
|
+
processingStringPool: '正在处理字符串池...',
|
|
87
|
+
publishUsage: '使用方法: pushy publish ppk后缀文件 --platform ios|android|harmony',
|
|
88
|
+
rnuVersionNotFound: 'react-native-update: 无法获取版本号。请在项目目录中运行命令',
|
|
89
|
+
rolloutConfigSet: '已在原生版本 {{versions}} 上设置灰度发布 {{rollout}}% 热更包 {{version}}',
|
|
90
|
+
rolloutRangeError: 'rollout 必须是 1-100 的整数',
|
|
91
|
+
runningHermesc: '运行 hermesc:{{- command}} {{- args}}',
|
|
92
|
+
sentryCliNotFound: '无法找到 Sentry CLI 工具,请确保已正确安装 @sentry/cli',
|
|
93
|
+
sentryReleaseCreated: '已为版本 {{version}} 创建 Sentry release',
|
|
94
|
+
totalApps: '共 {{count}} 个 {{platform}} 应用',
|
|
95
|
+
totalPackages: '共 {{count}} 个包',
|
|
96
|
+
typeStrings: '类型字符串:',
|
|
97
|
+
unsupportedPlatform: '无法识别的平台 `{{platform}}`',
|
|
98
|
+
uploadBundlePrompt: '是否现在上传此热更包?(Y/N)',
|
|
99
|
+
uploadingSourcemap: '正在上传 sourcemap',
|
|
100
|
+
usageDiff: '用法:pushy {{command}} <origin> <next>',
|
|
101
|
+
usageParseApk: '使用方法: pushy parseApk apk后缀文件',
|
|
102
|
+
usageParseAab: '使用方法: pushy parseAab aab后缀文件',
|
|
103
|
+
usageExtractApk: '使用方法: pushy extractApk aab后缀文件 [--output apk文件] [--includeAllSplits] [--splits 分包名列表]',
|
|
104
|
+
usageParseApp: '使用方法: pushy parseApp app后缀文件',
|
|
105
|
+
usageParseIpa: '使用方法: pushy parseIpa ipa后缀文件',
|
|
106
|
+
usageUploadApk: '使用方法: pushy uploadApk apk后缀文件',
|
|
107
|
+
usageUploadAab: '使用方法: pushy uploadAab aab后缀文件 [--includeAllSplits] [--splits 分包名列表]',
|
|
108
|
+
usageUploadApp: '使用方法: pushy uploadApp app后缀文件',
|
|
109
|
+
usageUploadIpa: '使用方法: pushy uploadIpa ipa后缀文件',
|
|
110
|
+
versionBind: '已将热更包 {{version}} 绑定到原生版本 {{nativeVersion}} (id: {{id}})',
|
|
111
|
+
welcomeMessage: '欢迎使用 pushy 热更新服务,{{name}}。',
|
|
112
|
+
versionNameQuestion: '输入版本名称:',
|
|
113
|
+
versionDescriptionQuestion: '输入版本描述:',
|
|
114
|
+
versionMetaInfoQuestion: '输入自定义的 meta info:',
|
|
115
|
+
updateNativePackageQuestion: '是否现在将此热更应用到原生包上?(Y/N)',
|
|
116
|
+
unnamed: '(未命名)',
|
|
117
|
+
dryRun: '以下是 dry-run 模拟运行结果,不会实际执行任何操作:',
|
|
118
|
+
usingCustomVersion: '使用自定义版本:{{version}}',
|
|
119
|
+
confirmDeletePackage: '确认删除原生包 {{packageId}}? 此操作不可撤销 (Y/N):',
|
|
120
|
+
deletePackageSuccess: '原生包 {{packageId}} 删除成功',
|
|
121
|
+
deletePackageError: '删除原生包 {{packageId}} 失败: {{error}}',
|
|
122
|
+
usageDeletePackage: '使用方法: pushy deletePackage [packageId] --appId [appId]',
|
|
123
|
+
deleteVersionSuccess: '热更包 {{versionId}} 删除成功',
|
|
124
|
+
deleteVersionError: '删除热更包 {{versionId}} 失败: {{error}}',
|
|
125
|
+
bundleFileNotFound: '未找到 bundle 文件!请使用默认的 bundle 文件名和路径。',
|
|
126
|
+
diffPackageGenerated: '{{- output}} 已生成。',
|
|
127
|
+
nodeBsdiffRequired: '此功能需要 "node-bsdiff"。请运行 "{{scriptName}} install node-bsdiff" 来安装',
|
|
128
|
+
nodeHdiffpatchRequired: '此功能需要 "node-hdiffpatch"。请运行 "{{scriptName}} install node-hdiffpatch" 来安装',
|
|
129
|
+
apkExtracted: 'APK 已提取到 {{output}}'
|
|
130
|
+
};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { CLIProviderImpl } from "./provider";
|
|
2
|
+
export class ModuleManager {
|
|
3
|
+
registerModule(module) {
|
|
4
|
+
if (this.modules.has(module.name)) {
|
|
5
|
+
throw new Error(`Module '${module.name}' is already registered`);
|
|
6
|
+
}
|
|
7
|
+
this.modules.set(module.name, module);
|
|
8
|
+
if (module.commands) {
|
|
9
|
+
for (const command of module.commands){
|
|
10
|
+
this.registerCommand(command);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
if (module.workflows) {
|
|
14
|
+
for (const workflow of module.workflows){
|
|
15
|
+
this.registerWorkflow(workflow);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (module.init) {
|
|
19
|
+
module.init(this.provider);
|
|
20
|
+
}
|
|
21
|
+
// console.log(
|
|
22
|
+
// `Module '${module.name}' (v${module.version}) registered successfully`,
|
|
23
|
+
// );
|
|
24
|
+
}
|
|
25
|
+
unregisterModule(moduleName) {
|
|
26
|
+
const module = this.modules.get(moduleName);
|
|
27
|
+
if (!module) {
|
|
28
|
+
throw new Error(`Module '${moduleName}' is not registered`);
|
|
29
|
+
}
|
|
30
|
+
if (module.commands) {
|
|
31
|
+
for (const command of module.commands){
|
|
32
|
+
this.commands.delete(command.name);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (module.workflows) {
|
|
36
|
+
for (const workflow of module.workflows){
|
|
37
|
+
this.workflows.delete(workflow.name);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (module.cleanup) {
|
|
41
|
+
module.cleanup();
|
|
42
|
+
}
|
|
43
|
+
this.modules.delete(moduleName);
|
|
44
|
+
console.log(`Module '${moduleName}' unregistered successfully`);
|
|
45
|
+
}
|
|
46
|
+
registerCommand(command) {
|
|
47
|
+
if (this.commands.has(command.name)) {
|
|
48
|
+
throw new Error(`Command '${command.name}' is already registered`);
|
|
49
|
+
}
|
|
50
|
+
this.commands.set(command.name, command);
|
|
51
|
+
}
|
|
52
|
+
registerWorkflow(workflow) {
|
|
53
|
+
if (this.workflows.has(workflow.name)) {
|
|
54
|
+
throw new Error(`Workflow '${workflow.name}' is already registered`);
|
|
55
|
+
}
|
|
56
|
+
this.workflows.set(workflow.name, workflow);
|
|
57
|
+
this.provider.registerWorkflow(workflow);
|
|
58
|
+
}
|
|
59
|
+
getRegisteredCommands() {
|
|
60
|
+
return Array.from(this.commands.values());
|
|
61
|
+
}
|
|
62
|
+
getRegisteredWorkflows() {
|
|
63
|
+
return Array.from(this.workflows.values());
|
|
64
|
+
}
|
|
65
|
+
getRegisteredModules() {
|
|
66
|
+
return Array.from(this.modules.values());
|
|
67
|
+
}
|
|
68
|
+
async executeCommand(commandName, context) {
|
|
69
|
+
const command = this.commands.get(commandName);
|
|
70
|
+
if (!command) {
|
|
71
|
+
throw new Error(`Command '${commandName}' not found`);
|
|
72
|
+
}
|
|
73
|
+
return await command.handler(context);
|
|
74
|
+
}
|
|
75
|
+
async executeWorkflow(workflowName, context) {
|
|
76
|
+
return await this.provider.executeWorkflow(workflowName, context);
|
|
77
|
+
}
|
|
78
|
+
getProvider() {
|
|
79
|
+
return this.provider;
|
|
80
|
+
}
|
|
81
|
+
listCommands() {
|
|
82
|
+
return Array.from(this.commands.values());
|
|
83
|
+
}
|
|
84
|
+
listWorkflows() {
|
|
85
|
+
return Array.from(this.workflows.values());
|
|
86
|
+
}
|
|
87
|
+
listAll() {
|
|
88
|
+
console.log('\n=== Registered Commands ===');
|
|
89
|
+
for (const command of this.commands.values()){
|
|
90
|
+
console.log(` ${command.name}: ${command.description || 'No description'}`);
|
|
91
|
+
}
|
|
92
|
+
console.log('\n=== Registered Workflows ===');
|
|
93
|
+
for (const workflow of this.workflows.values()){
|
|
94
|
+
console.log(` ${workflow.name}: ${workflow.description || 'No description'}`);
|
|
95
|
+
}
|
|
96
|
+
console.log('\n=== Registered Modules ===');
|
|
97
|
+
for (const module of this.modules.values()){
|
|
98
|
+
var _module_commands, _module_workflows;
|
|
99
|
+
console.log(` ${module.name} (v${module.version}): ${((_module_commands = module.commands) == null ? void 0 : _module_commands.length) || 0} commands, ${((_module_workflows = module.workflows) == null ? void 0 : _module_workflows.length) || 0} workflows`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
constructor(){
|
|
103
|
+
this.modules = new Map();
|
|
104
|
+
this.commands = new Map();
|
|
105
|
+
this.workflows = new Map();
|
|
106
|
+
this.provider = new CLIProviderImpl();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
export const moduleManager = new ModuleManager();
|