react-native-inapp-inspector 2.2.9 → 2.3.1

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 (105) hide show
  1. package/dist/commonjs/components/AppHeaderLogo.js +45 -12
  2. package/dist/commonjs/components/BrandSquareIcon.js +92 -49
  3. package/dist/commonjs/components/EmptyState.d.ts +7 -2
  4. package/dist/commonjs/components/EmptyState.js +11 -5
  5. package/dist/commonjs/components/Inspector/AnalyticsTab.js +29 -18
  6. package/dist/commonjs/components/Inspector/ConsoleTab.js +6 -1
  7. package/dist/commonjs/components/Inspector/CrashDetail.js +43 -9
  8. package/dist/commonjs/components/Inspector/CrashTab.js +34 -3
  9. package/dist/commonjs/components/Inspector/DeviceInfoTab.js +80 -16
  10. package/dist/commonjs/components/Inspector/InspectorHeader.js +16 -3
  11. package/dist/commonjs/components/Inspector/MainScreen.js +7 -11
  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 +123 -92
  17. package/dist/commonjs/components/JsonViewer.js +2 -0
  18. package/dist/commonjs/components/MetaAccordion.js +15 -3
  19. package/dist/commonjs/components/SkeletonPlaceholder.d.ts +6 -0
  20. package/dist/commonjs/components/SkeletonPlaceholder.js +208 -0
  21. package/dist/commonjs/constants/version.d.ts +1 -1
  22. package/dist/commonjs/constants/version.js +1 -1
  23. package/dist/commonjs/customHooks/networkLogger.d.ts +3 -0
  24. package/dist/commonjs/customHooks/networkLogger.js +10 -1
  25. package/dist/commonjs/customHooks/storageInspector.d.ts +2 -2
  26. package/dist/commonjs/customHooks/storageInspector.js +17 -13
  27. package/dist/commonjs/helpers/index.d.ts +6 -0
  28. package/dist/commonjs/helpers/index.js +196 -6
  29. package/dist/commonjs/helpers/searchQueryParser.js +62 -20
  30. package/dist/commonjs/i18n/index.d.ts +13 -0
  31. package/dist/commonjs/i18n/index.js +35 -2
  32. package/dist/commonjs/index.d.ts +3 -0
  33. package/dist/commonjs/index.js +108 -35
  34. package/dist/commonjs/styles/AppColors.d.ts +4 -0
  35. package/dist/commonjs/styles/AppColors.js +11 -1
  36. package/dist/commonjs/styles/AppFonts.d.ts +11 -0
  37. package/dist/commonjs/styles/AppFonts.js +11 -1
  38. package/dist/commonjs/types/interfaces.d.ts +2 -2
  39. package/dist/esm/components/AppHeaderLogo.js +45 -12
  40. package/dist/esm/components/BrandSquareIcon.js +92 -49
  41. package/dist/esm/components/EmptyState.d.ts +7 -2
  42. package/dist/esm/components/EmptyState.js +11 -5
  43. package/dist/esm/components/Inspector/AnalyticsTab.js +30 -19
  44. package/dist/esm/components/Inspector/ConsoleTab.js +6 -1
  45. package/dist/esm/components/Inspector/CrashDetail.js +43 -9
  46. package/dist/esm/components/Inspector/CrashTab.js +34 -3
  47. package/dist/esm/components/Inspector/DeviceInfoTab.js +80 -16
  48. package/dist/esm/components/Inspector/InspectorHeader.js +17 -4
  49. package/dist/esm/components/Inspector/MainScreen.js +8 -12
  50. package/dist/esm/components/Inspector/NetworkDetail.js +3 -2
  51. package/dist/esm/components/Inspector/NetworkTab.js +103 -4
  52. package/dist/esm/components/Inspector/ReduxTab.js +19 -3
  53. package/dist/esm/components/Inspector/SettingsPanel.js +4 -4
  54. package/dist/esm/components/Inspector/StorageTab.js +124 -93
  55. package/dist/esm/components/JsonViewer.js +2 -0
  56. package/dist/esm/components/MetaAccordion.js +15 -3
  57. package/dist/esm/components/SkeletonPlaceholder.d.ts +6 -0
  58. package/dist/esm/components/SkeletonPlaceholder.js +173 -0
  59. package/dist/esm/constants/version.d.ts +1 -1
  60. package/dist/esm/constants/version.js +1 -1
  61. package/dist/esm/customHooks/networkLogger.d.ts +3 -0
  62. package/dist/esm/customHooks/networkLogger.js +8 -0
  63. package/dist/esm/customHooks/storageInspector.d.ts +2 -2
  64. package/dist/esm/customHooks/storageInspector.js +17 -13
  65. package/dist/esm/helpers/index.d.ts +6 -0
  66. package/dist/esm/helpers/index.js +193 -5
  67. package/dist/esm/helpers/searchQueryParser.js +62 -20
  68. package/dist/esm/i18n/index.d.ts +13 -0
  69. package/dist/esm/i18n/index.js +33 -3
  70. package/dist/esm/index.d.ts +3 -0
  71. package/dist/esm/index.js +97 -37
  72. package/dist/esm/styles/AppColors.d.ts +4 -0
  73. package/dist/esm/styles/AppColors.js +9 -0
  74. package/dist/esm/styles/AppFonts.d.ts +11 -0
  75. package/dist/esm/styles/AppFonts.js +9 -0
  76. package/dist/esm/types/interfaces.d.ts +2 -2
  77. package/package.json +1 -1
  78. package/src/components/AppHeaderLogo.tsx +46 -12
  79. package/src/components/BrandSquareIcon.tsx +127 -78
  80. package/src/components/EmptyState.tsx +27 -5
  81. package/src/components/Inspector/AnalyticsTab.tsx +48 -27
  82. package/src/components/Inspector/ConsoleTab.tsx +10 -0
  83. package/src/components/Inspector/CrashDetail.tsx +65 -9
  84. package/src/components/Inspector/CrashTab.tsx +41 -3
  85. package/src/components/Inspector/DeviceInfoTab.tsx +87 -16
  86. package/src/components/Inspector/InspectorHeader.tsx +24 -4
  87. package/src/components/Inspector/MainScreen.tsx +7 -11
  88. package/src/components/Inspector/NetworkDetail.tsx +4 -4
  89. package/src/components/Inspector/NetworkTab.tsx +129 -4
  90. package/src/components/Inspector/ReduxTab.tsx +26 -8
  91. package/src/components/Inspector/SettingsPanel.tsx +4 -4
  92. package/src/components/Inspector/StorageTab.tsx +191 -117
  93. package/src/components/JsonViewer.tsx +2 -0
  94. package/src/components/MetaAccordion.tsx +18 -3
  95. package/src/components/SkeletonPlaceholder.tsx +206 -0
  96. package/src/constants/version.ts +1 -1
  97. package/src/customHooks/networkLogger.ts +15 -0
  98. package/src/customHooks/storageInspector.ts +18 -14
  99. package/src/helpers/index.ts +213 -5
  100. package/src/helpers/searchQueryParser.ts +63 -20
  101. package/src/i18n/index.ts +38 -3
  102. package/src/index.tsx +124 -37
  103. package/src/styles/AppColors.ts +9 -0
  104. package/src/styles/AppFonts.ts +16 -0
  105. package/src/types/interfaces.ts +2 -2
@@ -47,6 +47,92 @@ const NetworkIcons_1 = require("../NetworkIcons");
47
47
  const storageInspector_1 = require("../../customHooks/storageInspector");
48
48
  const helpers_1 = require("../../helpers");
49
49
  const toast_1 = require("../../helpers/toast");
50
+ const getTypeBadge = (type) => {
51
+ switch (type) {
52
+ case 'json':
53
+ return { label: 'JSON', color: AppColors_1.AppColors.purple, bg: `${AppColors_1.AppColors.purple}16` };
54
+ case 'number':
55
+ return { label: 'NUM', color: AppColors_1.AppColors.warningIconGold, bg: `${AppColors_1.AppColors.warningIconGold}16` };
56
+ case 'boolean':
57
+ return { label: 'BOOL', color: AppColors_1.AppColors.emerald500, bg: `${AppColors_1.AppColors.emerald500}16` };
58
+ case 'null':
59
+ return { label: 'NULL', color: AppColors_1.AppColors.grayTextWeak, bg: `${AppColors_1.AppColors.grayTextWeak}16` };
60
+ default:
61
+ return { label: 'STR', color: AppColors_1.AppColors.blue500, bg: `${AppColors_1.AppColors.blue500}16` };
62
+ }
63
+ };
64
+ const StorageEntryCard = react_1.default.memo(function StorageEntryCard({ entry, isExpanded, onToggleExpand, onCopy, onEdit, onDelete, badge, }) {
65
+ const formattedBytes = (0, react_1.useMemo)(() => {
66
+ return entry.byteSize < 1024
67
+ ? `${entry.byteSize} B`
68
+ : `${(entry.byteSize / 1024).toFixed(1)} KB`;
69
+ }, [entry.byteSize]);
70
+ // Lazy compute displayed value to avoid layout thrashing on large JSON strings
71
+ const displayValue = (0, react_1.useMemo)(() => {
72
+ if (!isExpanded) {
73
+ if (entry.value.length > 250) {
74
+ return entry.value.slice(0, 250) + '...';
75
+ }
76
+ return entry.value;
77
+ }
78
+ if (entry.type === 'json') {
79
+ try {
80
+ const parsed = entry.parsedValue ?? JSON.parse(entry.value);
81
+ return JSON.stringify(parsed, null, 2);
82
+ }
83
+ catch {
84
+ return entry.value;
85
+ }
86
+ }
87
+ return entry.value;
88
+ }, [isExpanded, entry.value, entry.type, entry.parsedValue]);
89
+ return (<react_native_1.View style={styles.entryCard}>
90
+ {/* Entry Header: Key name, Type Badge, Size, Actions */}
91
+ <react_native_1.View style={styles.entryHeader}>
92
+ <react_native_1.View style={{ flex: 1, marginRight: 8 }}>
93
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
94
+ <react_native_1.Text style={styles.entryKey} numberOfLines={1} selectable>
95
+ {entry.key}
96
+ </react_native_1.Text>
97
+ <react_native_1.View style={[
98
+ styles.typeBadge,
99
+ { backgroundColor: badge.bg, borderColor: `${badge.color}33` },
100
+ ]}>
101
+ <react_native_1.Text style={[styles.typeBadgeText, { color: badge.color }]}>
102
+ {badge.label}
103
+ </react_native_1.Text>
104
+ </react_native_1.View>
105
+ <react_native_1.Text style={styles.sizeText}>{formattedBytes}</react_native_1.Text>
106
+ </react_native_1.View>
107
+ </react_native_1.View>
108
+
109
+ {/* Actions: Copy, Edit, Delete */}
110
+ <react_native_1.View style={styles.entryActions}>
111
+ <TouchableScale_1.default hitSlop={6} onPress={() => onCopy(entry)} style={styles.entryActionBtn}>
112
+ <NetworkIcons_1.CopyIcon size={12} color={AppColors_1.AppColors.grayText}/>
113
+ </TouchableScale_1.default>
114
+
115
+ <TouchableScale_1.default hitSlop={6} onPress={() => onEdit(entry)} style={styles.entryActionBtn}>
116
+ <NetworkIcons_1.PencilIcon size={12} color={AppColors_1.AppColors.purple}/>
117
+ </TouchableScale_1.default>
118
+
119
+ <TouchableScale_1.default hitSlop={6} onPress={() => onDelete(entry.key)} style={[styles.entryActionBtn, { backgroundColor: `${AppColors_1.AppColors.errorColor}12` }]}>
120
+ <NetworkIcons_1.TrashIcon size={12} color={AppColors_1.AppColors.errorColor}/>
121
+ </TouchableScale_1.default>
122
+ </react_native_1.View>
123
+ </react_native_1.View>
124
+
125
+ {/* Entry Value Preview / Viewer */}
126
+ <TouchableScale_1.default onPress={() => onToggleExpand(entry.key)} style={styles.valuePreviewBox}>
127
+ <react_native_1.Text style={styles.valuePreviewText} numberOfLines={isExpanded ? undefined : 3} selectable={isExpanded}>
128
+ {displayValue}
129
+ </react_native_1.Text>
130
+ {entry.value.length > 80 && (<react_native_1.Text style={styles.expandHint}>
131
+ {isExpanded ? '▲ Collapse' : '▼ Expand'}
132
+ </react_native_1.Text>)}
133
+ </TouchableScale_1.default>
134
+ </react_native_1.View>);
135
+ });
50
136
  exports.StorageTab = react_1.default.memo(() => {
51
137
  const { t } = (0, i18n_1.useTranslation)();
52
138
  const [activeDriver, setActiveDriver] = (0, react_1.useState)('asyncStorage');
@@ -205,20 +291,11 @@ exports.StorageTab = react_1.default.memo(() => {
205
291
  return `${(totalBytes / 1024).toFixed(1)} KB`;
206
292
  return `${(totalBytes / (1024 * 1024)).toFixed(2)} MB`;
207
293
  }, [totalBytes]);
208
- const getTypeBadge = (type) => {
209
- switch (type) {
210
- case 'json':
211
- return { label: 'JSON', color: AppColors_1.AppColors.purple, bg: `${AppColors_1.AppColors.purple}16` };
212
- case 'number':
213
- return { label: 'NUM', color: AppColors_1.AppColors.warningIconGold, bg: `${AppColors_1.AppColors.warningIconGold}16` };
214
- case 'boolean':
215
- return { label: 'BOOL', color: AppColors_1.AppColors.emerald500, bg: `${AppColors_1.AppColors.emerald500}16` };
216
- case 'null':
217
- return { label: 'NULL', color: AppColors_1.AppColors.grayTextWeak, bg: `${AppColors_1.AppColors.grayTextWeak}16` };
218
- default:
219
- return { label: 'STR', color: AppColors_1.AppColors.blue500, bg: `${AppColors_1.AppColors.blue500}16` };
220
- }
221
- };
294
+ const handleCopyEntry = (0, react_1.useCallback)((entry) => {
295
+ (0, helpers_1.copyToClipboard)(entry.value, entry.key);
296
+ (0, toast_1.showToast)(`Copied value of "${entry.key}"`);
297
+ }, []);
298
+ const renderItem = (0, react_1.useCallback)(({ item }) => (<StorageEntryCard entry={item} isExpanded={Boolean(expandedKeys[item.key])} onToggleExpand={toggleExpand} onCopy={handleCopyEntry} onEdit={handleOpenEdit} onDelete={handleDeleteKey} badge={getTypeBadge(item.type)}/>), [expandedKeys, handleCopyEntry]);
222
299
  const isConnected = activeDriver === 'asyncStorage'
223
300
  ? (0, storageInspector_1.isAsyncStorageConnected)()
224
301
  : (0, storageInspector_1.isMMKVConnected)();
@@ -284,9 +361,25 @@ exports.StorageTab = react_1.default.memo(() => {
284
361
  <react_native_1.View style={styles.searchBar}>
285
362
  <NetworkIcons_1.SearchIcon size={14} color={AppColors_1.AppColors.grayTextWeak}/>
286
363
  <react_native_1.TextInput value={search} onChangeText={setSearch} placeholder={`Search ${entries.length} keys & values...`} placeholderTextColor={AppColors_1.AppColors.grayTextWeak} style={styles.searchInput} clearButtonMode="while-editing"/>
287
- {search.length > 0 && (<TouchableScale_1.default onPress={() => setSearch('')} hitSlop={8}>
288
- <NetworkIcons_1.ClearIcon size={13} color={AppColors_1.AppColors.grayTextWeak}/>
289
- </TouchableScale_1.default>)}
364
+ {search.length > 0 && (<react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 4 }}>
365
+ <react_native_1.View style={{
366
+ backgroundColor: `${AppColors_1.AppColors.purple}20`,
367
+ borderRadius: 10,
368
+ paddingHorizontal: 6,
369
+ paddingVertical: 1.5,
370
+ }}>
371
+ <react_native_1.Text style={{
372
+ color: AppColors_1.AppColors.purple,
373
+ fontSize: 9.5,
374
+ fontFamily: AppFonts_1.AppFonts.interBold,
375
+ }}>
376
+ {filteredEntries.length}
377
+ </react_native_1.Text>
378
+ </react_native_1.View>
379
+ <TouchableScale_1.default onPress={() => setSearch('')} hitSlop={8}>
380
+ <NetworkIcons_1.ClearIcon size={13} color={AppColors_1.AppColors.grayTextWeak}/>
381
+ </TouchableScale_1.default>
382
+ </react_native_1.View>)}
290
383
  </react_native_1.View>
291
384
 
292
385
  {/* Action Buttons: Add Key & Refresh */}
@@ -318,81 +411,19 @@ exports.StorageTab = react_1.default.memo(() => {
318
411
  {isLoading ? (<react_native_1.View style={styles.loadingContainer}>
319
412
  <react_native_1.ActivityIndicator size="small" color={AppColors_1.AppColors.purple}/>
320
413
  <react_native_1.Text style={styles.loadingText}>Loading storage entries...</react_native_1.Text>
321
- </react_native_1.View>) : filteredEntries.length === 0 ? (<react_native_1.ScrollView contentContainerStyle={styles.emptyContainer} showsVerticalScrollIndicator={false}>
322
- <react_native_1.View style={styles.emptyIconWrap}>
323
- <NetworkIcons_1.DatabaseIcon size={28} color={AppColors_1.AppColors.grayTextWeak}/>
324
- </react_native_1.View>
325
- <react_native_1.Text style={styles.emptyTitle}>
326
- {search ? 'No matching keys found' : `No ${activeDriver === 'asyncStorage' ? 'AsyncStorage' : 'MMKV'} Keys`}
327
- </react_native_1.Text>
328
- <react_native_1.Text style={styles.emptySubtitle}>
329
- {search
330
- ? 'Try modifying your search query'
331
- : `Storage is auto-detected. Tap "+ Add" above to create your first ${activeDriver === 'asyncStorage' ? 'AsyncStorage' : 'MMKV'} key!`}
332
- </react_native_1.Text>
333
- </react_native_1.ScrollView>) : (<react_native_1.ScrollView style={styles.scrollArea} contentContainerStyle={styles.scrollContent} showsVerticalScrollIndicator={false}>
334
- {filteredEntries.map(entry => {
335
- const isExpanded = Boolean(expandedKeys[entry.key]);
336
- const badge = getTypeBadge(entry.type);
337
- const formattedBytes = entry.byteSize < 1024
338
- ? `${entry.byteSize} B`
339
- : `${(entry.byteSize / 1024).toFixed(1)} KB`;
340
- return (<react_native_1.View key={entry.key} style={styles.entryCard}>
341
- {/* Entry Header: Key name, Type Badge, Size, Actions */}
342
- <react_native_1.View style={styles.entryHeader}>
343
- <react_native_1.View style={{ flex: 1, marginRight: 8 }}>
344
- <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
345
- <react_native_1.Text style={styles.entryKey} numberOfLines={1} selectable>
346
- {entry.key}
347
- </react_native_1.Text>
348
- <react_native_1.View style={[
349
- styles.typeBadge,
350
- { backgroundColor: badge.bg, borderColor: `${badge.color}33` },
351
- ]}>
352
- <react_native_1.Text style={[styles.typeBadgeText, { color: badge.color }]}>
353
- {badge.label}
354
- </react_native_1.Text>
355
- </react_native_1.View>
356
- <react_native_1.Text style={styles.sizeText}>{formattedBytes}</react_native_1.Text>
357
- </react_native_1.View>
358
- </react_native_1.View>
359
-
360
- {/* Actions: Copy, Edit, Delete */}
361
- <react_native_1.View style={styles.entryActions}>
362
- <TouchableScale_1.default hitSlop={6} onPress={() => {
363
- (0, helpers_1.copyToClipboard)(entry.value, entry.key);
364
- (0, toast_1.showToast)(`Copied value of "${entry.key}"`);
365
- }} style={styles.entryActionBtn}>
366
- <NetworkIcons_1.CopyIcon size={12} color={AppColors_1.AppColors.grayText}/>
367
- </TouchableScale_1.default>
368
-
369
- <TouchableScale_1.default hitSlop={6} onPress={() => handleOpenEdit(entry)} style={styles.entryActionBtn}>
370
- <NetworkIcons_1.PencilIcon size={12} color={AppColors_1.AppColors.purple}/>
371
- </TouchableScale_1.default>
372
-
373
- <TouchableScale_1.default hitSlop={6} onPress={() => handleDeleteKey(entry.key)} style={[styles.entryActionBtn, { backgroundColor: `${AppColors_1.AppColors.errorColor}12` }]}>
374
- <NetworkIcons_1.TrashIcon size={12} color={AppColors_1.AppColors.errorColor}/>
375
- </TouchableScale_1.default>
376
- </react_native_1.View>
377
- </react_native_1.View>
378
-
379
- {/* Entry Value Preview / Viewer */}
380
- <TouchableScale_1.default onPress={() => toggleExpand(entry.key)} style={styles.valuePreviewBox}>
381
- <react_native_1.Text style={styles.valuePreviewText} numberOfLines={isExpanded ? undefined : 3} selectable>
382
- {entry.type === 'json' && entry.parsedValue
383
- ? isExpanded
384
- ? JSON.stringify(entry.parsedValue, null, 2)
385
- : entry.value
386
- : entry.value}
387
- </react_native_1.Text>
388
- {entry.value.length > 80 && (<react_native_1.Text style={styles.expandHint}>
389
- {isExpanded ? '▲ Collapse' : '▼ Expand'}
390
- </react_native_1.Text>)}
391
- </TouchableScale_1.default>
392
- </react_native_1.View>);
393
- })}
394
- <react_native_1.View style={{ height: 60 }}/>
395
- </react_native_1.ScrollView>)}
414
+ </react_native_1.View>) : (<react_native_1.FlatList data={filteredEntries} keyExtractor={item => item.key} renderItem={renderItem} initialNumToRender={10} maxToRenderPerBatch={10} windowSize={5} removeClippedSubviews={react_native_1.Platform.OS === 'android'} style={styles.scrollArea} contentContainerStyle={styles.scrollContent} showsVerticalScrollIndicator={false} ListEmptyComponent={<react_native_1.View style={styles.emptyContainer}>
415
+ <react_native_1.View style={styles.emptyIconWrap}>
416
+ <NetworkIcons_1.DatabaseIcon size={28} color={AppColors_1.AppColors.grayTextWeak}/>
417
+ </react_native_1.View>
418
+ <react_native_1.Text style={styles.emptyTitle}>
419
+ {search ? 'No matching keys found' : `No ${activeDriver === 'asyncStorage' ? 'AsyncStorage' : 'MMKV'} Keys`}
420
+ </react_native_1.Text>
421
+ <react_native_1.Text style={styles.emptySubtitle}>
422
+ {search
423
+ ? 'Try modifying your search query'
424
+ : `Storage is auto-detected. Tap "+ Add" above to create your first ${activeDriver === 'asyncStorage' ? 'AsyncStorage' : 'MMKV'} key!`}
425
+ </react_native_1.Text>
426
+ </react_native_1.View>} ListFooterComponent={<react_native_1.View style={{ height: 60 }}/>}/>)}
396
427
 
397
428
  {/* ── Create / Edit Key Modal ── */}
398
429
  <react_native_1.Modal visible={modalVisible} transparent animationType="fade" onRequestClose={() => setModalVisible(false)}>
@@ -43,6 +43,7 @@ const i18n_1 = require("../i18n");
43
43
  const TreeNode_1 = __importDefault(require("./TreeNode"));
44
44
  const SegmentedTabs_1 = __importDefault(require("./SegmentedTabs"));
45
45
  const HighlightText_1 = __importDefault(require("./HighlightText"));
46
+ const CopyButton_1 = __importDefault(require("./CopyButton"));
46
47
  const NetworkIcons_1 = require("./NetworkIcons");
47
48
  // Styles
48
49
  const AppColors_1 = require("../styles/AppColors");
@@ -189,6 +190,7 @@ const JsonViewer = react_1.default.memo(({ data, search, forceOpen, defaultExpan
189
190
  icon: (isActive) => (<NetworkIcons_1.TableIcon color={isActive ? AppColors_1.AppColors.white : AppColors_1.AppColors.slate400} size={12}/>),
190
191
  },
191
192
  ]} activeKey={mode} onChange={key => setMode(key)}/>
193
+ <CopyButton_1.default value={data} label="JSON"/>
192
194
  </react_native_1.View>)}
193
195
 
194
196
  {/* ── Main View Content Area (Royal Monospace Theme) ── */}
@@ -49,6 +49,7 @@ const helpers_1 = require("../helpers");
49
49
  const NetworkIcons_1 = require("./NetworkIcons");
50
50
  // Components
51
51
  const TouchableScale_1 = __importDefault(require("./TouchableScale"));
52
+ const CopyButton_1 = __importDefault(require("./CopyButton"));
52
53
  // Stylesheet
53
54
  const AppColors_1 = require("../styles/AppColors");
54
55
  const AppFonts_1 = require("../styles/AppFonts");
@@ -98,9 +99,20 @@ const MetaAccordion = ({ status, statusColor, duration, size, triggeredAt, metho
98
99
  <react_native_1.Pressable onPress={toggleOpen} hitSlop={12}>
99
100
  <react_native_1.View style={styles_1.default.metaHeader}>
100
101
  <react_native_1.Text style={styles_1.default.metaTitle}>Metadata</react_native_1.Text>
101
- <react_native_1.Animated.View style={chevronStyle}>
102
- <NetworkIcons_1.ChevronIcon color={AppColors_1.AppColors.grayTextWeak} size={14}/>
103
- </react_native_1.Animated.View>
102
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
103
+ <CopyButton_1.default value={{
104
+ status: status ?? 0,
105
+ duration: duration != null ? `${duration} ms` : '—',
106
+ size: size || '—',
107
+ triggeredAt: triggeredAt || '',
108
+ method: method || 'GET',
109
+ contentType: contentType || 'application/json',
110
+ url: url || '',
111
+ }} label="Metadata"/>
112
+ <react_native_1.Animated.View style={chevronStyle}>
113
+ <NetworkIcons_1.ChevronIcon color={AppColors_1.AppColors.grayTextWeak} size={14}/>
114
+ </react_native_1.Animated.View>
115
+ </react_native_1.View>
104
116
  </react_native_1.View>
105
117
  </react_native_1.Pressable>
106
118
 
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ interface SkeletonPlaceholderProps {
3
+ cardCount?: number;
4
+ }
5
+ declare const SkeletonPlaceholder: React.NamedExoticComponent<SkeletonPlaceholderProps>;
6
+ export default SkeletonPlaceholder;
@@ -0,0 +1,208 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const react_1 = __importStar(require("react"));
37
+ const react_native_1 = require("react-native");
38
+ const AppColors_1 = require("../styles/AppColors");
39
+ const SkeletonPlaceholder = react_1.default.memo(function SkeletonPlaceholder({ cardCount = 4, }) {
40
+ const shimmerAnim = (0, react_1.useRef)(new react_native_1.Animated.Value(0.35)).current;
41
+ (0, react_1.useEffect)(() => {
42
+ const animation = react_native_1.Animated.loop(react_native_1.Animated.sequence([
43
+ react_native_1.Animated.timing(shimmerAnim, {
44
+ toValue: 0.85,
45
+ duration: 750,
46
+ useNativeDriver: true,
47
+ }),
48
+ react_native_1.Animated.timing(shimmerAnim, {
49
+ toValue: 0.35,
50
+ duration: 750,
51
+ useNativeDriver: true,
52
+ }),
53
+ ]));
54
+ animation.start();
55
+ return () => animation.stop();
56
+ }, [shimmerAnim]);
57
+ return (<react_native_1.View style={skeletonStyles.container}>
58
+ {/* ─── Search & Scope Toolbar Skeleton ─── */}
59
+ <react_native_1.View style={skeletonStyles.toolbarSkeleton}>
60
+ <react_native_1.Animated.View style={[
61
+ skeletonStyles.searchBarSkeleton,
62
+ { opacity: shimmerAnim },
63
+ ]}/>
64
+ <react_native_1.View style={skeletonStyles.actionButtonsRow}>
65
+ <react_native_1.Animated.View style={[skeletonStyles.iconButtonSkeleton, { opacity: shimmerAnim }]}/>
66
+ <react_native_1.Animated.View style={[skeletonStyles.iconButtonSkeleton, { opacity: shimmerAnim }]}/>
67
+ </react_native_1.View>
68
+ </react_native_1.View>
69
+
70
+ {/* ─── Quick Filter Chips Skeleton Strip ─── */}
71
+ <react_native_1.View style={skeletonStyles.chipStripSkeleton}>
72
+ <react_native_1.Animated.View style={[skeletonStyles.chipSkeleton, { width: 48, opacity: shimmerAnim }]}/>
73
+ <react_native_1.Animated.View style={[skeletonStyles.chipSkeleton, { width: 68, opacity: shimmerAnim }]}/>
74
+ <react_native_1.Animated.View style={[skeletonStyles.chipSkeleton, { width: 76, opacity: shimmerAnim }]}/>
75
+ <react_native_1.Animated.View style={[skeletonStyles.chipSkeleton, { width: 58, opacity: shimmerAnim }]}/>
76
+ </react_native_1.View>
77
+
78
+ {/* ─── List Cards Skeleton ─── */}
79
+ {Array.from({ length: cardCount }).map((_, i) => (<react_native_1.Animated.View key={`skeleton_card_${i}`} style={[skeletonStyles.cardSkeleton, { opacity: shimmerAnim }]}>
80
+ {/* Top row: Status pill + Method + Time */}
81
+ <react_native_1.View style={skeletonStyles.cardTopRow}>
82
+ <react_native_1.View style={skeletonStyles.badgeGroup}>
83
+ <react_native_1.View style={skeletonStyles.statusBadgeSkeleton}/>
84
+ <react_native_1.View style={skeletonStyles.methodBadgeSkeleton}/>
85
+ </react_native_1.View>
86
+ <react_native_1.View style={skeletonStyles.timeSkeleton}/>
87
+ </react_native_1.View>
88
+
89
+ {/* Middle row: URL lines */}
90
+ <react_native_1.View style={skeletonStyles.urlLineLong}/>
91
+ <react_native_1.View style={skeletonStyles.urlLineShort}/>
92
+
93
+ {/* Bottom row: Latency & Size */}
94
+ <react_native_1.View style={skeletonStyles.cardBottomRow}>
95
+ <react_native_1.View style={skeletonStyles.metaPillSkeleton}/>
96
+ <react_native_1.View style={skeletonStyles.metaPillSkeleton}/>
97
+ </react_native_1.View>
98
+ </react_native_1.Animated.View>))}
99
+ </react_native_1.View>);
100
+ });
101
+ const skeletonStyles = react_native_1.StyleSheet.create({
102
+ container: {
103
+ flex: 1,
104
+ paddingHorizontal: 12,
105
+ paddingTop: 8,
106
+ },
107
+ toolbarSkeleton: {
108
+ flexDirection: 'row',
109
+ alignItems: 'center',
110
+ gap: 8,
111
+ marginBottom: 8,
112
+ },
113
+ searchBarSkeleton: {
114
+ flex: 1,
115
+ height: 36,
116
+ borderRadius: 8,
117
+ backgroundColor: AppColors_1.AppColors.graySurface,
118
+ borderWidth: 1,
119
+ borderColor: AppColors_1.AppColors.dividerColor,
120
+ },
121
+ actionButtonsRow: {
122
+ flexDirection: 'row',
123
+ gap: 6,
124
+ },
125
+ iconButtonSkeleton: {
126
+ width: 36,
127
+ height: 36,
128
+ borderRadius: 8,
129
+ backgroundColor: AppColors_1.AppColors.graySurface,
130
+ borderWidth: 1,
131
+ borderColor: AppColors_1.AppColors.dividerColor,
132
+ },
133
+ chipStripSkeleton: {
134
+ flexDirection: 'row',
135
+ gap: 6,
136
+ marginBottom: 10,
137
+ },
138
+ chipSkeleton: {
139
+ height: 24,
140
+ borderRadius: 6,
141
+ backgroundColor: AppColors_1.AppColors.graySurface,
142
+ borderWidth: 1,
143
+ borderColor: AppColors_1.AppColors.dividerColor,
144
+ },
145
+ cardSkeleton: {
146
+ backgroundColor: AppColors_1.AppColors.primaryLight,
147
+ borderRadius: 10,
148
+ padding: 12,
149
+ marginBottom: 8,
150
+ borderWidth: 1,
151
+ borderColor: AppColors_1.AppColors.dividerColor,
152
+ },
153
+ cardTopRow: {
154
+ flexDirection: 'row',
155
+ justifyContent: 'space-between',
156
+ alignItems: 'center',
157
+ marginBottom: 8,
158
+ },
159
+ badgeGroup: {
160
+ flexDirection: 'row',
161
+ alignItems: 'center',
162
+ gap: 6,
163
+ },
164
+ statusBadgeSkeleton: {
165
+ width: 38,
166
+ height: 18,
167
+ borderRadius: 4,
168
+ backgroundColor: AppColors_1.AppColors.graySurface,
169
+ },
170
+ methodBadgeSkeleton: {
171
+ width: 44,
172
+ height: 18,
173
+ borderRadius: 4,
174
+ backgroundColor: AppColors_1.AppColors.graySurface,
175
+ },
176
+ timeSkeleton: {
177
+ width: 48,
178
+ height: 12,
179
+ borderRadius: 4,
180
+ backgroundColor: AppColors_1.AppColors.graySurface,
181
+ },
182
+ urlLineLong: {
183
+ height: 13,
184
+ borderRadius: 4,
185
+ backgroundColor: AppColors_1.AppColors.graySurface,
186
+ marginBottom: 5,
187
+ width: '90%',
188
+ },
189
+ urlLineShort: {
190
+ height: 11,
191
+ borderRadius: 4,
192
+ backgroundColor: AppColors_1.AppColors.graySurface,
193
+ marginBottom: 8,
194
+ width: '55%',
195
+ },
196
+ cardBottomRow: {
197
+ flexDirection: 'row',
198
+ gap: 8,
199
+ marginTop: 2,
200
+ },
201
+ metaPillSkeleton: {
202
+ width: 52,
203
+ height: 14,
204
+ borderRadius: 4,
205
+ backgroundColor: AppColors_1.AppColors.graySurface,
206
+ },
207
+ });
208
+ exports.default = SkeletonPlaceholder;
@@ -1 +1 @@
1
- export declare const LIB_VERSION = "2.2.9";
1
+ export declare const LIB_VERSION = "2.3.1";
@@ -3,4 +3,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LIB_VERSION = void 0;
4
4
  // AUTO-GENERATED FILE — do not edit by hand.
5
5
  // Regenerated from package.json on every build by scripts/gen-version.js.
6
- exports.LIB_VERSION = '2.2.9';
6
+ exports.LIB_VERSION = '2.3.1';
@@ -1,3 +1,4 @@
1
+ import { RouteInfo } from "../types";
1
2
  type NetworkLog = {
2
3
  id: number;
3
4
  url: string;
@@ -11,7 +12,9 @@ type NetworkLog = {
11
12
  client?: string;
12
13
  requestHeaders?: Record<string, string>;
13
14
  responseHeaders?: Record<string, string>;
15
+ routeInfo?: RouteInfo;
14
16
  };
17
+ export declare const setRouteInfoProvider: (provider: (() => RouteInfo | null) | null) => void;
15
18
  export declare const setNetworkModuleEnabled: (enabled: boolean) => void;
16
19
  export declare const getNetworkModuleEnabled: () => boolean;
17
20
  export declare const subscribeNetworkLogs: (callback: (logs: NetworkLog[]) => void) => () => void;
@@ -3,13 +3,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.addAxiosInterceptors = exports.setupNetworkLogger = exports.pruneNetworkLogs = exports.getMaxNetworkLogsLimit = exports.setMaxNetworkLogsLimit = exports.getNetworkLogs = exports.clearNetworkLogs = exports.subscribeNetworkLogs = exports.getNetworkModuleEnabled = exports.setNetworkModuleEnabled = void 0;
6
+ exports.addAxiosInterceptors = exports.setupNetworkLogger = exports.pruneNetworkLogs = exports.getMaxNetworkLogsLimit = exports.setMaxNetworkLogsLimit = exports.getNetworkLogs = exports.clearNetworkLogs = exports.subscribeNetworkLogs = exports.getNetworkModuleEnabled = exports.setNetworkModuleEnabled = exports.setRouteInfoProvider = void 0;
7
7
  const axios_1 = __importDefault(require("axios"));
8
8
  const crashHandler_1 = require("./crashHandler");
9
9
  let logs = [];
10
10
  let listeners = [];
11
11
  let counter = 0;
12
12
  let isNetworkModuleEnabled = true;
13
+ let currentRouteProvider = null;
14
+ const setRouteInfoProvider = (provider) => {
15
+ currentRouteProvider = provider;
16
+ };
17
+ exports.setRouteInfoProvider = setRouteInfoProvider;
13
18
  const setNetworkModuleEnabled = (enabled) => {
14
19
  isNetworkModuleEnabled = enabled;
15
20
  };
@@ -199,6 +204,7 @@ const setupNetworkLogger = () => {
199
204
  else if (caller?.toLowerCase().includes('axios')) {
200
205
  client = 'axios';
201
206
  }
207
+ const currentRoute = currentRouteProvider ? currentRouteProvider() : null;
202
208
  addOrUpdateLog({
203
209
  id,
204
210
  url: finalUrl,
@@ -206,6 +212,7 @@ const setupNetworkLogger = () => {
206
212
  startTime: start,
207
213
  caller,
208
214
  client,
215
+ routeInfo: currentRoute || undefined,
209
216
  request: method === "GET" ? undefined : parseRequestData(options?.body),
210
217
  requestHeaders,
211
218
  });
@@ -313,6 +320,7 @@ const addAxiosInterceptors = (axiosInstance) => {
313
320
  config.__logId = id;
314
321
  config.__logStart = start;
315
322
  config.__logCaller = caller;
323
+ const currentRoute = currentRouteProvider ? currentRouteProvider() : null;
316
324
  addOrUpdateLog({
317
325
  id,
318
326
  url,
@@ -320,6 +328,7 @@ const addAxiosInterceptors = (axiosInstance) => {
320
328
  startTime: start,
321
329
  caller,
322
330
  client: 'axios',
331
+ routeInfo: currentRoute || undefined,
323
332
  request: method === "GET" ? undefined : parseRequestData(config.data),
324
333
  requestHeaders: normaliseHeaders(config.headers),
325
334
  });
@@ -37,11 +37,11 @@ export declare const getRegisteredMMKVInstanceIds: () => string[];
37
37
  */
38
38
  export declare const calculateByteSize: (str: string) => number;
39
39
  /**
40
- * Determine type and format value safely
40
+ * Determine type and format value safely without blocking JS thread
41
41
  */
42
42
  export declare const analyzeStorageValue: (rawVal: any) => {
43
43
  strVal: string;
44
- parsedVal?: any;
44
+ parsedValue?: any;
45
45
  type: "json" | "string" | "number" | "boolean" | "null";
46
46
  byteSize: number;
47
47
  };