react-native-inapp-inspector 2.2.3 → 2.2.4
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/dist/commonjs/components/AnalyticsDetail.js +5 -1
- package/dist/commonjs/components/AnalyticsEventCard.js +2 -1
- package/dist/commonjs/components/DiffViewer.js +1 -1
- package/dist/commonjs/components/Inspector/BundleTab.js +22 -0
- package/dist/commonjs/components/Inspector/DeviceInfoTab.d.ts +3 -0
- package/dist/commonjs/components/Inspector/DeviceInfoTab.js +835 -0
- package/dist/commonjs/components/Inspector/InspectorHeader.js +12 -14
- package/dist/commonjs/components/Inspector/LogDetail.js +6 -3
- package/dist/commonjs/components/Inspector/MainScreen.js +7 -3
- package/dist/commonjs/components/Inspector/NetworkTab.js +92 -15
- package/dist/commonjs/components/Inspector/PerformanceTab.js +38 -12
- package/dist/commonjs/components/Inspector/SettingsPanel.js +440 -229
- package/dist/commonjs/components/Inspector/StorageTab.d.ts +3 -0
- package/dist/commonjs/components/Inspector/StorageTab.js +892 -0
- package/dist/commonjs/components/Inspector/TabBar.js +14 -0
- package/dist/commonjs/components/Inspector/TelemetryConsentModal.js +11 -2
- package/dist/commonjs/components/Inspector/UpdateAvailableModal.js +4 -1
- package/dist/commonjs/components/NetworkIcons.d.ts +6 -0
- package/dist/commonjs/components/NetworkIcons.js +30 -1
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/bundleAnalyzer.js +44 -22
- package/dist/commonjs/customHooks/storageInspector.d.ts +67 -0
- package/dist/commonjs/customHooks/storageInspector.js +486 -0
- package/dist/commonjs/i18n/locales/en.json +8 -2
- package/dist/commonjs/index.d.ts +1 -0
- package/dist/commonjs/index.js +16 -1
- package/dist/commonjs/storage.d.ts +5 -0
- package/dist/commonjs/storage.js +18 -0
- package/dist/commonjs/types/enums.d.ts +5 -0
- package/dist/commonjs/types/enums.js +5 -0
- package/dist/esm/components/AnalyticsDetail.js +6 -2
- package/dist/esm/components/AnalyticsEventCard.js +2 -1
- package/dist/esm/components/DiffViewer.js +1 -1
- package/dist/esm/components/Inspector/BundleTab.js +22 -0
- package/dist/esm/components/Inspector/DeviceInfoTab.d.ts +3 -0
- package/dist/esm/components/Inspector/DeviceInfoTab.js +796 -0
- package/dist/esm/components/Inspector/InspectorHeader.js +13 -15
- package/dist/esm/components/Inspector/LogDetail.js +7 -4
- package/dist/esm/components/Inspector/MainScreen.js +7 -3
- package/dist/esm/components/Inspector/NetworkTab.js +93 -16
- package/dist/esm/components/Inspector/PerformanceTab.js +39 -13
- package/dist/esm/components/Inspector/SettingsPanel.js +441 -230
- package/dist/esm/components/Inspector/StorageTab.d.ts +3 -0
- package/dist/esm/components/Inspector/StorageTab.js +853 -0
- package/dist/esm/components/Inspector/TabBar.js +15 -1
- package/dist/esm/components/Inspector/TelemetryConsentModal.js +11 -2
- package/dist/esm/components/Inspector/UpdateAvailableModal.js +4 -1
- package/dist/esm/components/NetworkIcons.d.ts +6 -0
- package/dist/esm/components/NetworkIcons.js +23 -0
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/bundleAnalyzer.js +44 -22
- package/dist/esm/customHooks/storageInspector.d.ts +67 -0
- package/dist/esm/customHooks/storageInspector.js +469 -0
- package/dist/esm/i18n/locales/en.json +8 -2
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/storage.d.ts +5 -0
- package/dist/esm/storage.js +5 -0
- package/dist/esm/types/enums.d.ts +5 -0
- package/dist/esm/types/enums.js +5 -0
- package/package.json +8 -1
- package/src/components/AnalyticsDetail.tsx +6 -1
- package/src/components/AnalyticsEventCard.tsx +2 -1
- package/src/components/DiffViewer.tsx +1 -1
- package/src/components/Inspector/BundleTab.tsx +29 -0
- package/src/components/Inspector/DeviceInfoTab.tsx +1204 -0
- package/src/components/Inspector/InspectorHeader.tsx +13 -14
- package/src/components/Inspector/LogDetail.tsx +15 -11
- package/src/components/Inspector/MainScreen.tsx +7 -3
- package/src/components/Inspector/NetworkTab.tsx +104 -16
- package/src/components/Inspector/PerformanceTab.tsx +46 -12
- package/src/components/Inspector/SettingsPanel.tsx +570 -304
- package/src/components/Inspector/StorageTab.tsx +1048 -0
- package/src/components/Inspector/TabBar.tsx +20 -0
- package/src/components/Inspector/TelemetryConsentModal.tsx +26 -2
- package/src/components/Inspector/UpdateAvailableModal.tsx +13 -1
- package/src/components/NetworkIcons.tsx +103 -0
- package/src/constants/version.ts +1 -1
- package/src/customHooks/bundleAnalyzer.ts +47 -22
- package/src/customHooks/storageInspector.ts +509 -0
- package/src/i18n/locales/en.json +8 -2
- package/src/index.tsx +21 -1
- package/src/storage.ts +18 -0
- package/src/types/enums.ts +5 -0
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
ReduxIcon,
|
|
13
13
|
PerformanceIcon,
|
|
14
14
|
CrashIcon,
|
|
15
|
+
SmartphoneIcon,
|
|
16
|
+
DatabaseIcon,
|
|
15
17
|
} from '../NetworkIcons';
|
|
16
18
|
|
|
17
19
|
import {isReduxConnected} from '../../customHooks/reduxLogger';
|
|
@@ -86,6 +88,18 @@ const TabBar = React.memo(() => {
|
|
|
86
88
|
count: crashRecords?.length || 0,
|
|
87
89
|
icon: 'crash',
|
|
88
90
|
},
|
|
91
|
+
{
|
|
92
|
+
key: 'device',
|
|
93
|
+
label: 'Device',
|
|
94
|
+
count: 0,
|
|
95
|
+
icon: 'device',
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
key: 'storage',
|
|
99
|
+
label: 'Storage',
|
|
100
|
+
count: 0,
|
|
101
|
+
icon: 'storage',
|
|
102
|
+
},
|
|
89
103
|
] as const
|
|
90
104
|
)
|
|
91
105
|
.filter(tab => {
|
|
@@ -149,6 +163,12 @@ const TabBar = React.memo(() => {
|
|
|
149
163
|
{tab.icon === 'crash' && (
|
|
150
164
|
<CrashIcon color={iconColor} size={14} />
|
|
151
165
|
)}
|
|
166
|
+
{tab.icon === 'device' && (
|
|
167
|
+
<SmartphoneIcon color={iconColor} size={14} />
|
|
168
|
+
)}
|
|
169
|
+
{tab.icon === 'storage' && (
|
|
170
|
+
<DatabaseIcon color={iconColor} size={14} />
|
|
171
|
+
)}
|
|
152
172
|
<Text
|
|
153
173
|
numberOfLines={1}
|
|
154
174
|
ellipsizeMode="tail"
|
|
@@ -61,6 +61,25 @@ const CloseSvg = ({size = 13, color = '#64748B'}: {size?: number; color?: string
|
|
|
61
61
|
</Svg>
|
|
62
62
|
);
|
|
63
63
|
|
|
64
|
+
const GearSvg = ({size = 13, color = '#6366F1'}: {size?: number; color?: string}) => (
|
|
65
|
+
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
66
|
+
<Path
|
|
67
|
+
d="M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z"
|
|
68
|
+
stroke={color}
|
|
69
|
+
strokeWidth="2"
|
|
70
|
+
strokeLinecap="round"
|
|
71
|
+
strokeLinejoin="round"
|
|
72
|
+
/>
|
|
73
|
+
<Path
|
|
74
|
+
d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1Z"
|
|
75
|
+
stroke={color}
|
|
76
|
+
strokeWidth="2"
|
|
77
|
+
strokeLinecap="round"
|
|
78
|
+
strokeLinejoin="round"
|
|
79
|
+
/>
|
|
80
|
+
</Svg>
|
|
81
|
+
);
|
|
82
|
+
|
|
64
83
|
export const TelemetryConsentModal = () => {
|
|
65
84
|
const [visible, setVisible] = useState(false);
|
|
66
85
|
const fadeAnim = useState(new Animated.Value(0))[0];
|
|
@@ -150,8 +169,9 @@ export const TelemetryConsentModal = () => {
|
|
|
150
169
|
|
|
151
170
|
{/* Subheading instruction hint badge */}
|
|
152
171
|
<View style={styles.hintBadge}>
|
|
172
|
+
<GearSvg size={12} color="#6366F1" />
|
|
153
173
|
<Text style={styles.hintBadgeText}>
|
|
154
|
-
|
|
174
|
+
You can enable or disable this anytime in Settings
|
|
155
175
|
</Text>
|
|
156
176
|
</View>
|
|
157
177
|
</View>
|
|
@@ -290,12 +310,16 @@ const styles = StyleSheet.create({
|
|
|
290
310
|
...fontStack,
|
|
291
311
|
},
|
|
292
312
|
hintBadge: {
|
|
313
|
+
flexDirection: 'row',
|
|
314
|
+
alignItems: 'center',
|
|
315
|
+
justifyContent: 'center',
|
|
316
|
+
gap: 5,
|
|
293
317
|
backgroundColor: '#EDE9FE80',
|
|
294
318
|
borderWidth: 1,
|
|
295
319
|
borderColor: '#DDD6FE',
|
|
296
320
|
borderRadius: 7,
|
|
297
321
|
paddingHorizontal: 8,
|
|
298
|
-
paddingVertical:
|
|
322
|
+
paddingVertical: 3,
|
|
299
323
|
marginBottom: 8,
|
|
300
324
|
},
|
|
301
325
|
hintBadgeText: {
|
|
@@ -96,6 +96,18 @@ const SparkleSvg = ({size = 14, color = '#F59E0B'}: {size?: number; color?: stri
|
|
|
96
96
|
</Svg>
|
|
97
97
|
);
|
|
98
98
|
|
|
99
|
+
const ArrowRightSvg = ({size = 14, color = '#94A3B8'}: {size?: number; color?: string}) => (
|
|
100
|
+
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
101
|
+
<Path
|
|
102
|
+
d="M5 12h14M12 5l7 7-7 7"
|
|
103
|
+
stroke={color}
|
|
104
|
+
strokeWidth="2.2"
|
|
105
|
+
strokeLinecap="round"
|
|
106
|
+
strokeLinejoin="round"
|
|
107
|
+
/>
|
|
108
|
+
</Svg>
|
|
109
|
+
);
|
|
110
|
+
|
|
99
111
|
interface UpdateAvailableModalProps {
|
|
100
112
|
visible: boolean;
|
|
101
113
|
latestVersion: string | null;
|
|
@@ -215,7 +227,7 @@ export const UpdateAvailableModal: React.FC<UpdateAvailableModalProps> = ({
|
|
|
215
227
|
</View>
|
|
216
228
|
|
|
217
229
|
<View style={styles.arrowContainer}>
|
|
218
|
-
<
|
|
230
|
+
<ArrowRightSvg size={14} color="#94A3B8" />
|
|
219
231
|
</View>
|
|
220
232
|
|
|
221
233
|
<View style={styles.versionColumn}>
|
|
@@ -2116,3 +2116,106 @@ export const ChevronDownIcon = ({color = AppColors.grayTextWeak, size = 14}: Ico
|
|
|
2116
2116
|
</Svg>
|
|
2117
2117
|
);
|
|
2118
2118
|
|
|
2119
|
+
export const CpuIcon = ({
|
|
2120
|
+
color = AppColors.grayTextWeak,
|
|
2121
|
+
size = 14,
|
|
2122
|
+
}: IconProps) => (
|
|
2123
|
+
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
2124
|
+
<Rect x="4" y="4" width="16" height="16" rx="2" stroke={color} strokeWidth="2" />
|
|
2125
|
+
<Rect x="9" y="9" width="6" height="6" stroke={color} strokeWidth="2" />
|
|
2126
|
+
<Path
|
|
2127
|
+
d="M9 1v3M15 1v3M9 20v3M15 20v3M20 9h3M20 14h3M1 9h3M1 14h3"
|
|
2128
|
+
stroke={color}
|
|
2129
|
+
strokeWidth="2"
|
|
2130
|
+
strokeLinecap="round"
|
|
2131
|
+
/>
|
|
2132
|
+
</Svg>
|
|
2133
|
+
);
|
|
2134
|
+
|
|
2135
|
+
export const WifiIcon = ({
|
|
2136
|
+
color = AppColors.grayTextWeak,
|
|
2137
|
+
size = 14,
|
|
2138
|
+
}: IconProps) => (
|
|
2139
|
+
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
2140
|
+
<Path
|
|
2141
|
+
d="M5 12.55a11 11 0 0 1 14.08 0M1.42 9a16 16 0 0 1 21.16 0M8.53 16.11a6 6 0 0 1 6.95 0M12 20h.01"
|
|
2142
|
+
stroke={color}
|
|
2143
|
+
strokeWidth="2"
|
|
2144
|
+
strokeLinecap="round"
|
|
2145
|
+
/>
|
|
2146
|
+
</Svg>
|
|
2147
|
+
);
|
|
2148
|
+
|
|
2149
|
+
export const ShieldCheckIcon = ({
|
|
2150
|
+
color = AppColors.grayTextWeak,
|
|
2151
|
+
size = 14,
|
|
2152
|
+
}: IconProps) => (
|
|
2153
|
+
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
2154
|
+
<Path
|
|
2155
|
+
d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"
|
|
2156
|
+
stroke={color}
|
|
2157
|
+
strokeWidth="2"
|
|
2158
|
+
strokeLinecap="round"
|
|
2159
|
+
strokeLinejoin="round"
|
|
2160
|
+
/>
|
|
2161
|
+
<Path
|
|
2162
|
+
d="M9 12l2 2 4-4"
|
|
2163
|
+
stroke={color}
|
|
2164
|
+
strokeWidth="2"
|
|
2165
|
+
strokeLinecap="round"
|
|
2166
|
+
strokeLinejoin="round"
|
|
2167
|
+
/>
|
|
2168
|
+
</Svg>
|
|
2169
|
+
);
|
|
2170
|
+
|
|
2171
|
+
export const DatabaseIcon = ({
|
|
2172
|
+
color = AppColors.grayTextWeak,
|
|
2173
|
+
size = 14,
|
|
2174
|
+
}: IconProps) => (
|
|
2175
|
+
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
2176
|
+
<Ellipse cx="12" cy="5" rx="9" ry="3" stroke={color} strokeWidth="2" />
|
|
2177
|
+
<Path
|
|
2178
|
+
d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"
|
|
2179
|
+
stroke={color}
|
|
2180
|
+
strokeWidth="2"
|
|
2181
|
+
strokeLinecap="round"
|
|
2182
|
+
/>
|
|
2183
|
+
<Path
|
|
2184
|
+
d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"
|
|
2185
|
+
stroke={color}
|
|
2186
|
+
strokeWidth="2"
|
|
2187
|
+
strokeLinecap="round"
|
|
2188
|
+
/>
|
|
2189
|
+
</Svg>
|
|
2190
|
+
);
|
|
2191
|
+
|
|
2192
|
+
export const PencilIcon = ({
|
|
2193
|
+
color = AppColors.grayTextWeak,
|
|
2194
|
+
size = 14,
|
|
2195
|
+
}: IconProps) => (
|
|
2196
|
+
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
2197
|
+
<Path
|
|
2198
|
+
d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z"
|
|
2199
|
+
stroke={color}
|
|
2200
|
+
strokeWidth="2"
|
|
2201
|
+
strokeLinecap="round"
|
|
2202
|
+
strokeLinejoin="round"
|
|
2203
|
+
/>
|
|
2204
|
+
</Svg>
|
|
2205
|
+
);
|
|
2206
|
+
|
|
2207
|
+
export const PlusIcon = ({
|
|
2208
|
+
color = AppColors.grayTextWeak,
|
|
2209
|
+
size = 14,
|
|
2210
|
+
}: IconProps) => (
|
|
2211
|
+
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
2212
|
+
<Path
|
|
2213
|
+
d="M12 5v14M5 12h14"
|
|
2214
|
+
stroke={color}
|
|
2215
|
+
strokeWidth="2"
|
|
2216
|
+
strokeLinecap="round"
|
|
2217
|
+
strokeLinejoin="round"
|
|
2218
|
+
/>
|
|
2219
|
+
</Svg>
|
|
2220
|
+
);
|
|
2221
|
+
|
package/src/constants/version.ts
CHANGED
|
@@ -120,8 +120,9 @@ export const getBundleModuleEnabled = () => isBundleModuleEnabled;
|
|
|
120
120
|
const getSourceCodeModule = (): any => {
|
|
121
121
|
try {
|
|
122
122
|
const legacy = NativeModules?.SourceCode;
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
const scriptURL = legacy?.scriptURL || legacy?.getConstants?.()?.scriptURL;
|
|
124
|
+
if (typeof scriptURL === 'string' && scriptURL.length > 0) {
|
|
125
|
+
return {scriptURL};
|
|
125
126
|
}
|
|
126
127
|
} catch {}
|
|
127
128
|
try {
|
|
@@ -203,11 +204,11 @@ const extractHostAndPort = (
|
|
|
203
204
|
|
|
204
205
|
const probeCandidateUrlsInParallel = async (
|
|
205
206
|
scriptURL: string,
|
|
206
|
-
timeoutMs =
|
|
207
|
+
timeoutMs = 3000,
|
|
207
208
|
): Promise<{text: string; bytes: number; url: string} | null> => {
|
|
208
209
|
const {host: extractedHost, port: extractedPort} = extractHostAndPort(scriptURL);
|
|
209
210
|
|
|
210
|
-
// 1. If we have a direct scriptURL, try fetching directly
|
|
211
|
+
// 1. If we have a direct HTTP scriptURL, try fetching directly
|
|
211
212
|
if (scriptURL && scriptURL.startsWith('http')) {
|
|
212
213
|
try {
|
|
213
214
|
const controller = new AbortController();
|
|
@@ -227,7 +228,7 @@ const probeCandidateUrlsInParallel = async (
|
|
|
227
228
|
}
|
|
228
229
|
}
|
|
229
230
|
|
|
230
|
-
// 2. Dynamic Port Discovery via lightweight Metro /status
|
|
231
|
+
// 2. Dynamic Port Discovery via parallel lightweight Metro /status probes
|
|
231
232
|
const candidateHosts = extractedHost
|
|
232
233
|
? [extractedHost, 'localhost', '127.0.0.1', ...(Platform.OS === 'android' ? ['10.0.2.2', '10.0.3.2'] : [])]
|
|
233
234
|
: ['localhost', '127.0.0.1', ...(Platform.OS === 'android' ? ['10.0.2.2', '10.0.3.2'] : [])];
|
|
@@ -237,28 +238,52 @@ const probeCandidateUrlsInParallel = async (
|
|
|
237
238
|
? Array.from(new Set([extractedPort, ...DYNAMIC_DEV_PORTS]))
|
|
238
239
|
: DYNAMIC_DEV_PORTS;
|
|
239
240
|
|
|
240
|
-
|
|
241
|
+
const probeTasks: Promise<{host: string; port: number}>[] = [];
|
|
241
242
|
|
|
242
|
-
// Probe lightweight /status on candidate ports (very fast 400ms timeout)
|
|
243
243
|
for (const host of uniqueHosts) {
|
|
244
244
|
for (const port of candidatePorts) {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
245
|
+
probeTasks.push(
|
|
246
|
+
new Promise(async (resolve, reject) => {
|
|
247
|
+
const controller = new AbortController();
|
|
248
|
+
const timer = setTimeout(() => controller.abort(), 700);
|
|
249
|
+
try {
|
|
250
|
+
const res = await fetch(`http://${host}:${port}/status`, {signal: controller.signal});
|
|
251
|
+
clearTimeout(timer);
|
|
252
|
+
if (res.ok) {
|
|
253
|
+
const statusText = await res.text();
|
|
254
|
+
if (statusText && statusText.includes('packager-status:running')) {
|
|
255
|
+
resolve({host, port});
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
} catch {
|
|
260
|
+
clearTimeout(timer);
|
|
255
261
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
262
|
+
reject(new Error('unreachable'));
|
|
263
|
+
}),
|
|
264
|
+
);
|
|
260
265
|
}
|
|
261
|
-
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
let activeServer: {host: string; port: number} | null = null;
|
|
269
|
+
try {
|
|
270
|
+
activeServer = await new Promise<{host: string; port: number}>((resolve, reject) => {
|
|
271
|
+
let pending = probeTasks.length;
|
|
272
|
+
if (pending === 0) {
|
|
273
|
+
reject(new Error('No candidate hosts'));
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
probeTasks.forEach(p => {
|
|
277
|
+
p.then(resolve).catch(() => {
|
|
278
|
+
pending--;
|
|
279
|
+
if (pending === 0) {
|
|
280
|
+
reject(new Error('All probes failed'));
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
} catch {
|
|
286
|
+
activeServer = null;
|
|
262
287
|
}
|
|
263
288
|
|
|
264
289
|
// 3. If a live Metro port was detected dynamically, fetch the bundle from it
|