react-native-inapp-inspector 2.2.8 → 2.3.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 (100) hide show
  1. package/android/src/main/java/com/inappinspector/NetworkInspectorModule.kt +22 -7
  2. package/dist/commonjs/components/AppHeaderLogo.js +45 -12
  3. package/dist/commonjs/components/BrandSquareIcon.js +92 -49
  4. package/dist/commonjs/components/EmptyState.d.ts +7 -2
  5. package/dist/commonjs/components/EmptyState.js +11 -5
  6. package/dist/commonjs/components/Inspector/AnalyticsTab.js +29 -18
  7. package/dist/commonjs/components/Inspector/ConsoleTab.js +6 -1
  8. package/dist/commonjs/components/Inspector/CrashDetail.js +43 -9
  9. package/dist/commonjs/components/Inspector/CrashTab.js +34 -3
  10. package/dist/commonjs/components/Inspector/DeviceInfoTab.js +80 -16
  11. package/dist/commonjs/components/Inspector/InspectorHeader.js +16 -3
  12. package/dist/commonjs/components/Inspector/NetworkDetail.js +3 -2
  13. package/dist/commonjs/components/Inspector/NetworkTab.js +103 -4
  14. package/dist/commonjs/components/Inspector/ReduxTab.js +19 -3
  15. package/dist/commonjs/components/Inspector/SettingsPanel.js +4 -4
  16. package/dist/commonjs/components/Inspector/StorageTab.js +19 -3
  17. package/dist/commonjs/components/JsonViewer.js +2 -0
  18. package/dist/commonjs/components/MetaAccordion.js +15 -3
  19. package/dist/commonjs/constants/version.d.ts +1 -1
  20. package/dist/commonjs/constants/version.js +1 -1
  21. package/dist/commonjs/customHooks/networkLogger.d.ts +3 -0
  22. package/dist/commonjs/customHooks/networkLogger.js +10 -1
  23. package/dist/commonjs/helpers/index.d.ts +6 -0
  24. package/dist/commonjs/helpers/index.js +196 -6
  25. package/dist/commonjs/helpers/searchQueryParser.js +62 -20
  26. package/dist/commonjs/i18n/index.d.ts +13 -0
  27. package/dist/commonjs/i18n/index.js +35 -2
  28. package/dist/commonjs/index.d.ts +3 -0
  29. package/dist/commonjs/index.js +80 -11
  30. package/dist/commonjs/native/NativeInspector.js +13 -0
  31. package/dist/commonjs/native/NativeNetworkInspector.d.ts +1 -1
  32. package/dist/commonjs/styles/AppColors.d.ts +4 -0
  33. package/dist/commonjs/styles/AppColors.js +11 -1
  34. package/dist/commonjs/styles/AppFonts.d.ts +11 -0
  35. package/dist/commonjs/styles/AppFonts.js +11 -1
  36. package/dist/commonjs/types/interfaces.d.ts +1 -0
  37. package/dist/esm/components/AppHeaderLogo.js +45 -12
  38. package/dist/esm/components/BrandSquareIcon.js +92 -49
  39. package/dist/esm/components/EmptyState.d.ts +7 -2
  40. package/dist/esm/components/EmptyState.js +11 -5
  41. package/dist/esm/components/Inspector/AnalyticsTab.js +30 -19
  42. package/dist/esm/components/Inspector/ConsoleTab.js +6 -1
  43. package/dist/esm/components/Inspector/CrashDetail.js +43 -9
  44. package/dist/esm/components/Inspector/CrashTab.js +34 -3
  45. package/dist/esm/components/Inspector/DeviceInfoTab.js +80 -16
  46. package/dist/esm/components/Inspector/InspectorHeader.js +17 -4
  47. package/dist/esm/components/Inspector/NetworkDetail.js +3 -2
  48. package/dist/esm/components/Inspector/NetworkTab.js +103 -4
  49. package/dist/esm/components/Inspector/ReduxTab.js +19 -3
  50. package/dist/esm/components/Inspector/SettingsPanel.js +4 -4
  51. package/dist/esm/components/Inspector/StorageTab.js +19 -3
  52. package/dist/esm/components/JsonViewer.js +2 -0
  53. package/dist/esm/components/MetaAccordion.js +15 -3
  54. package/dist/esm/constants/version.d.ts +1 -1
  55. package/dist/esm/constants/version.js +1 -1
  56. package/dist/esm/customHooks/networkLogger.d.ts +3 -0
  57. package/dist/esm/customHooks/networkLogger.js +8 -0
  58. package/dist/esm/helpers/index.d.ts +6 -0
  59. package/dist/esm/helpers/index.js +193 -5
  60. package/dist/esm/helpers/searchQueryParser.js +62 -20
  61. package/dist/esm/i18n/index.d.ts +13 -0
  62. package/dist/esm/i18n/index.js +33 -3
  63. package/dist/esm/index.d.ts +3 -0
  64. package/dist/esm/index.js +68 -12
  65. package/dist/esm/native/NativeInspector.js +13 -0
  66. package/dist/esm/native/NativeNetworkInspector.d.ts +1 -1
  67. package/dist/esm/styles/AppColors.d.ts +4 -0
  68. package/dist/esm/styles/AppColors.js +9 -0
  69. package/dist/esm/styles/AppFonts.d.ts +11 -0
  70. package/dist/esm/styles/AppFonts.js +9 -0
  71. package/dist/esm/types/interfaces.d.ts +1 -0
  72. package/ios/NetworkInspectorModule.mm +11 -1
  73. package/package.json +1 -1
  74. package/src/components/AppHeaderLogo.tsx +46 -12
  75. package/src/components/BrandSquareIcon.tsx +127 -78
  76. package/src/components/EmptyState.tsx +27 -5
  77. package/src/components/Inspector/AnalyticsTab.tsx +48 -27
  78. package/src/components/Inspector/ConsoleTab.tsx +10 -0
  79. package/src/components/Inspector/CrashDetail.tsx +65 -9
  80. package/src/components/Inspector/CrashTab.tsx +41 -3
  81. package/src/components/Inspector/DeviceInfoTab.tsx +87 -16
  82. package/src/components/Inspector/InspectorHeader.tsx +24 -4
  83. package/src/components/Inspector/NetworkDetail.tsx +4 -4
  84. package/src/components/Inspector/NetworkTab.tsx +129 -4
  85. package/src/components/Inspector/ReduxTab.tsx +26 -8
  86. package/src/components/Inspector/SettingsPanel.tsx +4 -4
  87. package/src/components/Inspector/StorageTab.tsx +21 -3
  88. package/src/components/JsonViewer.tsx +2 -0
  89. package/src/components/MetaAccordion.tsx +18 -3
  90. package/src/constants/version.ts +1 -1
  91. package/src/customHooks/networkLogger.ts +15 -0
  92. package/src/helpers/index.ts +213 -5
  93. package/src/helpers/searchQueryParser.ts +63 -20
  94. package/src/i18n/index.ts +38 -3
  95. package/src/index.tsx +89 -11
  96. package/src/native/NativeInspector.ts +13 -0
  97. package/src/native/NativeNetworkInspector.ts +1 -1
  98. package/src/styles/AppColors.ts +9 -0
  99. package/src/styles/AppFonts.ts +16 -0
  100. package/src/types/interfaces.ts +1 -0
@@ -17,7 +17,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.getRuntimeDiagnostics = exports.getCategoryColors = exports.registerGAPlugin = exports.getEventCategory = exports.getEventColor = exports.ANALYTICS_EVENT_PALETTE = exports.openInVSCode = exports.parseStackLine = exports.getJsonPreviewText = exports.getJsonContent = exports.formatGap = exports.formatTime = exports.formatTimeShort = exports.handleOpenExternalLink = exports.getAppName = exports.getBundleIdentifier = exports.formatDateTimeToAnalytics = exports.isAllValuesEmpty = exports.getLocalizedFilePathWithSlash = exports.getLocalizedFilePath = exports.formatDisplayUrl = exports.getDiff = exports.flattenObject = exports.getNavigationInfo = exports.escapeRegex = exports.deduplicateLogs = exports.getFetchCommand = exports.getCurlCommand = exports.getBaseUrl = exports.getPath = exports.copyToClipboard = exports.getSize = exports.getDurationColor = exports.getStatusColor = exports.formatTimestamp = exports.formatDateTime = exports.getDomainColor = void 0;
20
+ exports.getRuntimeDiagnostics = exports.getCategoryColors = exports.registerGAPlugin = exports.getEventCategory = exports.getEventColor = exports.ANALYTICS_EVENT_PALETTE = exports.openInVSCode = exports.parseStackLine = exports.getJsonPreviewText = exports.getJsonContent = exports.formatGap = exports.formatTime = exports.formatTimeShort = exports.handleOpenExternalLink = exports.getAppVersionAndBuild = exports.getAppName = exports.getBundleIdentifier = exports.formatDateTimeToAnalytics = exports.isAllValuesEmpty = exports.getLocalizedFilePathWithSlash = exports.getLocalizedFilePath = exports.formatDisplayUrl = exports.getDiff = exports.flattenObject = exports.getLogPageName = exports.getNavigationInfo = exports.escapeRegex = exports.deduplicateLogs = exports.getFetchCommand = exports.getCurlCommand = exports.getBaseUrl = exports.getPath = exports.copyToClipboard = exports.getSize = exports.getDurationColor = exports.getStatusColor = exports.formatTimestamp = exports.formatDateTime = exports.getDomainColor = void 0;
21
21
  const react_native_1 = require("react-native");
22
22
  const clipboard_1 = __importDefault(require("@react-native-clipboard/clipboard"));
23
23
  const toast_1 = require("./toast");
@@ -210,16 +210,33 @@ const escapeRegex = (str) => {
210
210
  };
211
211
  exports.escapeRegex = escapeRegex;
212
212
  const getNavigationInfo = (state, path = []) => {
213
- if (!state?.routes) {
213
+ if (!state) {
214
214
  return {
215
- path: path.length > 0 ? path.join(' ➔ ') : 'Navigators',
215
+ path: path.length > 0 ? path.join(' ➔ ') : '',
216
216
  params: null,
217
217
  };
218
218
  }
219
- const route = state.routes[state.index ?? 0];
219
+ if (state.name && !state.routes) {
220
+ const fullPath = path.length > 0 ? [...path, state.name].join(' ➔ ') : state.name;
221
+ return { path: fullPath, params: state.params || null };
222
+ }
223
+ if (!state.routes ||
224
+ !Array.isArray(state.routes) ||
225
+ state.routes.length === 0) {
226
+ return {
227
+ path: path.length > 0 ? path.join(' ➔ ') : '',
228
+ params: null,
229
+ };
230
+ }
231
+ const index = typeof state.index === 'number' &&
232
+ state.index >= 0 &&
233
+ state.index < state.routes.length
234
+ ? state.index
235
+ : 0;
236
+ const route = state.routes[index];
220
237
  if (!route) {
221
238
  return {
222
- path: path.length > 0 ? path.join(' ➔ ') : 'Navigators',
239
+ path: path.length > 0 ? path.join(' ➔ ') : '',
223
240
  params: null,
224
241
  };
225
242
  }
@@ -227,10 +244,89 @@ const getNavigationInfo = (state, path = []) => {
227
244
  if (route?.state) {
228
245
  return (0, exports.getNavigationInfo)(route.state, currentPath);
229
246
  }
230
- const resolved = currentPath.length > 0 ? currentPath.join(' ➔ ') : 'Navigators';
247
+ const resolved = currentPath.length > 0 ? currentPath.join(' ➔ ') : route.name || '';
231
248
  return { path: resolved, params: route.params || null };
232
249
  };
233
250
  exports.getNavigationInfo = getNavigationInfo;
251
+ const getLogPageName = (log, routeInfo) => {
252
+ // 1. If routeInfo has a valid path, resolve the leaf screen name
253
+ const effectiveRoute = routeInfo || log?.routeInfo;
254
+ if (effectiveRoute &&
255
+ effectiveRoute.path &&
256
+ effectiveRoute.path !== 'Navigators') {
257
+ const parts = effectiveRoute.path
258
+ .split(' ➔ ')
259
+ .map((s) => s.trim())
260
+ .filter(Boolean);
261
+ if (parts.length > 0) {
262
+ return parts[parts.length - 1]; // Leaf screen name, e.g. "HomeScreen", "ProfileScreen"
263
+ }
264
+ return effectiveRoute.path;
265
+ }
266
+ // 2. Extract screen / component name from log.caller stack trace
267
+ if (log.caller && log.caller !== 'Unknown') {
268
+ try {
269
+ const match = log.caller.match(/([^/\\]+)\.(tsx|jsx|ts|js)/i);
270
+ if (match && match[1]) {
271
+ const file = match[1];
272
+ const ignored = [
273
+ 'networklogger',
274
+ 'fetch',
275
+ 'axios',
276
+ 'apiclient',
277
+ 'request',
278
+ 'http',
279
+ 'index',
280
+ 'nativeinspector',
281
+ 'inappinspector',
282
+ 'bundleanalyzer',
283
+ ];
284
+ if (!ignored.includes(file.toLowerCase())) {
285
+ return file;
286
+ }
287
+ }
288
+ }
289
+ catch (e) { }
290
+ }
291
+ // 3. Fallback to API resource / endpoint category from URL
292
+ if (log.url) {
293
+ try {
294
+ const cleanUrl = log.url.split('?')[0].split('#')[0];
295
+ const withoutProto = cleanUrl.replace(/^https?:\/\//i, '');
296
+ const slashIdx = withoutProto.indexOf('/');
297
+ if (slashIdx !== -1) {
298
+ const pathSegments = withoutProto
299
+ .substring(slashIdx + 1)
300
+ .split('/')
301
+ .filter(Boolean);
302
+ const ignoredSegments = [
303
+ 'api',
304
+ 'v1',
305
+ 'v2',
306
+ 'v3',
307
+ 'v4',
308
+ 'rest',
309
+ 'graphql',
310
+ 'json',
311
+ 'data',
312
+ 'service',
313
+ 'app',
314
+ ];
315
+ const meaningful = pathSegments.filter(s => !ignoredSegments.includes(s.toLowerCase()));
316
+ if (meaningful.length > 0) {
317
+ const seg = meaningful[0];
318
+ return seg.charAt(0).toUpperCase() + seg.slice(1);
319
+ }
320
+ }
321
+ const host = withoutProto.split('/')[0];
322
+ if (host)
323
+ return host;
324
+ }
325
+ catch (e) { }
326
+ }
327
+ return 'General';
328
+ };
329
+ exports.getLogPageName = getLogPageName;
234
330
  const flattenObject = (obj, prefix = '') => {
235
331
  let result = {};
236
332
  if (typeof obj === 'object' && obj !== null) {
@@ -394,6 +490,100 @@ const getAppName = () => {
394
490
  return 'App';
395
491
  };
396
492
  exports.getAppName = getAppName;
493
+ const getAppVersionAndBuild = () => {
494
+ let version = '';
495
+ let build = '';
496
+ // 1. Try ExpoApplication / ExponentConstants
497
+ const ExpoApplication = react_native_1.NativeModules.ExpoApplication;
498
+ if (ExpoApplication) {
499
+ if (typeof ExpoApplication.nativeAppVersion === 'string') {
500
+ version = ExpoApplication.nativeAppVersion;
501
+ }
502
+ if (typeof ExpoApplication.nativeBuildVersion === 'string') {
503
+ build = ExpoApplication.nativeBuildVersion;
504
+ }
505
+ }
506
+ const ExponentConstants = react_native_1.NativeModules.ExponentConstants;
507
+ if (ExponentConstants) {
508
+ const manifest = ExponentConstants.manifest || ExponentConstants.expoConfig;
509
+ if (manifest) {
510
+ if (!version && manifest.version) {
511
+ version = String(manifest.version);
512
+ }
513
+ if (!build) {
514
+ if (manifest.ios?.buildNumber) {
515
+ build = String(manifest.ios.buildNumber);
516
+ }
517
+ else if (manifest.android?.versionCode) {
518
+ build = String(manifest.android.versionCode);
519
+ }
520
+ }
521
+ }
522
+ }
523
+ // 2. Try react-native-device-info
524
+ const RNDeviceInfo = react_native_1.NativeModules.RNDeviceInfo;
525
+ if (RNDeviceInfo) {
526
+ if (!version) {
527
+ if (typeof RNDeviceInfo.appVersion === 'string') {
528
+ version = RNDeviceInfo.appVersion;
529
+ }
530
+ else if (typeof RNDeviceInfo.getVersion === 'function') {
531
+ try {
532
+ version = RNDeviceInfo.getVersion();
533
+ }
534
+ catch (e) { }
535
+ }
536
+ }
537
+ if (!build) {
538
+ if (typeof RNDeviceInfo.buildNumber === 'string') {
539
+ build = RNDeviceInfo.buildNumber;
540
+ }
541
+ else if (typeof RNDeviceInfo.getBuildNumber === 'function') {
542
+ try {
543
+ build = RNDeviceInfo.getBuildNumber();
544
+ }
545
+ catch (e) { }
546
+ }
547
+ }
548
+ }
549
+ // 3. Try PlatformConstants / Platform.constants
550
+ const constants = react_native_1.Platform.constants || react_native_1.NativeModules.PlatformConstants;
551
+ if (constants) {
552
+ if (!version &&
553
+ constants.Version &&
554
+ typeof constants.Version === 'string' &&
555
+ constants.Version.includes('.')) {
556
+ version = constants.Version;
557
+ }
558
+ if (!version && constants.reactNativeVersion) {
559
+ const rnv = constants.reactNativeVersion;
560
+ if (rnv.major !== undefined) {
561
+ version = `${rnv.major}.${rnv.minor}.${rnv.patch}`;
562
+ }
563
+ }
564
+ }
565
+ // 4. Try Android AppInfo
566
+ const AppInfo = react_native_1.NativeModules.AppInfo;
567
+ if (AppInfo) {
568
+ if (!version && typeof AppInfo.versionName === 'string') {
569
+ version = AppInfo.versionName;
570
+ }
571
+ if (!build && typeof AppInfo.versionCode === 'string') {
572
+ build = AppInfo.versionCode;
573
+ }
574
+ }
575
+ // Fallbacks
576
+ if (!version)
577
+ version = '1.0.0';
578
+ if (!build)
579
+ build = '1';
580
+ return {
581
+ version,
582
+ build,
583
+ formatted: `${version} (${build})`,
584
+ };
585
+ };
586
+ exports.getAppVersionAndBuild = getAppVersionAndBuild;
397
587
  const handleOpenExternalLink = (url) => {
398
588
  if (!url)
399
589
  return;
@@ -8,7 +8,8 @@ exports.matchNetworkLogQuery = matchNetworkLogQuery;
8
8
  function matchNetworkLogQuery(log, searchQuery, routePath, options) {
9
9
  if (!searchQuery || searchQuery.trim().length === 0)
10
10
  return true;
11
- const rawTokens = searchQuery.trim().match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g) || [];
11
+ // Split tokens by spaces or commas while respecting quotes
12
+ const rawTokens = searchQuery.trim().match(/(?:[^\s,"']+|"[^"]*"|'[^']*')+/g) || [];
12
13
  if (rawTokens.length === 0)
13
14
  return true;
14
15
  const isCaseSensitive = Boolean(options?.isCaseSensitive);
@@ -18,24 +19,35 @@ function matchNetworkLogQuery(log, searchQuery, routePath, options) {
18
19
  const urlRaw = log.url || '';
19
20
  const statusNum = typeof log.status === 'number'
20
21
  ? log.status
21
- : parseInt(String(log.status || 0), 10);
22
- const statusStr = String(log.status ?? '');
22
+ : log.status != null
23
+ ? parseInt(String(log.status), 10)
24
+ : null;
25
+ const statusStr = log.status != null ? String(log.status) : 'pending';
23
26
  const durationNum = log.duration || 0;
24
27
  const clientRaw = log.client || '';
28
+ const callerRaw = log.caller || '';
25
29
  const reqRaw = typeof log.request === 'string'
26
30
  ? log.request
27
- : JSON.stringify(log.request || '');
31
+ : log.request != null
32
+ ? JSON.stringify(log.request)
33
+ : '';
28
34
  const resRaw = typeof log.response === 'string'
29
35
  ? log.response
30
- : JSON.stringify(log.response || '');
31
- const reqHeadersRaw = JSON.stringify(log.requestHeaders || '');
32
- const resHeadersRaw = JSON.stringify(log.responseHeaders || '');
33
- const pathRaw = routePath || '';
36
+ : log.response != null
37
+ ? JSON.stringify(log.response)
38
+ : '';
39
+ const reqHeadersRaw = log.requestHeaders
40
+ ? JSON.stringify(log.requestHeaders)
41
+ : '';
42
+ const resHeadersRaw = log.responseHeaders
43
+ ? JSON.stringify(log.responseHeaders)
44
+ : '';
45
+ const pathRaw = routePath || log?.routeInfo?.path || '';
34
46
  // Construct search corpus based on active scope
35
47
  const getScopedCorpus = (caseSens) => {
36
48
  let parts = [];
37
49
  if (scope === 'url') {
38
- parts = [methodRaw, urlRaw, pathRaw];
50
+ parts = [methodRaw, urlRaw, pathRaw, callerRaw];
39
51
  }
40
52
  else if (scope === 'reqBody') {
41
53
  parts = [reqRaw];
@@ -52,6 +64,7 @@ function matchNetworkLogQuery(log, searchQuery, routePath, options) {
52
64
  urlRaw,
53
65
  statusStr,
54
66
  pathRaw,
67
+ callerRaw,
55
68
  clientRaw,
56
69
  reqRaw,
57
70
  resRaw,
@@ -66,6 +79,7 @@ function matchNetworkLogQuery(log, searchQuery, routePath, options) {
66
79
  const methodStr = methodRaw.toLowerCase();
67
80
  const urlStr = urlRaw.toLowerCase();
68
81
  const clientStr = clientRaw.toLowerCase();
82
+ const callerStr = callerRaw.toLowerCase();
69
83
  const reqStr = reqRaw.toLowerCase();
70
84
  const resStr = resRaw.toLowerCase();
71
85
  const reqHeadersStr = reqHeadersRaw.toLowerCase();
@@ -92,24 +106,28 @@ function matchNetworkLogQuery(log, searchQuery, routePath, options) {
92
106
  // 2. status:<VAL> or s:<VAL>
93
107
  if (lowerToken.startsWith('status:') || lowerToken.startsWith('s:')) {
94
108
  const val = lowerToken.replace(/^(status:|s:)/, '').trim();
95
- if (val.startsWith('>=')) {
109
+ if (val === 'pending' || val === 'loading') {
110
+ if (log.status != null)
111
+ return false;
112
+ }
113
+ else if (val.startsWith('>=')) {
96
114
  const threshold = parseInt(val.slice(2), 10);
97
- if (isNaN(threshold) || statusNum < threshold)
115
+ if (isNaN(threshold) || statusNum === null || statusNum < threshold)
98
116
  return false;
99
117
  }
100
118
  else if (val.startsWith('>')) {
101
119
  const threshold = parseInt(val.slice(1), 10);
102
- if (isNaN(threshold) || statusNum <= threshold)
120
+ if (isNaN(threshold) || statusNum === null || statusNum <= threshold)
103
121
  return false;
104
122
  }
105
123
  else if (val.startsWith('<=')) {
106
124
  const threshold = parseInt(val.slice(2), 10);
107
- if (isNaN(threshold) || statusNum > threshold)
125
+ if (isNaN(threshold) || statusNum === null || statusNum > threshold)
108
126
  return false;
109
127
  }
110
128
  else if (val.startsWith('<')) {
111
129
  const threshold = parseInt(val.slice(1), 10);
112
- if (isNaN(threshold) || statusNum >= threshold)
130
+ if (isNaN(threshold) || statusNum === null || statusNum >= threshold)
113
131
  return false;
114
132
  }
115
133
  else if (val.endsWith('xx') || val.endsWith('x')) {
@@ -136,15 +154,19 @@ function matchNetworkLogQuery(log, searchQuery, routePath, options) {
136
154
  flag === 'failed' ||
137
155
  flag === 'err' ||
138
156
  flag === 'fail') {
139
- const isErr = log.status === 0 || log.status == null || statusNum >= 400;
157
+ const isErr = log.status === 0 || (statusNum !== null && statusNum >= 400);
140
158
  if (!isErr)
141
159
  return false;
142
160
  }
143
161
  else if (flag === 'success' || flag === 'ok' || flag === '2xx') {
144
- const isSuccess = statusNum >= 200 && statusNum < 300;
162
+ const isSuccess = statusNum !== null && statusNum >= 200 && statusNum < 300;
145
163
  if (!isSuccess)
146
164
  return false;
147
165
  }
166
+ else if (flag === 'pending' || flag === 'loading') {
167
+ if (log.status != null)
168
+ return false;
169
+ }
148
170
  else if (flag === 'slow') {
149
171
  if (durationNum < 1000)
150
172
  return false;
@@ -175,6 +197,12 @@ function matchNetworkLogQuery(log, searchQuery, routePath, options) {
175
197
  if (!isJson)
176
198
  return false;
177
199
  }
200
+ else if (flag === 'image') {
201
+ const isImg = resHeadersStr.includes('image/') ||
202
+ /\.(png|jpe?g|gif|webp|svg)/i.test(urlStr);
203
+ if (!isImg)
204
+ return false;
205
+ }
178
206
  continue;
179
207
  }
180
208
  // 4. slow:<DURATION> or dur:<DURATION> or duration:<DURATION>
@@ -236,10 +264,16 @@ function matchNetworkLogQuery(log, searchQuery, routePath, options) {
236
264
  return false;
237
265
  continue;
238
266
  }
239
- // 7. path:<PATH> or p:<PATH>
240
- if (lowerToken.startsWith('path:') || lowerToken.startsWith('p:')) {
241
- const targetPath = lowerToken.replace(/^(path:|p:)/, '').trim();
242
- if (!urlStr.includes(targetPath) && !pathStr.includes(targetPath)) {
267
+ // 7. path:<PATH> or p:<PATH> or page:<PAGE>
268
+ if (lowerToken.startsWith('path:') ||
269
+ lowerToken.startsWith('p:') ||
270
+ lowerToken.startsWith('page:')) {
271
+ const targetPath = lowerToken
272
+ .replace(/^(path:|p:|page:)/, '')
273
+ .trim();
274
+ if (!urlStr.includes(targetPath) &&
275
+ !pathStr.includes(targetPath) &&
276
+ !callerStr.includes(targetPath)) {
243
277
  return false;
244
278
  }
245
279
  continue;
@@ -282,6 +316,14 @@ function matchNetworkLogQuery(log, searchQuery, routePath, options) {
282
316
  else {
283
317
  const queryTerm = isCaseSensitive ? token : lowerToken;
284
318
  if (!targetCorpus.includes(queryTerm)) {
319
+ // Special case: if user typed "error" / "failed", check error status
320
+ if (queryTerm === 'error' ||
321
+ queryTerm === 'failed' ||
322
+ queryTerm === 'fail') {
323
+ const isErr = log.status === 0 || (statusNum !== null && statusNum >= 400);
324
+ if (isErr)
325
+ continue;
326
+ }
285
327
  return false;
286
328
  }
287
329
  }
@@ -4,9 +4,17 @@ type TranslationParams = Record<string, any>;
4
4
  * Standalone zero-dependency translation function
5
5
  */
6
6
  export declare function t(key: string, optionsOrFallback?: TranslationParams | string): string;
7
+ export declare function setLanguage(lang: string): void;
8
+ export declare function addTranslations(lang: string, translations: Record<string, any>): void;
9
+ export declare function setTranslations(translations: Record<string, any>, lang?: string): void;
7
10
  export declare const i18n: {
8
11
  t: typeof t;
9
12
  language: string;
13
+ changeLanguage: typeof setLanguage;
14
+ addResourceBundle: (lng: string, _ns: string, resources: any) => void;
15
+ setLanguage: typeof setLanguage;
16
+ addTranslations: typeof addTranslations;
17
+ setTranslations: typeof setTranslations;
10
18
  };
11
19
  /**
12
20
  * React hook compatible with react-i18next useTranslation()
@@ -16,6 +24,11 @@ export declare function useTranslation(): {
16
24
  i18n: {
17
25
  t: typeof t;
18
26
  language: string;
27
+ changeLanguage: typeof setLanguage;
28
+ addResourceBundle: (lng: string, _ns: string, resources: any) => void;
29
+ setLanguage: typeof setLanguage;
30
+ addTranslations: typeof addTranslations;
31
+ setTranslations: typeof setTranslations;
19
32
  };
20
33
  };
21
34
  /**
@@ -5,9 +5,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.I18nextProvider = exports.i18n = void 0;
7
7
  exports.t = t;
8
+ exports.setLanguage = setLanguage;
9
+ exports.addTranslations = addTranslations;
10
+ exports.setTranslations = setTranslations;
8
11
  exports.useTranslation = useTranslation;
9
12
  const react_1 = __importDefault(require("react"));
10
13
  const en_json_1 = __importDefault(require("./locales/en.json"));
14
+ const localeRegistry = {
15
+ en: en_json_1.default,
16
+ };
17
+ let currentLanguage = 'en';
11
18
  /**
12
19
  * Lightweight nested lookup for translation keys (e.g. "network.headers")
13
20
  */
@@ -37,7 +44,11 @@ function interpolate(template, params) {
37
44
  * Standalone zero-dependency translation function
38
45
  */
39
46
  function t(key, optionsOrFallback) {
40
- const raw = lookupKey(en_json_1.default, key);
47
+ const activeBundle = localeRegistry[currentLanguage] || localeRegistry.en;
48
+ let raw = lookupKey(activeBundle, key);
49
+ if (raw === undefined && currentLanguage !== 'en') {
50
+ raw = lookupKey(localeRegistry.en, key);
51
+ }
41
52
  if (typeof raw === 'string') {
42
53
  if (typeof optionsOrFallback === 'object' && optionsOrFallback !== null) {
43
54
  return interpolate(raw, optionsOrFallback);
@@ -49,9 +60,31 @@ function t(key, optionsOrFallback) {
49
60
  }
50
61
  return key;
51
62
  }
63
+ function setLanguage(lang) {
64
+ if (typeof lang === 'string' && lang.trim()) {
65
+ currentLanguage = lang.trim();
66
+ exports.i18n.language = currentLanguage;
67
+ }
68
+ }
69
+ function addTranslations(lang, translations) {
70
+ if (!lang || !translations || typeof translations !== 'object')
71
+ return;
72
+ localeRegistry[lang] = {
73
+ ...(localeRegistry[lang] || {}),
74
+ ...translations,
75
+ };
76
+ }
77
+ function setTranslations(translations, lang = 'en') {
78
+ addTranslations(lang, translations);
79
+ }
52
80
  exports.i18n = {
53
81
  t,
54
- language: 'en',
82
+ language: currentLanguage,
83
+ changeLanguage: setLanguage,
84
+ addResourceBundle: (lng, _ns, resources) => addTranslations(lng, resources),
85
+ setLanguage,
86
+ addTranslations,
87
+ setTranslations,
55
88
  };
56
89
  /**
57
90
  * React hook compatible with react-i18next useTranslation()
@@ -23,3 +23,6 @@ export { setMaxPerformanceEventsLimit, getMaxPerformanceEventsLimit, prunePerfor
23
23
  export { BrandSquareIcon, BrandCircleIcon, } from './components/NetworkIcons';
24
24
  export { connectAsyncStorage, connectMMKV, isAsyncStorageConnected, isMMKVConnected, getRegisteredMMKVInstanceIds, fetchStorageEntries, setStorageEntry, removeStorageEntry, clearStorageDriver, subscribeToStorageChanges, type StorageEntry, type StorageDriver, } from './customHooks/storageInspector';
25
25
  export { ActiveTab, Method, StatusFilter, SortOrder, LocalFilter, ModalAnimationType, SettingsPage, SettingsSubTab, LogFilter, ConsoleLogType, AnalyticsEventSource, GAEventCategory, StackFrameType, DiffResultType, BundleSubTab, PerformanceSubTab, CrashType, CrashExportFormat, CrashDetailSubTab, CrashFilterType, BreadcrumbType, } from './types';
26
+ export { AppFonts, setAppFonts, type AppFontConfig, } from './styles/AppFonts';
27
+ export { AppColors, setAppColors, getThemeColors, updateAppColorsTheme, } from './styles/AppColors';
28
+ export { t, i18n, useTranslation, setLanguage, addTranslations, setTranslations, I18nextProvider, } from './i18n';