react-native-inapp-inspector 2.0.3 → 2.0.5

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 (46) hide show
  1. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  2. package/android/.gradle/8.9/checksums/md5-checksums.bin +0 -0
  3. package/android/.gradle/8.9/checksums/sha1-checksums.bin +0 -0
  4. package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  5. package/android/.gradle/8.9/executionHistory/executionHistory.lock +0 -0
  6. package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  7. package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  8. package/android/.gradle/8.9/gc.properties +0 -0
  9. package/android/.gradle/9.2.0/checksums/checksums.lock +0 -0
  10. package/android/.gradle/9.2.0/fileChanges/last-build.bin +0 -0
  11. package/android/.gradle/9.2.0/fileHashes/fileHashes.bin +0 -0
  12. package/android/.gradle/9.2.0/fileHashes/fileHashes.lock +0 -0
  13. package/android/.gradle/9.2.0/gc.properties +0 -0
  14. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  15. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  16. package/android/.gradle/vcs-1/gc.properties +0 -0
  17. package/android/build/reports/problems/problems-report.html +659 -0
  18. package/dist/commonjs/components/Inspector/InspectorHeader.js +87 -50
  19. package/dist/commonjs/components/Inspector/MainScreen.js +1 -0
  20. package/dist/commonjs/components/Inspector/NetworkTab.js +317 -12
  21. package/dist/commonjs/components/Inspector/NpmUpdateToast.js +88 -39
  22. package/dist/commonjs/components/Inspector/SettingsPanel.js +525 -359
  23. package/dist/commonjs/components/Inspector/UpdateAvailableModal.d.ts +8 -0
  24. package/dist/commonjs/components/Inspector/UpdateAvailableModal.js +469 -0
  25. package/dist/commonjs/constants/version.d.ts +1 -1
  26. package/dist/commonjs/constants/version.js +1 -1
  27. package/dist/commonjs/helpers/searchQueryParser.d.ts +8 -3
  28. package/dist/commonjs/helpers/searchQueryParser.js +85 -31
  29. package/dist/commonjs/helpers/telemetry.js +4 -4
  30. package/dist/commonjs/index.js +58 -7
  31. package/dist/commonjs/types/interfaces.d.ts +9 -0
  32. package/dist/esm/components/Inspector/InspectorHeader.js +87 -50
  33. package/dist/esm/components/Inspector/MainScreen.js +1 -0
  34. package/dist/esm/components/Inspector/NetworkTab.js +317 -12
  35. package/dist/esm/components/Inspector/NpmUpdateToast.js +88 -39
  36. package/dist/esm/components/Inspector/SettingsPanel.js +526 -360
  37. package/dist/esm/components/Inspector/UpdateAvailableModal.d.ts +8 -0
  38. package/dist/esm/components/Inspector/UpdateAvailableModal.js +432 -0
  39. package/dist/esm/constants/version.d.ts +1 -1
  40. package/dist/esm/constants/version.js +1 -1
  41. package/dist/esm/helpers/searchQueryParser.d.ts +8 -3
  42. package/dist/esm/helpers/searchQueryParser.js +85 -31
  43. package/dist/esm/helpers/telemetry.js +4 -4
  44. package/dist/esm/index.js +58 -7
  45. package/dist/esm/types/interfaces.d.ts +9 -0
  46. package/package.json +1 -1
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ interface UpdateAvailableModalProps {
3
+ visible: boolean;
4
+ latestVersion: string | null;
5
+ onClose: () => void;
6
+ }
7
+ export declare const UpdateAvailableModal: React.FC<UpdateAvailableModalProps>;
8
+ export default UpdateAvailableModal;
@@ -0,0 +1,432 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { Modal, View, Text, TouchableOpacity, StyleSheet, Animated, Platform, Linking, } from 'react-native';
3
+ import Svg, { Path } from 'react-native-svg';
4
+ import { BrandSquareIcon } from '../BrandSquareIcon';
5
+ import { NpmIcon } from '../NetworkIcons';
6
+ import { LIB_VERSION } from '../../constants';
7
+ import { copyToClipboard } from '../../helpers';
8
+ import { showToast } from '../../helpers/toast';
9
+ // ─── Crisp SVG Icons ─────────────────────────────────────────────────────────
10
+ const CopySvg = ({ size = 14, color = '#64748B' }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
11
+ <Path d="M8 4v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2h-8a2 2 0 0 0-2 2z" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
12
+ <Path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
13
+ </Svg>);
14
+ const CheckSvg = ({ size = 14, color = '#10B981' }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
15
+ <Path d="M20 6L9 17l-5-5" stroke={color} strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"/>
16
+ </Svg>);
17
+ const ExternalLinkSvg = ({ size = 13, color = '#FFFFFF' }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
18
+ <Path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
19
+ <Path d="M15 3h6v6" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
20
+ <Path d="M10 14L21 3" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
21
+ </Svg>);
22
+ const CloseSvg = ({ size = 13, color = '#64748B' }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
23
+ <Path d="M18 6L6 18M6 6l12 12" stroke={color} strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"/>
24
+ </Svg>);
25
+ const SparkleSvg = ({ size = 14, color = '#F59E0B' }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
26
+ <Path d="M12 2l2.4 6.6L21 11l-6.6 2.4L12 20l-2.4-6.6L3 11l6.6-2.4L12 2z" fill={color}/>
27
+ </Svg>);
28
+ export const UpdateAvailableModal = ({ visible, latestVersion, onClose, }) => {
29
+ const [copied, setCopied] = useState(false);
30
+ const fadeAnim = useState(new Animated.Value(0))[0];
31
+ const scaleAnim = useState(new Animated.Value(0.92))[0];
32
+ const installCommand = `npm install react-native-inapp-inspector@latest`;
33
+ useEffect(() => {
34
+ if (visible) {
35
+ setCopied(false);
36
+ Animated.parallel([
37
+ Animated.timing(fadeAnim, {
38
+ toValue: 1,
39
+ duration: 220,
40
+ useNativeDriver: true,
41
+ }),
42
+ Animated.spring(scaleAnim, {
43
+ toValue: 1,
44
+ friction: 8,
45
+ tension: 50,
46
+ useNativeDriver: true,
47
+ }),
48
+ ]).start();
49
+ }
50
+ }, [visible, fadeAnim, scaleAnim]);
51
+ const handleClose = () => {
52
+ Animated.parallel([
53
+ Animated.timing(fadeAnim, {
54
+ toValue: 0,
55
+ duration: 160,
56
+ useNativeDriver: true,
57
+ }),
58
+ Animated.timing(scaleAnim, {
59
+ toValue: 0.92,
60
+ duration: 160,
61
+ useNativeDriver: true,
62
+ }),
63
+ ]).start(() => {
64
+ onClose();
65
+ });
66
+ };
67
+ const handleCopyCommand = () => {
68
+ copyToClipboard(installCommand, 'Install Command');
69
+ setCopied(true);
70
+ showToast('Copied npm install command to clipboard!');
71
+ setTimeout(() => {
72
+ setCopied(false);
73
+ }, 2500);
74
+ };
75
+ const handleOpenNpm = () => {
76
+ Linking.openURL('https://www.npmjs.com/package/react-native-inapp-inspector').catch(() => { });
77
+ handleClose();
78
+ };
79
+ if (!visible)
80
+ return null;
81
+ return (<Modal transparent visible={visible} animationType="none" statusBarTranslucent onRequestClose={handleClose}>
82
+ <View style={styles.overlay}>
83
+ <Animated.View style={[
84
+ styles.card,
85
+ {
86
+ opacity: fadeAnim,
87
+ transform: [{ scale: scaleAnim }],
88
+ },
89
+ ]}>
90
+ {/* Top-Right Dismiss Button */}
91
+ <TouchableOpacity style={styles.topCloseButton} onPress={handleClose} hitSlop={10} activeOpacity={0.7}>
92
+ <CloseSvg size={13} color="#64748B"/>
93
+ </TouchableOpacity>
94
+
95
+ {/* Header section with brand square icon & sparkle */}
96
+ <View style={styles.headerSection}>
97
+ <View style={styles.iconHaloRing}>
98
+ <BrandSquareIcon size={52}/>
99
+ <View style={styles.sparkleBadge}>
100
+ <SparkleSvg size={13} color="#F59E0B"/>
101
+ </View>
102
+ </View>
103
+
104
+ <Text style={styles.title}>Update Available</Text>
105
+ <Text style={styles.subtitle}>
106
+ A newer release of react-native-inapp-inspector is ready
107
+ </Text>
108
+ </View>
109
+
110
+ {/* Version Comparison Card */}
111
+ <View style={styles.versionComparisonCard}>
112
+ <View style={styles.versionColumn}>
113
+ <Text style={styles.versionLabel}>INSTALLED</Text>
114
+ <View style={styles.installedChip}>
115
+ <Text style={styles.installedText}>v{LIB_VERSION}</Text>
116
+ </View>
117
+ </View>
118
+
119
+ <View style={styles.arrowContainer}>
120
+ <Text style={styles.arrowText}>➔</Text>
121
+ </View>
122
+
123
+ <View style={styles.versionColumn}>
124
+ <Text style={styles.versionLabel}>LATEST ON NPM</Text>
125
+ <View style={styles.latestChip}>
126
+ <NpmIcon size={12} color="#CB3837"/>
127
+ <Text style={styles.latestText}>v{latestVersion || 'latest'}</Text>
128
+ </View>
129
+ </View>
130
+ </View>
131
+
132
+ {/* Quick Install Snippet Box */}
133
+ <View style={styles.codeSnippetBox}>
134
+ <View style={styles.codeSnippetHeader}>
135
+ <Text style={styles.codeSnippetLabel}>UPGRADE COMMAND</Text>
136
+ {copied && (<View style={styles.copiedIndicator}>
137
+ <CheckSvg size={11} color="#10B981"/>
138
+ <Text style={styles.copiedText}>Copied</Text>
139
+ </View>)}
140
+ </View>
141
+
142
+ <TouchableOpacity style={styles.commandRow} onPress={handleCopyCommand} activeOpacity={0.75}>
143
+ <Text style={styles.commandText} numberOfLines={1}>
144
+ {installCommand}
145
+ </Text>
146
+ <View style={styles.copyIconWrapper}>
147
+ {copied ? <CheckSvg size={14} color="#10B981"/> : <CopySvg size={14} color="#64748B"/>}
148
+ </View>
149
+ </TouchableOpacity>
150
+ </View>
151
+
152
+ {/* Action Buttons */}
153
+ <View style={styles.buttonRow}>
154
+ <TouchableOpacity style={styles.secondaryButton} onPress={handleClose} activeOpacity={0.7}>
155
+ <Text style={styles.secondaryButtonText}>Later</Text>
156
+ </TouchableOpacity>
157
+
158
+ <TouchableOpacity style={styles.primaryButton} onPress={handleOpenNpm} activeOpacity={0.85}>
159
+ <Text style={styles.primaryButtonText}>View on NPM</Text>
160
+ <ExternalLinkSvg size={12} color="#FFFFFF"/>
161
+ </TouchableOpacity>
162
+ </View>
163
+ </Animated.View>
164
+ </View>
165
+ </Modal>);
166
+ };
167
+ const fontStack = Platform.select({
168
+ ios: {
169
+ fontFamily: 'System',
170
+ },
171
+ android: {
172
+ fontFamily: 'sans-serif',
173
+ },
174
+ default: {},
175
+ });
176
+ const styles = StyleSheet.create({
177
+ overlay: {
178
+ flex: 1,
179
+ backgroundColor: 'rgba(15, 23, 42, 0.62)',
180
+ justifyContent: 'center',
181
+ alignItems: 'center',
182
+ paddingHorizontal: 20,
183
+ zIndex: 999999,
184
+ },
185
+ card: {
186
+ width: '100%',
187
+ maxWidth: 360,
188
+ backgroundColor: '#FFFFFF',
189
+ borderRadius: 24,
190
+ borderWidth: 1,
191
+ borderColor: '#E2E8F0',
192
+ paddingHorizontal: 20,
193
+ paddingTop: 22,
194
+ paddingBottom: 20,
195
+ alignItems: 'center',
196
+ shadowColor: '#0F172A',
197
+ shadowOffset: { width: 0, height: 18 },
198
+ shadowOpacity: 0.24,
199
+ shadowRadius: 36,
200
+ elevation: 24,
201
+ },
202
+ topCloseButton: {
203
+ position: 'absolute',
204
+ top: 14,
205
+ right: 14,
206
+ width: 28,
207
+ height: 28,
208
+ borderRadius: 14,
209
+ backgroundColor: '#F8FAFC',
210
+ justifyContent: 'center',
211
+ alignItems: 'center',
212
+ borderWidth: 1,
213
+ borderColor: '#E2E8F0',
214
+ zIndex: 10,
215
+ },
216
+ headerSection: {
217
+ alignItems: 'center',
218
+ width: '100%',
219
+ marginBottom: 12,
220
+ },
221
+ iconHaloRing: {
222
+ width: 66,
223
+ height: 66,
224
+ borderRadius: 20,
225
+ backgroundColor: '#FAF5FF',
226
+ justifyContent: 'center',
227
+ alignItems: 'center',
228
+ borderWidth: 1.5,
229
+ borderColor: '#F3E8FF',
230
+ marginBottom: 8,
231
+ shadowColor: '#7C3AED',
232
+ shadowOffset: { width: 0, height: 4 },
233
+ shadowOpacity: 0.16,
234
+ shadowRadius: 10,
235
+ elevation: 4,
236
+ },
237
+ sparkleBadge: {
238
+ position: 'absolute',
239
+ top: -4,
240
+ right: -4,
241
+ width: 22,
242
+ height: 22,
243
+ borderRadius: 11,
244
+ backgroundColor: '#FEF3C7',
245
+ justifyContent: 'center',
246
+ alignItems: 'center',
247
+ borderWidth: 1.5,
248
+ borderColor: '#FFFFFF',
249
+ },
250
+ title: {
251
+ fontSize: 17.5,
252
+ fontWeight: '800',
253
+ color: '#0F172A',
254
+ letterSpacing: -0.4,
255
+ textAlign: 'center',
256
+ lineHeight: 22,
257
+ marginBottom: 2,
258
+ ...fontStack,
259
+ },
260
+ subtitle: {
261
+ fontSize: 12,
262
+ fontWeight: '500',
263
+ color: '#64748B',
264
+ textAlign: 'center',
265
+ lineHeight: 16,
266
+ paddingHorizontal: 8,
267
+ ...fontStack,
268
+ },
269
+ versionComparisonCard: {
270
+ flexDirection: 'row',
271
+ alignItems: 'center',
272
+ justifyContent: 'space-between',
273
+ backgroundColor: '#F8FAFC',
274
+ borderRadius: 14,
275
+ borderWidth: 1,
276
+ borderColor: '#E2E8F0',
277
+ paddingVertical: 10,
278
+ paddingHorizontal: 14,
279
+ marginBottom: 12,
280
+ width: '100%',
281
+ },
282
+ versionColumn: {
283
+ alignItems: 'center',
284
+ gap: 4,
285
+ },
286
+ versionLabel: {
287
+ fontSize: 9.5,
288
+ fontWeight: '700',
289
+ color: '#94A3B8',
290
+ letterSpacing: 0.6,
291
+ ...fontStack,
292
+ },
293
+ installedChip: {
294
+ backgroundColor: '#E2E8F0',
295
+ paddingHorizontal: 8,
296
+ paddingVertical: 3,
297
+ borderRadius: 6,
298
+ },
299
+ installedText: {
300
+ fontSize: 12,
301
+ fontWeight: '700',
302
+ color: '#475569',
303
+ ...fontStack,
304
+ },
305
+ arrowContainer: {
306
+ paddingHorizontal: 6,
307
+ },
308
+ arrowText: {
309
+ fontSize: 14,
310
+ color: '#94A3B8',
311
+ fontWeight: '700',
312
+ },
313
+ latestChip: {
314
+ flexDirection: 'row',
315
+ alignItems: 'center',
316
+ gap: 4,
317
+ backgroundColor: '#EDE9FE',
318
+ paddingHorizontal: 8,
319
+ paddingVertical: 3,
320
+ borderRadius: 6,
321
+ borderWidth: 1,
322
+ borderColor: '#DDD6FE',
323
+ },
324
+ latestText: {
325
+ fontSize: 12,
326
+ fontWeight: '800',
327
+ color: '#6D28D9',
328
+ ...fontStack,
329
+ },
330
+ codeSnippetBox: {
331
+ backgroundColor: '#0F172A',
332
+ borderRadius: 12,
333
+ padding: 10,
334
+ width: '100%',
335
+ marginBottom: 14,
336
+ borderWidth: 1,
337
+ borderColor: '#1E293B',
338
+ },
339
+ codeSnippetHeader: {
340
+ flexDirection: 'row',
341
+ justifyContent: 'space-between',
342
+ alignItems: 'center',
343
+ marginBottom: 6,
344
+ },
345
+ codeSnippetLabel: {
346
+ fontSize: 9.5,
347
+ fontWeight: '700',
348
+ color: '#64748B',
349
+ letterSpacing: 0.6,
350
+ ...fontStack,
351
+ },
352
+ copiedIndicator: {
353
+ flexDirection: 'row',
354
+ alignItems: 'center',
355
+ gap: 3,
356
+ },
357
+ copiedText: {
358
+ fontSize: 9.5,
359
+ fontWeight: '600',
360
+ color: '#10B981',
361
+ ...fontStack,
362
+ },
363
+ commandRow: {
364
+ flexDirection: 'row',
365
+ alignItems: 'center',
366
+ justifyContent: 'space-between',
367
+ backgroundColor: '#1E293B',
368
+ borderRadius: 8,
369
+ paddingVertical: 7,
370
+ paddingHorizontal: 9,
371
+ gap: 8,
372
+ },
373
+ commandText: {
374
+ flex: 1,
375
+ fontSize: 11,
376
+ fontFamily: Platform.OS === 'ios' ? 'Courier' : 'monospace',
377
+ color: '#38BDF8',
378
+ },
379
+ copyIconWrapper: {
380
+ width: 22,
381
+ height: 22,
382
+ borderRadius: 6,
383
+ backgroundColor: '#334155',
384
+ justifyContent: 'center',
385
+ alignItems: 'center',
386
+ },
387
+ buttonRow: {
388
+ flexDirection: 'row',
389
+ justifyContent: 'space-between',
390
+ alignItems: 'center',
391
+ gap: 10,
392
+ width: '100%',
393
+ },
394
+ secondaryButton: {
395
+ flex: 1,
396
+ alignItems: 'center',
397
+ justifyContent: 'center',
398
+ paddingVertical: 11,
399
+ borderRadius: 12,
400
+ backgroundColor: '#F1F5F9',
401
+ borderWidth: 1,
402
+ borderColor: '#E2E8F0',
403
+ },
404
+ secondaryButtonText: {
405
+ fontSize: 13,
406
+ fontWeight: '600',
407
+ color: '#475569',
408
+ ...fontStack,
409
+ },
410
+ primaryButton: {
411
+ flex: 1.3,
412
+ flexDirection: 'row',
413
+ alignItems: 'center',
414
+ justifyContent: 'center',
415
+ gap: 6,
416
+ paddingVertical: 11,
417
+ borderRadius: 12,
418
+ backgroundColor: '#7C3AED',
419
+ shadowColor: '#7C3AED',
420
+ shadowOffset: { width: 0, height: 3 },
421
+ shadowOpacity: 0.28,
422
+ shadowRadius: 6,
423
+ elevation: 4,
424
+ },
425
+ primaryButtonText: {
426
+ fontSize: 13,
427
+ fontWeight: '700',
428
+ color: '#FFFFFF',
429
+ ...fontStack,
430
+ },
431
+ });
432
+ export default UpdateAvailableModal;
@@ -1 +1 @@
1
- export declare const LIB_VERSION = "2.0.3";
1
+ export declare const LIB_VERSION = "2.0.5";
@@ -1,3 +1,3 @@
1
1
  // AUTO-GENERATED FILE — do not edit by hand.
2
2
  // Regenerated from package.json on every build by scripts/gen-version.js.
3
- export const LIB_VERSION = '2.0.3';
3
+ export const LIB_VERSION = '2.0.5';
@@ -1,6 +1,11 @@
1
- import { NetworkLog } from '../types';
1
+ import { NetworkLog, SearchScope } from '../types';
2
+ export interface SearchQueryOptions {
3
+ scope?: SearchScope;
4
+ isRegex?: boolean;
5
+ isCaseSensitive?: boolean;
6
+ }
2
7
  /**
3
8
  * Parses query strings like `method:POST is:error slow:>1s status:200 auth`
4
- * and checks whether a given NetworkLog matches all tokens.
9
+ * and checks whether a given NetworkLog matches all tokens against the specified scope.
5
10
  */
6
- export declare function matchNetworkLogQuery(log: NetworkLog, searchQuery: string, routePath?: string): boolean;
11
+ export declare function matchNetworkLogQuery(log: NetworkLog, searchQuery: string, routePath?: string, options?: SearchQueryOptions): boolean;
@@ -1,37 +1,73 @@
1
1
  /**
2
2
  * Parses query strings like `method:POST is:error slow:>1s status:200 auth`
3
- * and checks whether a given NetworkLog matches all tokens.
3
+ * and checks whether a given NetworkLog matches all tokens against the specified scope.
4
4
  */
5
- export function matchNetworkLogQuery(log, searchQuery, routePath) {
5
+ export function matchNetworkLogQuery(log, searchQuery, routePath, options) {
6
6
  if (!searchQuery || searchQuery.trim().length === 0)
7
7
  return true;
8
- const rawTokens = searchQuery
9
- .trim()
10
- .match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g) || [];
8
+ const rawTokens = searchQuery.trim().match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g) || [];
11
9
  if (rawTokens.length === 0)
12
10
  return true;
13
- const methodStr = (log.method || '').toLowerCase();
14
- const urlStr = (log.url || '').toLowerCase();
15
- const statusNum = typeof log.status === 'number' ? log.status : parseInt(String(log.status || 0), 10);
11
+ const isCaseSensitive = Boolean(options?.isCaseSensitive);
12
+ const isRegex = Boolean(options?.isRegex);
13
+ const scope = options?.scope || 'all';
14
+ const methodRaw = log.method || '';
15
+ const urlRaw = log.url || '';
16
+ const statusNum = typeof log.status === 'number'
17
+ ? log.status
18
+ : parseInt(String(log.status || 0), 10);
16
19
  const statusStr = String(log.status ?? '');
17
20
  const durationNum = log.duration || 0;
18
- const clientStr = (log.client || '').toLowerCase();
19
- const reqStr = typeof log.request === 'string' ? log.request : JSON.stringify(log.request || '');
20
- const resStr = typeof log.response === 'string' ? log.response : JSON.stringify(log.response || '');
21
- const reqHeadersStr = JSON.stringify(log.requestHeaders || '').toLowerCase();
22
- const resHeadersStr = JSON.stringify(log.responseHeaders || '').toLowerCase();
23
- const pathStr = routePath ? routePath.toLowerCase() : '';
24
- const fullSearchCorpus = [
25
- methodStr,
26
- urlStr,
27
- statusStr,
28
- pathStr,
29
- clientStr,
30
- reqStr.toLowerCase(),
31
- resStr.toLowerCase(),
32
- reqHeadersStr,
33
- resHeadersStr,
34
- ].join(' ');
21
+ const clientRaw = log.client || '';
22
+ const reqRaw = typeof log.request === 'string'
23
+ ? log.request
24
+ : JSON.stringify(log.request || '');
25
+ const resRaw = typeof log.response === 'string'
26
+ ? log.response
27
+ : JSON.stringify(log.response || '');
28
+ const reqHeadersRaw = JSON.stringify(log.requestHeaders || '');
29
+ const resHeadersRaw = JSON.stringify(log.responseHeaders || '');
30
+ const pathRaw = routePath || '';
31
+ // Construct search corpus based on active scope
32
+ const getScopedCorpus = (caseSens) => {
33
+ let parts = [];
34
+ if (scope === 'url') {
35
+ parts = [methodRaw, urlRaw, pathRaw];
36
+ }
37
+ else if (scope === 'reqBody') {
38
+ parts = [reqRaw];
39
+ }
40
+ else if (scope === 'resBody') {
41
+ parts = [resRaw];
42
+ }
43
+ else if (scope === 'headers') {
44
+ parts = [reqHeadersRaw, resHeadersRaw];
45
+ }
46
+ else {
47
+ parts = [
48
+ methodRaw,
49
+ urlRaw,
50
+ statusStr,
51
+ pathRaw,
52
+ clientRaw,
53
+ reqRaw,
54
+ resRaw,
55
+ reqHeadersRaw,
56
+ resHeadersRaw,
57
+ ];
58
+ }
59
+ const combined = parts.join(' ');
60
+ return caseSens ? combined : combined.toLowerCase();
61
+ };
62
+ const targetCorpus = getScopedCorpus(isCaseSensitive);
63
+ const methodStr = methodRaw.toLowerCase();
64
+ const urlStr = urlRaw.toLowerCase();
65
+ const clientStr = clientRaw.toLowerCase();
66
+ const reqStr = reqRaw.toLowerCase();
67
+ const resStr = resRaw.toLowerCase();
68
+ const reqHeadersStr = reqHeadersRaw.toLowerCase();
69
+ const resHeadersStr = resHeadersRaw.toLowerCase();
70
+ const pathStr = pathRaw.toLowerCase();
35
71
  for (const rawToken of rawTokens) {
36
72
  const token = rawToken.replace(/^["']|["']$/g, '').trim();
37
73
  if (!token)
@@ -93,7 +129,10 @@ export function matchNetworkLogQuery(log, searchQuery, routePath) {
93
129
  // 3. is:<FLAG>
94
130
  if (lowerToken.startsWith('is:')) {
95
131
  const flag = lowerToken.slice(3).trim();
96
- if (flag === 'error' || flag === 'failed' || flag === 'err' || flag === 'fail') {
132
+ if (flag === 'error' ||
133
+ flag === 'failed' ||
134
+ flag === 'err' ||
135
+ flag === 'fail') {
97
136
  const isErr = log.status === 0 || log.status == null || statusNum >= 400;
98
137
  if (!isErr)
99
138
  return false;
@@ -205,14 +244,14 @@ export function matchNetworkLogQuery(log, searchQuery, routePath) {
205
244
  // 8. req:<TERM> or body:<TERM>
206
245
  if (lowerToken.startsWith('req:') || lowerToken.startsWith('body:')) {
207
246
  const target = lowerToken.replace(/^(req:|body:)/, '').trim();
208
- if (!reqStr.toLowerCase().includes(target))
247
+ if (!reqStr.includes(target))
209
248
  return false;
210
249
  continue;
211
250
  }
212
251
  // 9. res:<TERM>
213
252
  if (lowerToken.startsWith('res:')) {
214
253
  const target = lowerToken.slice(4).trim();
215
- if (!resStr.toLowerCase().includes(target))
254
+ if (!resStr.includes(target))
216
255
  return false;
217
256
  continue;
218
257
  }
@@ -224,9 +263,24 @@ export function matchNetworkLogQuery(log, searchQuery, routePath) {
224
263
  }
225
264
  continue;
226
265
  }
227
- // 11. Generic Plain Substring Match
228
- if (!fullSearchCorpus.includes(lowerToken)) {
229
- return false;
266
+ // 11. Generic Match (handles Regex, Case-sensitivity, and Scoped corpus)
267
+ if (isRegex) {
268
+ try {
269
+ const re = new RegExp(token, isCaseSensitive ? '' : 'i');
270
+ if (!re.test(targetCorpus))
271
+ return false;
272
+ }
273
+ catch {
274
+ const queryTerm = isCaseSensitive ? token : lowerToken;
275
+ if (!targetCorpus.includes(queryTerm))
276
+ return false;
277
+ }
278
+ }
279
+ else {
280
+ const queryTerm = isCaseSensitive ? token : lowerToken;
281
+ if (!targetCorpus.includes(queryTerm)) {
282
+ return false;
283
+ }
230
284
  }
231
285
  }
232
286
  return true;
@@ -13,8 +13,8 @@ import { LIB_VERSION } from '../constants';
13
13
  import { getNativeStorageItem, setNativeStorageItem, isNativeModuleAvailable, getNativeDeviceMetrics, } from '../native/NativeInspector';
14
14
  // ─── GA4 Measurement Protocol Configuration ──────────────────────────────────
15
15
  // Automatically replaced at build-time from .env by scripts/inject-telemetry.js
16
- export const GA4_MEASUREMENT_ID = 'G-XXXXXXXXXX';
17
- export const GA4_API_SECRET = 'YOUR_GA4_API_SECRET';
16
+ export const GA4_MEASUREMENT_ID = 'G-3QGMQVZX5V';
17
+ export const GA4_API_SECRET = 'C46RQZ3PTfmHDnLnvU3KIg';
18
18
  const GA4_ENDPOINT = 'https://www.google-analytics.com/mp/collect';
19
19
  const CLIENT_ID_KEY = 'telemetry_client_id';
20
20
  // Stable session ID created once per JavaScript runtime instance
@@ -236,9 +236,9 @@ export async function trackTelemetryEvent(eventName, params = {}, options) {
236
236
  return;
237
237
  // Don't send if credentials haven't been configured yet
238
238
  if (!GA4_MEASUREMENT_ID ||
239
- GA4_MEASUREMENT_ID === 'G-XXXXXXXXXX' ||
239
+ GA4_MEASUREMENT_ID === 'G-3QGMQVZX5V' ||
240
240
  !GA4_API_SECRET ||
241
- GA4_API_SECRET === 'YOUR_GA4_API_SECRET') {
241
+ GA4_API_SECRET === 'C46RQZ3PTfmHDnLnvU3KIg') {
242
242
  return;
243
243
  }
244
244
  try {