react-native-update 10.37.1 → 10.37.3
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/harmony/pushy/hvigor-plugin.ts +1 -1
- package/package.json +1 -1
- package/scripts/bundle-metadata-plugin.js +184 -0
- package/scripts/hermesc-wrapper.js +97 -0
- package/src/provider.tsx +4 -2
- package/src/type.ts +4 -4
package/package.json
CHANGED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
const crypto = require('crypto');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const PROJECT_ROOT = path.resolve(__dirname, '../../..');
|
|
5
|
+
console.log(`[Bundle Metadata] Project root: ${PROJECT_ROOT}`);
|
|
6
|
+
|
|
7
|
+
function calculateContentHash(bundleCode) {
|
|
8
|
+
const hash = crypto.createHash('sha256');
|
|
9
|
+
hash.update(bundleCode, 'utf8');
|
|
10
|
+
return hash.digest('hex');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function generateMetadataInjection(contentHash) {
|
|
14
|
+
return `// Auto-injected bundle metadata by Metro plugin
|
|
15
|
+
var __BUNDLE_METADATA__ = {
|
|
16
|
+
contentHash: '${contentHash}'
|
|
17
|
+
};
|
|
18
|
+
`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function generateMetadataComment(contentHash) {
|
|
22
|
+
return `\n//# BUNDLE_METADATA ${JSON.stringify({
|
|
23
|
+
contentHash
|
|
24
|
+
})}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function setupSingleHermesc(hermescPath, locationName) {
|
|
28
|
+
const hermescDir = path.dirname(hermescPath);
|
|
29
|
+
const backupHermescPath = path.join(hermescDir, '_hermesc');
|
|
30
|
+
const wrapperSourcePath = path.join(__dirname, 'hermesc-wrapper.js');
|
|
31
|
+
|
|
32
|
+
if (fs.existsSync(backupHermescPath)) {
|
|
33
|
+
console.log(`⏭️ [Hermesc Setup] ${locationName} already configured, skipping...`);
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!fs.existsSync(hermescPath)) {
|
|
38
|
+
console.log(`ℹ️ [Hermesc Setup] ${locationName} hermesc not found at: ${hermescPath}`);
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!fs.existsSync(wrapperSourcePath)) {
|
|
43
|
+
console.error(`❌ [Hermesc Setup] Wrapper script not found at: ${wrapperSourcePath}`);
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
console.log(`🔧 [Hermesc Setup] Setting up hermesc wrapper for ${locationName}...`);
|
|
49
|
+
|
|
50
|
+
fs.renameSync(hermescPath, backupHermescPath);
|
|
51
|
+
console.log(`✅ [Hermesc Setup] ${locationName}: Renamed hermesc -> _hermesc`);
|
|
52
|
+
|
|
53
|
+
const shellScript = `#!/bin/bash
|
|
54
|
+
# Hermesc wrapper script - auto-generated
|
|
55
|
+
# This script calls the Node.js wrapper which handles post-processing
|
|
56
|
+
|
|
57
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
58
|
+
WRAPPER_SCRIPT="${wrapperSourcePath}"
|
|
59
|
+
|
|
60
|
+
find_node() {
|
|
61
|
+
if command -v node >/dev/null 2>&1; then
|
|
62
|
+
command -v node
|
|
63
|
+
return 0
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
local NODE_PATHS=(
|
|
67
|
+
"/usr/local/bin/node"
|
|
68
|
+
"/opt/homebrew/bin/node"
|
|
69
|
+
"$HOME/.nvm/versions/node/$(ls -t "$HOME/.nvm/versions/node" 2>/dev/null | head -1)/bin/node"
|
|
70
|
+
"/usr/bin/node"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
for node_path in "\${NODE_PATHS[@]}"; do
|
|
74
|
+
if [ -x "$node_path" ]; then
|
|
75
|
+
echo "$node_path"
|
|
76
|
+
return 0
|
|
77
|
+
fi
|
|
78
|
+
done
|
|
79
|
+
|
|
80
|
+
echo "Error: node executable not found" >&2
|
|
81
|
+
echo "Please ensure Node.js is installed and accessible" >&2
|
|
82
|
+
exit 1
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
NODE_BIN=$(find_node)
|
|
86
|
+
exec "$NODE_BIN" "$WRAPPER_SCRIPT" "$@"
|
|
87
|
+
`;
|
|
88
|
+
|
|
89
|
+
fs.writeFileSync(hermescPath, shellScript, { mode: 0o755 });
|
|
90
|
+
console.log(`✅ [Hermesc Setup] ${locationName}: Created hermesc wrapper shell script`);
|
|
91
|
+
|
|
92
|
+
console.log(`🎉 [Hermesc Setup] ${locationName} configured successfully!`);
|
|
93
|
+
console.log(`📋 [Hermesc Setup] ${locationName} details:`);
|
|
94
|
+
console.log(` - Original: ${backupHermescPath}`);
|
|
95
|
+
console.log(` - Wrapper: ${hermescPath}`);
|
|
96
|
+
console.log(` - Handler: ${wrapperSourcePath}`);
|
|
97
|
+
|
|
98
|
+
return true;
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.error(`❌ [Hermesc Setup] Failed to setup hermesc wrapper for ${locationName}:`, error);
|
|
101
|
+
|
|
102
|
+
if (fs.existsSync(backupHermescPath) && !fs.existsSync(hermescPath)) {
|
|
103
|
+
try {
|
|
104
|
+
fs.renameSync(backupHermescPath, hermescPath);
|
|
105
|
+
console.log(`🔄 [Hermesc Setup] ${locationName}: Rolled back changes`);
|
|
106
|
+
} catch (rollbackError) {
|
|
107
|
+
console.error(`❌ [Hermesc Setup] ${locationName}: Rollback failed:`, rollbackError);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function setupHermescWrapper() {
|
|
116
|
+
const wrapperSourcePath = path.join(__dirname, 'hermesc-wrapper.js');
|
|
117
|
+
|
|
118
|
+
if (!fs.existsSync(wrapperSourcePath)) {
|
|
119
|
+
console.error(`❌ [Hermesc Setup] Wrapper script not found at: ${wrapperSourcePath}`);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
fs.chmodSync(wrapperSourcePath, 0o755);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error('❌ [Hermesc Setup] Failed to set execute permissions on wrapper:', error);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
console.log('🔧 [Hermesc Setup] Starting hermesc wrapper setup...');
|
|
130
|
+
|
|
131
|
+
const hermescLocations = [
|
|
132
|
+
{
|
|
133
|
+
path: path.join(PROJECT_ROOT, 'node_modules/react-native/sdks/hermesc/osx-bin/hermesc'),
|
|
134
|
+
name: 'Node Modules'
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
path: path.join(PROJECT_ROOT, 'ios/Pods/hermes-engine/destroot/bin/hermesc'),
|
|
138
|
+
name: 'iOS Pods'
|
|
139
|
+
}
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
let successCount = 0;
|
|
143
|
+
let totalProcessed = 0;
|
|
144
|
+
|
|
145
|
+
for (const location of hermescLocations) {
|
|
146
|
+
const success = setupSingleHermesc(location.path, location.name);
|
|
147
|
+
if (success) {
|
|
148
|
+
successCount++;
|
|
149
|
+
}
|
|
150
|
+
totalProcessed++;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
console.log(`\n📊 [Hermesc Setup] Summary: ${successCount}/${totalProcessed} locations configured successfully`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function metadataSerializer(entryPoint, preModules, graph, options) {
|
|
157
|
+
setupHermescWrapper();
|
|
158
|
+
const baseJSBundle = require('metro/src/DeltaBundler/Serializers/baseJSBundle');
|
|
159
|
+
const bundleToString = require('metro/src/lib/bundleToString');
|
|
160
|
+
const bundle = baseJSBundle(entryPoint, preModules, graph, options);
|
|
161
|
+
const { code: bundleCode } = bundleToString(bundle);
|
|
162
|
+
const contentHash = calculateContentHash(bundleCode);
|
|
163
|
+
const metadataInjection = generateMetadataInjection(contentHash);
|
|
164
|
+
const metadataComment = generateMetadataComment(contentHash);
|
|
165
|
+
const hashFilePath = path.join(PROJECT_ROOT, 'bundle-hash.json');
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const hashData = {
|
|
169
|
+
contentHash,
|
|
170
|
+
timestamp: new Date().toISOString(),
|
|
171
|
+
};
|
|
172
|
+
fs.writeFileSync(hashFilePath, JSON.stringify(hashData, null, 2));
|
|
173
|
+
console.log(`✅ [Metro] Saved hash to: ${hashFilePath}`);
|
|
174
|
+
console.log(`🔐 [Metro] Hash: ${contentHash.slice(0, 16)}...`);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.error('❌ [Metro] Failed to save hash file:', error);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return bundleCode + metadataInjection + metadataComment;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
module.exports = {
|
|
183
|
+
metadataSerializer,
|
|
184
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawn } = require('child_process');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const PROJECT_ROOT = path.resolve(__dirname, '../../..');
|
|
7
|
+
const realHermescPath = path.join(PROJECT_ROOT, 'node_modules/react-native/sdks/hermesc/osx-bin/_hermesc');
|
|
8
|
+
const args = process.argv.slice(2);
|
|
9
|
+
|
|
10
|
+
console.log(`[Hermesc Wrapper] Executing Hermes compilation...`);
|
|
11
|
+
console.log(`[Hermesc Wrapper] Args:`, args.join(' '));
|
|
12
|
+
|
|
13
|
+
const isCompileOperation = args.includes('-emit-binary');
|
|
14
|
+
let outputFile = null;
|
|
15
|
+
|
|
16
|
+
const outIndex = args.indexOf('-out');
|
|
17
|
+
if (outIndex !== -1 && outIndex + 1 < args.length) {
|
|
18
|
+
outputFile = args[outIndex + 1];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const hermesc = spawn(realHermescPath, args, {
|
|
22
|
+
stdio: 'inherit',
|
|
23
|
+
env: process.env
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
hermesc.on('error', (error) => {
|
|
27
|
+
console.error(`[Hermesc Wrapper] ❌ Failed to start hermesc:`, error);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
hermesc.on('close', (code) => {
|
|
32
|
+
console.log(`[Hermesc Wrapper] Hermes compilation completed with code: ${code}`);
|
|
33
|
+
|
|
34
|
+
if (code === 0 && isCompileOperation && outputFile) {
|
|
35
|
+
console.log(`[Hermesc Wrapper] 🔄 Post-processing HBC file: ${outputFile}`);
|
|
36
|
+
|
|
37
|
+
setTimeout(() => {
|
|
38
|
+
processHBCFile(outputFile);
|
|
39
|
+
}, 500);
|
|
40
|
+
} else {
|
|
41
|
+
process.exit(code);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
function processHBCFile(hbcFilePath) {
|
|
46
|
+
const hashFilePath = path.join(PROJECT_ROOT, 'bundle-hash.json');
|
|
47
|
+
|
|
48
|
+
if (!fs.existsSync(hashFilePath)) {
|
|
49
|
+
console.warn(`[Hermesc Wrapper] ⚠️ Hash file not found: ${hashFilePath}`);
|
|
50
|
+
console.warn(`[Hermesc Wrapper] Skipping metadata injection.`);
|
|
51
|
+
process.exit(0);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!fs.existsSync(hbcFilePath)) {
|
|
56
|
+
console.warn(`[Hermesc Wrapper] ⚠️ HBC file not found: ${hbcFilePath}`);
|
|
57
|
+
console.warn(`[Hermesc Wrapper] Skipping metadata injection.`);
|
|
58
|
+
process.exit(0);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
const hashData = JSON.parse(fs.readFileSync(hashFilePath, 'utf8'));
|
|
64
|
+
const { contentHash } = hashData;
|
|
65
|
+
|
|
66
|
+
console.log(`[Hermesc Wrapper] 📝 Injecting metadata into HBC...`);
|
|
67
|
+
console.log(`[Hermesc Wrapper] Hash: ${contentHash.slice(0, 16)}...`);
|
|
68
|
+
|
|
69
|
+
const hbcBuffer = fs.readFileSync(hbcFilePath);
|
|
70
|
+
|
|
71
|
+
const metadata = { contentHash };
|
|
72
|
+
const metadataJson = JSON.stringify(metadata);
|
|
73
|
+
|
|
74
|
+
const MAGIC = Buffer.from('RNUPDATE', 'utf8');
|
|
75
|
+
const jsonBuffer = Buffer.from(metadataJson, 'utf8');
|
|
76
|
+
const lengthBuffer = Buffer.alloc(4);
|
|
77
|
+
lengthBuffer.writeUInt32LE(jsonBuffer.length);
|
|
78
|
+
|
|
79
|
+
const finalBuffer = Buffer.concat([
|
|
80
|
+
hbcBuffer,
|
|
81
|
+
MAGIC,
|
|
82
|
+
jsonBuffer,
|
|
83
|
+
lengthBuffer,
|
|
84
|
+
MAGIC,
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
fs.writeFileSync(hbcFilePath, finalBuffer);
|
|
88
|
+
|
|
89
|
+
console.log(`[Hermesc Wrapper] ✅ Successfully injected metadata into: ${hbcFilePath}`);
|
|
90
|
+
console.log(`[Hermesc Wrapper] 🧹 Cleaning up hash file...`);
|
|
91
|
+
|
|
92
|
+
process.exit(0);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error(`[Hermesc Wrapper] ❌ Failed to process HBC file:`, error);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
}
|
package/src/provider.tsx
CHANGED
|
@@ -197,7 +197,9 @@ export const UpdateProvider = ({
|
|
|
197
197
|
}
|
|
198
198
|
log(`${info.name} in ${rollout}% rollout, continue`);
|
|
199
199
|
}
|
|
200
|
-
|
|
200
|
+
if (info.update) {
|
|
201
|
+
info.description = info.description ?? '';
|
|
202
|
+
}
|
|
201
203
|
updateInfoRef.current = info;
|
|
202
204
|
setUpdateInfo(info);
|
|
203
205
|
if (info.expired) {
|
|
@@ -250,7 +252,7 @@ export const UpdateProvider = ({
|
|
|
250
252
|
client.t('alert_title'),
|
|
251
253
|
client.t('alert_new_version_found', {
|
|
252
254
|
name: info.name!,
|
|
253
|
-
description: info.description
|
|
255
|
+
description: info.description!,
|
|
254
256
|
}),
|
|
255
257
|
[
|
|
256
258
|
{ text: client.t('alert_cancel'), style: 'cancel' },
|
package/src/type.ts
CHANGED
|
@@ -98,10 +98,10 @@ export interface ClientOptions {
|
|
|
98
98
|
dismissErrorAfter?: number;
|
|
99
99
|
debug?: boolean;
|
|
100
100
|
throwError?: boolean;
|
|
101
|
-
beforeCheckUpdate?: () => Promise<boolean
|
|
102
|
-
beforeDownloadUpdate?: (info: CheckResult) => Promise<boolean
|
|
103
|
-
afterDownloadUpdate?: (info: CheckResult) => Promise<boolean
|
|
104
|
-
onPackageExpired?: (info: CheckResult) => Promise<boolean
|
|
101
|
+
beforeCheckUpdate?: () => Promise<boolean> | boolean;
|
|
102
|
+
beforeDownloadUpdate?: (info: CheckResult) => Promise<boolean> | boolean;
|
|
103
|
+
afterDownloadUpdate?: (info: CheckResult) => Promise<boolean> | boolean;
|
|
104
|
+
onPackageExpired?: (info: CheckResult) => Promise<boolean> | boolean;
|
|
105
105
|
overridePackageVersion?: string;
|
|
106
106
|
}
|
|
107
107
|
|