react-native-inapp-inspector 2.3.14 → 2.3.16
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/README.md +1 -0
- package/dist/commonjs/components/AnimatedEntrance.js +3 -3
- package/dist/commonjs/components/ConsoleLogCard.js +174 -100
- package/dist/commonjs/components/Inspector/AnalyticsTab.js +0 -22
- package/dist/commonjs/components/Inspector/ConsoleTab.js +25 -38
- package/dist/commonjs/components/Inspector/CrashTab.js +19 -28
- package/dist/commonjs/components/Inspector/DeviceInfoTab.js +198 -98
- package/dist/commonjs/components/Inspector/FeedbackModal.d.ts +7 -0
- package/dist/commonjs/components/Inspector/FeedbackModal.js +552 -0
- package/dist/commonjs/components/Inspector/InspectorHeader.js +58 -6
- package/dist/commonjs/components/Inspector/MainScreen.js +100 -58
- package/dist/commonjs/components/Inspector/NetworkTab.js +26 -371
- package/dist/commonjs/components/Inspector/NpmStarPrompt.d.ts +3 -0
- package/dist/commonjs/components/Inspector/NpmStarPrompt.js +494 -0
- package/dist/commonjs/components/Inspector/PerformanceTab.js +40 -7
- package/dist/commonjs/components/Inspector/ReduxTab.js +3 -23
- package/dist/commonjs/components/Inspector/SettingsPanel.js +1035 -173
- package/dist/commonjs/components/Inspector/StorageTab.js +23 -28
- package/dist/commonjs/components/Inspector/TabBar.js +50 -15
- package/dist/commonjs/components/JsonViewer.js +14 -2
- package/dist/commonjs/components/LogCard.js +428 -227
- package/dist/commonjs/components/NetworkIcons.d.ts +5 -0
- package/dist/commonjs/components/NetworkIcons.js +33 -2
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/analyticsLogger.js +1 -1
- package/dist/commonjs/customHooks/consoleLogger.js +34 -2
- package/dist/commonjs/customHooks/crashHandler.js +1 -1
- package/dist/commonjs/customHooks/networkLogger.js +184 -26
- package/dist/commonjs/helpers/index.d.ts +1 -0
- package/dist/commonjs/helpers/index.js +1 -0
- package/dist/commonjs/helpers/remoteConfig.d.ts +4 -0
- package/dist/commonjs/helpers/remoteConfig.js +165 -0
- package/dist/commonjs/helpers/searchQueryParser.d.ts +1 -1
- package/dist/commonjs/helpers/searchQueryParser.js +39 -291
- package/dist/commonjs/helpers/telemetry.d.ts +5 -0
- package/dist/commonjs/helpers/telemetry.js +339 -8
- package/dist/commonjs/index.d.ts +1 -0
- package/dist/commonjs/index.js +173 -29
- package/dist/commonjs/styles/AppFonts.d.ts +2 -0
- package/dist/commonjs/styles/AppFonts.js +1 -0
- package/dist/commonjs/styles/index.d.ts +22 -0
- package/dist/commonjs/styles/index.js +19 -0
- package/dist/commonjs/types/enums.d.ts +1 -0
- package/dist/commonjs/types/enums.js +1 -0
- package/dist/commonjs/types/interfaces.d.ts +12 -0
- package/dist/esm/components/AnimatedEntrance.js +3 -3
- package/dist/esm/components/ConsoleLogCard.js +141 -100
- package/dist/esm/components/Inspector/AnalyticsTab.js +1 -23
- package/dist/esm/components/Inspector/ConsoleTab.js +26 -39
- package/dist/esm/components/Inspector/CrashTab.js +20 -29
- package/dist/esm/components/Inspector/DeviceInfoTab.js +198 -98
- package/dist/esm/components/Inspector/FeedbackModal.d.ts +7 -0
- package/dist/esm/components/Inspector/FeedbackModal.js +515 -0
- package/dist/esm/components/Inspector/InspectorHeader.js +60 -8
- package/dist/esm/components/Inspector/MainScreen.js +101 -59
- package/dist/esm/components/Inspector/NetworkTab.js +27 -372
- package/dist/esm/components/Inspector/NpmStarPrompt.d.ts +3 -0
- package/dist/esm/components/Inspector/NpmStarPrompt.js +454 -0
- package/dist/esm/components/Inspector/PerformanceTab.js +40 -7
- package/dist/esm/components/Inspector/ReduxTab.js +4 -24
- package/dist/esm/components/Inspector/SettingsPanel.js +1038 -176
- package/dist/esm/components/Inspector/StorageTab.js +23 -28
- package/dist/esm/components/Inspector/TabBar.js +50 -15
- package/dist/esm/components/JsonViewer.js +14 -2
- package/dist/esm/components/LogCard.js +422 -221
- package/dist/esm/components/NetworkIcons.d.ts +5 -0
- package/dist/esm/components/NetworkIcons.js +26 -0
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/analyticsLogger.js +1 -1
- package/dist/esm/customHooks/consoleLogger.js +34 -2
- package/dist/esm/customHooks/crashHandler.js +1 -1
- package/dist/esm/customHooks/networkLogger.js +184 -26
- package/dist/esm/helpers/index.d.ts +1 -0
- package/dist/esm/helpers/index.js +1 -0
- package/dist/esm/helpers/remoteConfig.d.ts +4 -0
- package/dist/esm/helpers/remoteConfig.js +160 -0
- package/dist/esm/helpers/searchQueryParser.d.ts +1 -1
- package/dist/esm/helpers/searchQueryParser.js +39 -291
- package/dist/esm/helpers/telemetry.d.ts +5 -0
- package/dist/esm/helpers/telemetry.js +332 -9
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +171 -29
- package/dist/esm/styles/AppFonts.d.ts +2 -0
- package/dist/esm/styles/AppFonts.js +1 -0
- package/dist/esm/styles/index.d.ts +22 -0
- package/dist/esm/styles/index.js +19 -0
- package/dist/esm/types/enums.d.ts +1 -0
- package/dist/esm/types/enums.js +1 -0
- package/dist/esm/types/interfaces.d.ts +12 -0
- package/package.json +1 -1
- package/src/components/AnimatedEntrance.tsx +3 -3
- package/src/components/ConsoleLogCard.tsx +154 -103
- package/src/components/Inspector/AnalyticsTab.tsx +0 -23
- package/src/components/Inspector/ConsoleTab.tsx +27 -41
- package/src/components/Inspector/CrashTab.tsx +19 -28
- package/src/components/Inspector/DeviceInfoTab.tsx +224 -102
- package/src/components/Inspector/FeedbackModal.tsx +626 -0
- package/src/components/Inspector/InspectorHeader.tsx +83 -5
- package/src/components/Inspector/MainScreen.tsx +61 -6
- package/src/components/Inspector/NetworkTab.tsx +70 -480
- package/src/components/Inspector/NpmStarPrompt.tsx +532 -0
- package/src/components/Inspector/PerformanceTab.tsx +44 -8
- package/src/components/Inspector/ReduxTab.tsx +9 -24
- package/src/components/Inspector/SettingsPanel.tsx +1162 -197
- package/src/components/Inspector/StorageTab.tsx +27 -30
- package/src/components/Inspector/TabBar.tsx +57 -20
- package/src/components/JsonViewer.tsx +15 -2
- package/src/components/LogCard.tsx +528 -339
- package/src/components/NetworkIcons.tsx +92 -0
- package/src/constants/version.ts +1 -1
- package/src/customHooks/analyticsLogger.ts +1 -1
- package/src/customHooks/consoleLogger.ts +36 -3
- package/src/customHooks/crashHandler.ts +1 -1
- package/src/customHooks/networkLogger.ts +214 -26
- package/src/helpers/index.ts +1 -0
- package/src/helpers/remoteConfig.ts +212 -0
- package/src/helpers/searchQueryParser.ts +42 -284
- package/src/helpers/telemetry.ts +381 -10
- package/src/index.tsx +374 -211
- package/src/styles/AppFonts.ts +2 -0
- package/src/styles/index.ts +20 -1
- package/src/types/enums.ts +1 -0
- package/src/types/interfaces.ts +12 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import {ActiveTab} from '../types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Supported Remote Config keys for each module:
|
|
5
|
+
*
|
|
6
|
+
* 1. JSON Configuration:
|
|
7
|
+
* - `inspector_modules` (e.g. `{"apis": true, "logs": true, "analytics": true, ...}`)
|
|
8
|
+
* - `inapp_inspector_modules`
|
|
9
|
+
*
|
|
10
|
+
* 2. Individual Boolean Keys:
|
|
11
|
+
* - `inspector_module_apis` / `inapp_inspector_apis` / `inspector_apis`
|
|
12
|
+
* - `inspector_module_logs` / `inapp_inspector_logs` / `inspector_logs`
|
|
13
|
+
* - `inspector_module_analytics` / `inapp_inspector_analytics` / `inspector_analytics`
|
|
14
|
+
* - `inspector_module_redux` / `inapp_inspector_redux` / `inspector_redux`
|
|
15
|
+
* - `inspector_module_storage` / `inapp_inspector_storage` / `inspector_storage`
|
|
16
|
+
* - `inspector_module_device` / `inapp_inspector_device` / `inspector_device`
|
|
17
|
+
* - `inspector_module_crash` / `inapp_inspector_crash` / `inspector_crash`
|
|
18
|
+
* - `inspector_module_bundle` / `inapp_inspector_bundle` / `inspector_bundle`
|
|
19
|
+
* - `inspector_module_performance` / `inapp_inspector_performance` / `inspector_performance`
|
|
20
|
+
* - `inspector_module_debugging` / `inapp_inspector_debugging` / `inspector_debugging`
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const MODULE_KEYS: ActiveTab[] = [
|
|
24
|
+
'apis',
|
|
25
|
+
'logs',
|
|
26
|
+
'analytics',
|
|
27
|
+
'redux',
|
|
28
|
+
'storage',
|
|
29
|
+
'device',
|
|
30
|
+
'crash',
|
|
31
|
+
'bundle',
|
|
32
|
+
'performance',
|
|
33
|
+
'debugging',
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
let cachedRemoteConfigInstance: any = null;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Dynamically resolves Firebase Remote Config instance if installed.
|
|
40
|
+
*/
|
|
41
|
+
export function getFirebaseRemoteConfig(customInstance?: any): any {
|
|
42
|
+
if (customInstance && typeof customInstance === 'object') {
|
|
43
|
+
cachedRemoteConfigInstance = customInstance;
|
|
44
|
+
return customInstance;
|
|
45
|
+
}
|
|
46
|
+
if (cachedRemoteConfigInstance) {
|
|
47
|
+
return cachedRemoteConfigInstance;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
const rcModule = require('@react-native-firebase/remote-config');
|
|
51
|
+
const instance =
|
|
52
|
+
typeof rcModule.default === 'function'
|
|
53
|
+
? rcModule.default()
|
|
54
|
+
: typeof rcModule === 'function'
|
|
55
|
+
? rcModule()
|
|
56
|
+
: rcModule;
|
|
57
|
+
cachedRemoteConfigInstance = instance;
|
|
58
|
+
return instance;
|
|
59
|
+
} catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Checks if @react-native-firebase/remote-config is available in the environment.
|
|
66
|
+
*/
|
|
67
|
+
export function isFirebaseRemoteConfigAvailable(customInstance?: any): boolean {
|
|
68
|
+
return Boolean(getFirebaseRemoteConfig(customInstance));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Helper to extract a boolean or JSON value from a Firebase Remote Config parameter.
|
|
73
|
+
*/
|
|
74
|
+
function extractValue(val: any): any {
|
|
75
|
+
if (val === null || val === undefined) return undefined;
|
|
76
|
+
if (typeof val === 'boolean') return val;
|
|
77
|
+
if (typeof val === 'number') return val !== 0;
|
|
78
|
+
if (typeof val === 'string') {
|
|
79
|
+
const lower = val.trim().toLowerCase();
|
|
80
|
+
if (lower === 'true' || lower === '1' || lower === 'enabled' || lower === 'on') return true;
|
|
81
|
+
if (lower === 'false' || lower === '0' || lower === 'disabled' || lower === 'off') return false;
|
|
82
|
+
try {
|
|
83
|
+
return JSON.parse(val);
|
|
84
|
+
} catch {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Firebase Remote Config Value object with .asBoolean() or .asString()
|
|
89
|
+
if (typeof val.asBoolean === 'function') {
|
|
90
|
+
return val.asBoolean();
|
|
91
|
+
}
|
|
92
|
+
if (typeof val.asString === 'function') {
|
|
93
|
+
const str = val.asString();
|
|
94
|
+
const lower = str.trim().toLowerCase();
|
|
95
|
+
if (lower === 'true' || lower === '1' || lower === 'enabled' || lower === 'on') return true;
|
|
96
|
+
if (lower === 'false' || lower === '0' || lower === 'disabled' || lower === 'off') return false;
|
|
97
|
+
try {
|
|
98
|
+
return JSON.parse(str);
|
|
99
|
+
} catch {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Fetches and activates latest values from Firebase Remote Config, then parses module enable/disable statuses.
|
|
108
|
+
* Returns a partial or complete mapping of module visibility flags, or null if Remote Config is unavailable.
|
|
109
|
+
*
|
|
110
|
+
* @param customInstance Optional custom remoteConfig instance from consumer app
|
|
111
|
+
* @param fetchTimeoutMs Timeout for fetch operation in ms (default: 8000)
|
|
112
|
+
*/
|
|
113
|
+
export async function fetchRemoteConfigModuleStatus(
|
|
114
|
+
customInstance?: any,
|
|
115
|
+
fetchTimeoutMs = 8000,
|
|
116
|
+
): Promise<Partial<Record<ActiveTab, boolean>> | null> {
|
|
117
|
+
const rc = getFirebaseRemoteConfig(customInstance);
|
|
118
|
+
if (!rc) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
// 1. Fetch & Activate with timeout protection
|
|
124
|
+
const fetchPromise = (async () => {
|
|
125
|
+
if (typeof rc.fetchAndActivate === 'function') {
|
|
126
|
+
await rc.fetchAndActivate();
|
|
127
|
+
} else {
|
|
128
|
+
if (typeof rc.fetch === 'function') {
|
|
129
|
+
await rc.fetch();
|
|
130
|
+
}
|
|
131
|
+
if (typeof rc.activate === 'function') {
|
|
132
|
+
await rc.activate();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
})();
|
|
136
|
+
|
|
137
|
+
const timeoutPromise = new Promise((_, reject) =>
|
|
138
|
+
setTimeout(() => reject(new Error('Remote Config fetch timeout')), fetchTimeoutMs),
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
await Promise.race([fetchPromise, timeoutPromise]).catch(() => {
|
|
142
|
+
// If network fetch fails/times out, we still read cached/activated values
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// 2. Read values from Remote Config
|
|
146
|
+
const result: Partial<Record<ActiveTab, boolean>> = {};
|
|
147
|
+
|
|
148
|
+
// Check JSON bundle key first: `inspector_modules` or `inapp_inspector_modules`
|
|
149
|
+
const jsonKeys = [
|
|
150
|
+
'inspector_modules',
|
|
151
|
+
'inapp_inspector_modules',
|
|
152
|
+
'react_native_inapp_inspector_modules',
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
for (const jKey of jsonKeys) {
|
|
156
|
+
let rawVal: any;
|
|
157
|
+
if (typeof rc.getValue === 'function') {
|
|
158
|
+
try {
|
|
159
|
+
rawVal = rc.getValue(jKey);
|
|
160
|
+
} catch {}
|
|
161
|
+
} else if (rc[jKey] !== undefined) {
|
|
162
|
+
rawVal = rc[jKey];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const parsed = extractValue(rawVal);
|
|
166
|
+
if (parsed && typeof parsed === 'object') {
|
|
167
|
+
for (const modKey of MODULE_KEYS) {
|
|
168
|
+
if (typeof parsed[modKey] === 'boolean') {
|
|
169
|
+
result[modKey] = parsed[modKey];
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Check individual module boolean flags (overrides JSON if explicitly defined)
|
|
176
|
+
for (const modKey of MODULE_KEYS) {
|
|
177
|
+
const paramKeys = [
|
|
178
|
+
`inspector_module_${modKey}`,
|
|
179
|
+
`inapp_inspector_${modKey}`,
|
|
180
|
+
`inspector_${modKey}`,
|
|
181
|
+
`inapp_inspector_module_${modKey}`,
|
|
182
|
+
`rn_inspector_${modKey}`,
|
|
183
|
+
];
|
|
184
|
+
|
|
185
|
+
for (const pKey of paramKeys) {
|
|
186
|
+
let rawVal: any;
|
|
187
|
+
if (typeof rc.getValue === 'function') {
|
|
188
|
+
try {
|
|
189
|
+
rawVal = rc.getValue(pKey);
|
|
190
|
+
} catch {}
|
|
191
|
+
} else if (rc[pKey] !== undefined) {
|
|
192
|
+
rawVal = rc[pKey];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const boolVal = extractValue(rawVal);
|
|
196
|
+
if (typeof boolVal === 'boolean') {
|
|
197
|
+
result[modKey] = boolVal;
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// APIs module is fundamental core, keep true unless explicitly disabled via remote config
|
|
204
|
+
if (result.apis === undefined) {
|
|
205
|
+
result.apis = true;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return Object.keys(result).length > 0 ? result : null;
|
|
209
|
+
} catch (error) {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {NetworkLog, SearchScope} from '../types';
|
|
2
|
+
import {markSearchFilterUsed} from './telemetry';
|
|
2
3
|
|
|
3
4
|
export interface SearchQueryOptions {
|
|
4
5
|
scope?: SearchScope;
|
|
@@ -7,320 +8,77 @@ export interface SearchQueryOptions {
|
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
11
|
+
* Universal substring search for NetworkLog.
|
|
12
|
+
* Checks whether a given NetworkLog matches all query keywords across all log fields.
|
|
12
13
|
*/
|
|
13
14
|
export function matchNetworkLogQuery(
|
|
14
15
|
log: NetworkLog,
|
|
15
16
|
searchQuery: string,
|
|
16
17
|
routePath?: string,
|
|
17
|
-
|
|
18
|
+
_options?: SearchQueryOptions,
|
|
18
19
|
): boolean {
|
|
19
20
|
if (!searchQuery || searchQuery.trim().length === 0) return true;
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
const rawTokens =
|
|
23
|
-
searchQuery.trim().match(/(?:[^\s,"']+|"[^"]*"|'[^']*')+/g) || [];
|
|
22
|
+
markSearchFilterUsed();
|
|
24
23
|
|
|
24
|
+
const rawTokens = searchQuery.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
25
25
|
if (rawTokens.length === 0) return true;
|
|
26
26
|
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
const methodRaw = log.method || '';
|
|
32
|
-
const urlRaw = log.url || '';
|
|
27
|
+
const methodRaw = (log.method || '').toLowerCase();
|
|
28
|
+
const urlRaw = (log.url || '').toLowerCase();
|
|
29
|
+
const statusStr = log.status != null ? String(log.status).toLowerCase() : 'pending';
|
|
33
30
|
const statusNum =
|
|
34
31
|
typeof log.status === 'number'
|
|
35
32
|
? log.status
|
|
36
33
|
: log.status != null
|
|
37
34
|
? parseInt(String(log.status), 10)
|
|
38
35
|
: null;
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
|
|
36
|
+
const clientRaw = (log.client || '').toLowerCase();
|
|
37
|
+
const callerRaw = (log.caller || '').toLowerCase();
|
|
38
|
+
const pathRaw = (routePath || (log as any)?.routeInfo?.path || '').toLowerCase();
|
|
39
|
+
|
|
43
40
|
const reqRaw =
|
|
44
41
|
typeof log.request === 'string'
|
|
45
|
-
? log.request
|
|
42
|
+
? log.request.toLowerCase()
|
|
46
43
|
: log.request != null
|
|
47
|
-
? JSON.stringify(log.request)
|
|
44
|
+
? JSON.stringify(log.request).toLowerCase()
|
|
48
45
|
: '';
|
|
49
46
|
const resRaw =
|
|
50
47
|
typeof log.response === 'string'
|
|
51
|
-
? log.response
|
|
48
|
+
? log.response.toLowerCase()
|
|
52
49
|
: log.response != null
|
|
53
|
-
? JSON.stringify(log.response)
|
|
50
|
+
? JSON.stringify(log.response).toLowerCase()
|
|
54
51
|
: '';
|
|
55
52
|
const reqHeadersRaw = log.requestHeaders
|
|
56
|
-
? JSON.stringify(log.requestHeaders)
|
|
53
|
+
? JSON.stringify(log.requestHeaders).toLowerCase()
|
|
57
54
|
: '';
|
|
58
55
|
const resHeadersRaw = log.responseHeaders
|
|
59
|
-
? JSON.stringify(log.responseHeaders)
|
|
56
|
+
? JSON.stringify(log.responseHeaders).toLowerCase()
|
|
60
57
|
: '';
|
|
61
|
-
const pathRaw = routePath || (log as any)?.routeInfo?.path || '';
|
|
62
|
-
|
|
63
|
-
// Construct search corpus based on active scope
|
|
64
|
-
const getScopedCorpus = (caseSens: boolean): string => {
|
|
65
|
-
let parts: string[] = [];
|
|
66
|
-
if (scope === 'url') {
|
|
67
|
-
parts = [methodRaw, urlRaw, pathRaw, callerRaw];
|
|
68
|
-
} else if (scope === 'reqBody') {
|
|
69
|
-
parts = [reqRaw];
|
|
70
|
-
} else if (scope === 'resBody') {
|
|
71
|
-
parts = [resRaw];
|
|
72
|
-
} else if (scope === 'headers') {
|
|
73
|
-
parts = [reqHeadersRaw, resHeadersRaw];
|
|
74
|
-
} else {
|
|
75
|
-
parts = [
|
|
76
|
-
methodRaw,
|
|
77
|
-
urlRaw,
|
|
78
|
-
statusStr,
|
|
79
|
-
pathRaw,
|
|
80
|
-
callerRaw,
|
|
81
|
-
clientRaw,
|
|
82
|
-
reqRaw,
|
|
83
|
-
resRaw,
|
|
84
|
-
reqHeadersRaw,
|
|
85
|
-
resHeadersRaw,
|
|
86
|
-
];
|
|
87
|
-
}
|
|
88
|
-
const combined = parts.join(' ');
|
|
89
|
-
return caseSens ? combined : combined.toLowerCase();
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const targetCorpus = getScopedCorpus(isCaseSensitive);
|
|
93
|
-
|
|
94
|
-
const methodStr = methodRaw.toLowerCase();
|
|
95
|
-
const urlStr = urlRaw.toLowerCase();
|
|
96
|
-
const clientStr = clientRaw.toLowerCase();
|
|
97
|
-
const callerStr = callerRaw.toLowerCase();
|
|
98
|
-
const reqStr = reqRaw.toLowerCase();
|
|
99
|
-
const resStr = resRaw.toLowerCase();
|
|
100
|
-
const reqHeadersStr = reqHeadersRaw.toLowerCase();
|
|
101
|
-
const resHeadersStr = resHeadersRaw.toLowerCase();
|
|
102
|
-
const pathStr = pathRaw.toLowerCase();
|
|
103
|
-
|
|
104
|
-
for (const rawToken of rawTokens) {
|
|
105
|
-
const token = rawToken.replace(/^["']|["']$/g, '').trim();
|
|
106
|
-
if (!token) continue;
|
|
107
|
-
|
|
108
|
-
const lowerToken = token.toLowerCase();
|
|
109
58
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
59
|
+
const corpus = [
|
|
60
|
+
methodRaw,
|
|
61
|
+
urlRaw,
|
|
62
|
+
statusStr,
|
|
63
|
+
pathRaw,
|
|
64
|
+
callerRaw,
|
|
65
|
+
clientRaw,
|
|
66
|
+
reqRaw,
|
|
67
|
+
resRaw,
|
|
68
|
+
reqHeadersRaw,
|
|
69
|
+
resHeadersRaw,
|
|
70
|
+
].join(' ');
|
|
71
|
+
|
|
72
|
+
return rawTokens.every(token => {
|
|
73
|
+
if (corpus.includes(token)) return true;
|
|
74
|
+
// Error status keywords
|
|
75
|
+
if (token === 'error' || token === 'failed' || token === 'err' || token === 'fail') {
|
|
76
|
+
return log.status === 0 || (statusNum !== null && statusNum >= 400);
|
|
119
77
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const val = lowerToken.replace(/^(status:|s:)/, '').trim();
|
|
124
|
-
if (val === 'pending' || val === 'loading') {
|
|
125
|
-
if (log.status != null) return false;
|
|
126
|
-
} else if (val.startsWith('>=')) {
|
|
127
|
-
const threshold = parseInt(val.slice(2), 10);
|
|
128
|
-
if (isNaN(threshold) || statusNum === null || statusNum < threshold) return false;
|
|
129
|
-
} else if (val.startsWith('>')) {
|
|
130
|
-
const threshold = parseInt(val.slice(1), 10);
|
|
131
|
-
if (isNaN(threshold) || statusNum === null || statusNum <= threshold) return false;
|
|
132
|
-
} else if (val.startsWith('<=')) {
|
|
133
|
-
const threshold = parseInt(val.slice(2), 10);
|
|
134
|
-
if (isNaN(threshold) || statusNum === null || statusNum > threshold) return false;
|
|
135
|
-
} else if (val.startsWith('<')) {
|
|
136
|
-
const threshold = parseInt(val.slice(1), 10);
|
|
137
|
-
if (isNaN(threshold) || statusNum === null || statusNum >= threshold) return false;
|
|
138
|
-
} else if (val.endsWith('xx') || val.endsWith('x')) {
|
|
139
|
-
const prefix = val.replace(/x/g, '');
|
|
140
|
-
if (!statusStr.startsWith(prefix)) return false;
|
|
141
|
-
} else {
|
|
142
|
-
const targetCode = parseInt(val, 10);
|
|
143
|
-
if (!isNaN(targetCode)) {
|
|
144
|
-
if (statusNum !== targetCode) return false;
|
|
145
|
-
} else if (!statusStr.includes(val)) {
|
|
146
|
-
return false;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
continue;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// 3. is:<FLAG>
|
|
153
|
-
if (lowerToken.startsWith('is:')) {
|
|
154
|
-
const flag = lowerToken.slice(3).trim();
|
|
155
|
-
if (
|
|
156
|
-
flag === 'error' ||
|
|
157
|
-
flag === 'failed' ||
|
|
158
|
-
flag === 'err' ||
|
|
159
|
-
flag === 'fail'
|
|
160
|
-
) {
|
|
161
|
-
const isErr =
|
|
162
|
-
log.status === 0 || (statusNum !== null && statusNum >= 400);
|
|
163
|
-
if (!isErr) return false;
|
|
164
|
-
} else if (flag === 'success' || flag === 'ok' || flag === '2xx') {
|
|
165
|
-
const isSuccess = statusNum !== null && statusNum >= 200 && statusNum < 300;
|
|
166
|
-
if (!isSuccess) return false;
|
|
167
|
-
} else if (flag === 'pending' || flag === 'loading') {
|
|
168
|
-
if (log.status != null) return false;
|
|
169
|
-
} else if (flag === 'slow') {
|
|
170
|
-
if (durationNum < 1000) return false;
|
|
171
|
-
} else if (flag === 'fast') {
|
|
172
|
-
if (durationNum >= 200) return false;
|
|
173
|
-
} else if (flag === 'graphql' || flag === 'gql') {
|
|
174
|
-
const isGql =
|
|
175
|
-
urlStr.includes('graphql') ||
|
|
176
|
-
clientStr === 'graphql' ||
|
|
177
|
-
clientStr === 'apollo';
|
|
178
|
-
if (!isGql) return false;
|
|
179
|
-
} else if (flag === 'https') {
|
|
180
|
-
if (!urlStr.startsWith('https')) return false;
|
|
181
|
-
} else if (flag === 'http') {
|
|
182
|
-
if (urlStr.startsWith('https') || !urlStr.startsWith('http'))
|
|
183
|
-
return false;
|
|
184
|
-
} else if (flag === 'json') {
|
|
185
|
-
const isJson =
|
|
186
|
-
reqHeadersStr.includes('application/json') ||
|
|
187
|
-
resHeadersStr.includes('application/json') ||
|
|
188
|
-
urlStr.includes('.json');
|
|
189
|
-
if (!isJson) return false;
|
|
190
|
-
} else if (flag === 'image') {
|
|
191
|
-
const isImg =
|
|
192
|
-
resHeadersStr.includes('image/') ||
|
|
193
|
-
/\.(png|jpe?g|gif|webp|svg)/i.test(urlStr);
|
|
194
|
-
if (!isImg) return false;
|
|
195
|
-
}
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// 4. slow:<DURATION> or dur:<DURATION> or duration:<DURATION>
|
|
200
|
-
if (
|
|
201
|
-
lowerToken.startsWith('slow:') ||
|
|
202
|
-
lowerToken.startsWith('dur:') ||
|
|
203
|
-
lowerToken.startsWith('duration:')
|
|
204
|
-
) {
|
|
205
|
-
const val = lowerToken.replace(/^(slow:|dur:|duration:)/, '').trim();
|
|
206
|
-
let thresholdMs = 0;
|
|
207
|
-
let isGreater = true;
|
|
208
|
-
|
|
209
|
-
let cleanVal = val;
|
|
210
|
-
if (val.startsWith('>=')) {
|
|
211
|
-
isGreater = true;
|
|
212
|
-
cleanVal = val.slice(2);
|
|
213
|
-
} else if (val.startsWith('>')) {
|
|
214
|
-
isGreater = true;
|
|
215
|
-
cleanVal = val.slice(1);
|
|
216
|
-
} else if (val.startsWith('<=')) {
|
|
217
|
-
isGreater = false;
|
|
218
|
-
cleanVal = val.slice(2);
|
|
219
|
-
} else if (val.startsWith('<')) {
|
|
220
|
-
isGreater = false;
|
|
221
|
-
cleanVal = val.slice(1);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (cleanVal.endsWith('s') && !cleanVal.endsWith('ms')) {
|
|
225
|
-
thresholdMs = parseFloat(cleanVal.slice(0, -1)) * 1000;
|
|
226
|
-
} else if (cleanVal.endsWith('ms')) {
|
|
227
|
-
thresholdMs = parseFloat(cleanVal.slice(0, -2));
|
|
228
|
-
} else {
|
|
229
|
-
thresholdMs = parseFloat(cleanVal);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (!isNaN(thresholdMs)) {
|
|
233
|
-
if (isGreater) {
|
|
234
|
-
if (durationNum < thresholdMs) return false;
|
|
235
|
-
} else {
|
|
236
|
-
if (durationNum > thresholdMs) return false;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
continue;
|
|
78
|
+
// Success status keywords
|
|
79
|
+
if (token === 'success' || token === 'ok' || token === '2xx') {
|
|
80
|
+
return statusNum !== null && statusNum >= 200 && statusNum < 300;
|
|
240
81
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
if (lowerToken.startsWith('client:') || lowerToken.startsWith('c:')) {
|
|
244
|
-
const targetClient = lowerToken.replace(/^(client:|c:)/, '').trim();
|
|
245
|
-
if (!clientStr.includes(targetClient)) return false;
|
|
246
|
-
continue;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// 6. domain:<DOMAIN> or d:<DOMAIN>
|
|
250
|
-
if (lowerToken.startsWith('domain:') || lowerToken.startsWith('d:')) {
|
|
251
|
-
const targetDomain = lowerToken.replace(/^(domain:|d:)/, '').trim();
|
|
252
|
-
if (!urlStr.includes(targetDomain)) return false;
|
|
253
|
-
continue;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// 7. path:<PATH> or p:<PATH> or page:<PAGE>
|
|
257
|
-
if (
|
|
258
|
-
lowerToken.startsWith('path:') ||
|
|
259
|
-
lowerToken.startsWith('p:') ||
|
|
260
|
-
lowerToken.startsWith('page:')
|
|
261
|
-
) {
|
|
262
|
-
const targetPath = lowerToken
|
|
263
|
-
.replace(/^(path:|p:|page:)/, '')
|
|
264
|
-
.trim();
|
|
265
|
-
if (
|
|
266
|
-
!urlStr.includes(targetPath) &&
|
|
267
|
-
!pathStr.includes(targetPath) &&
|
|
268
|
-
!callerStr.includes(targetPath)
|
|
269
|
-
) {
|
|
270
|
-
return false;
|
|
271
|
-
}
|
|
272
|
-
continue;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// 8. req:<TERM> or body:<TERM>
|
|
276
|
-
if (lowerToken.startsWith('req:') || lowerToken.startsWith('body:')) {
|
|
277
|
-
const target = lowerToken.replace(/^(req:|body:)/, '').trim();
|
|
278
|
-
if (!reqStr.includes(target)) return false;
|
|
279
|
-
continue;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// 9. res:<TERM>
|
|
283
|
-
if (lowerToken.startsWith('res:')) {
|
|
284
|
-
const target = lowerToken.slice(4).trim();
|
|
285
|
-
if (!resStr.includes(target)) return false;
|
|
286
|
-
continue;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// 10. header:<TERM> or h:<TERM>
|
|
290
|
-
if (lowerToken.startsWith('header:') || lowerToken.startsWith('h:')) {
|
|
291
|
-
const target = lowerToken.replace(/^(header:|h:)/, '').trim();
|
|
292
|
-
if (!reqHeadersStr.includes(target) && !resHeadersStr.includes(target)) {
|
|
293
|
-
return false;
|
|
294
|
-
}
|
|
295
|
-
continue;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// 11. Generic Match (handles Regex, Case-sensitivity, and Scoped corpus)
|
|
299
|
-
if (isRegex) {
|
|
300
|
-
try {
|
|
301
|
-
const re = new RegExp(token, isCaseSensitive ? '' : 'i');
|
|
302
|
-
if (!re.test(targetCorpus)) return false;
|
|
303
|
-
} catch {
|
|
304
|
-
const queryTerm = isCaseSensitive ? token : lowerToken;
|
|
305
|
-
if (!targetCorpus.includes(queryTerm)) return false;
|
|
306
|
-
}
|
|
307
|
-
} else {
|
|
308
|
-
const queryTerm = isCaseSensitive ? token : lowerToken;
|
|
309
|
-
if (!targetCorpus.includes(queryTerm)) {
|
|
310
|
-
// Special case: if user typed "error" / "failed", check error status
|
|
311
|
-
if (
|
|
312
|
-
queryTerm === 'error' ||
|
|
313
|
-
queryTerm === 'failed' ||
|
|
314
|
-
queryTerm === 'fail'
|
|
315
|
-
) {
|
|
316
|
-
const isErr =
|
|
317
|
-
log.status === 0 || (statusNum !== null && statusNum >= 400);
|
|
318
|
-
if (isErr) continue;
|
|
319
|
-
}
|
|
320
|
-
return false;
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
return true;
|
|
82
|
+
return false;
|
|
83
|
+
});
|
|
326
84
|
}
|