react-native-inapp-inspector 2.2.2 → 2.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/package.json +2 -1
- package/src/analytics.ts +35 -0
- package/src/bundle.ts +25 -0
- package/src/components/AnalyticsDetail.tsx +865 -0
- package/src/components/AnalyticsEventCard.tsx +441 -0
- package/src/components/AnalyticsGraph.tsx +583 -0
- package/src/components/AnimatedEntrance.tsx +64 -0
- package/src/components/AppHeaderLogo.tsx +109 -0
- package/src/components/BrandCircleIcon.tsx +144 -0
- package/src/components/BrandSquareIcon.tsx +144 -0
- package/src/components/CodeSnippet.tsx +725 -0
- package/src/components/ConsoleLogCard.tsx +628 -0
- package/src/components/CopyButton.tsx +87 -0
- package/src/components/DiffViewer.tsx +82 -0
- package/src/components/DomainHeader.tsx +237 -0
- package/src/components/EmptyState.tsx +73 -0
- package/src/components/EndOfListFooter.tsx +100 -0
- package/src/components/ErrorBoundary.tsx +688 -0
- package/src/components/HeadersSection.tsx +192 -0
- package/src/components/HighlightText.tsx +100 -0
- package/src/components/Inspector/AnalyticsFilterModal.tsx +1250 -0
- package/src/components/Inspector/AnalyticsTab.tsx +1336 -0
- package/src/components/Inspector/BundleTab.tsx +4731 -0
- package/src/components/Inspector/ConsoleTab.tsx +702 -0
- package/src/components/Inspector/CrashDetail.tsx +941 -0
- package/src/components/Inspector/CrashFilterModal.tsx +721 -0
- package/src/components/Inspector/CrashTab.tsx +871 -0
- package/src/components/Inspector/FabLauncher.tsx +80 -0
- package/src/components/Inspector/InspectorContext.tsx +28 -0
- package/src/components/Inspector/InspectorHeader.tsx +973 -0
- package/src/components/Inspector/LogDetail.tsx +1427 -0
- package/src/components/Inspector/MainScreen.tsx +258 -0
- package/src/components/Inspector/NavigationTracker.tsx +13 -0
- package/src/components/Inspector/NetworkDetail.tsx +794 -0
- package/src/components/Inspector/NetworkTab.tsx +1095 -0
- package/src/components/Inspector/NpmUpdateToast.tsx +392 -0
- package/src/components/Inspector/PerformanceTab.tsx +1894 -0
- package/src/components/Inspector/ReduxDetail.tsx +1651 -0
- package/src/components/Inspector/ReduxTab.tsx +954 -0
- package/src/components/Inspector/SettingsPanel.tsx +3181 -0
- package/src/components/Inspector/TabBar.tsx +187 -0
- package/src/components/Inspector/TelemetryConsentModal.tsx +392 -0
- package/src/components/Inspector/UpdateAvailableModal.tsx +545 -0
- package/src/components/JsonViewer.tsx +486 -0
- package/src/components/LogCard.tsx +491 -0
- package/src/components/LogSyntaxHighlighter.tsx +178 -0
- package/src/components/MetaAccordion.tsx +340 -0
- package/src/components/MiniBarChart.tsx +42 -0
- package/src/components/MiniLineChart.tsx +33 -0
- package/src/components/NetworkIcons.tsx +2118 -0
- package/src/components/SectionHeader.tsx +113 -0
- package/src/components/SegmentedTabs.tsx +83 -0
- package/src/components/Slider.tsx +300 -0
- package/src/components/SourcePageCard.tsx +148 -0
- package/src/components/Toast.tsx +131 -0
- package/src/components/TouchableScale.tsx +91 -0
- package/src/components/TreeNode.tsx +186 -0
- package/src/console.ts +24 -0
- package/src/constants/index.ts +38 -0
- package/src/constants/version.ts +3 -0
- package/src/crash.ts +32 -0
- package/src/customHooks/analyticsLogger.ts +336 -0
- package/src/customHooks/bundleAnalyzer.ts +1231 -0
- package/src/customHooks/consoleLogger.ts +497 -0
- package/src/customHooks/crashHandler.ts +944 -0
- package/src/customHooks/logFilters.ts +32 -0
- package/src/customHooks/networkLogger.ts +419 -0
- package/src/customHooks/performanceTracker.ts +1014 -0
- package/src/customHooks/reduxLogger.ts +406 -0
- package/src/customHooks/useAccordion.tsx +60 -0
- package/src/decorators/index.ts +184 -0
- package/src/helpers/gaAnalyticsRegistry.ts +204 -0
- package/src/helpers/index.ts +860 -0
- package/src/helpers/memoryManager.ts +138 -0
- package/src/helpers/searchQueryParser.ts +283 -0
- package/src/helpers/settingsStore.ts +171 -0
- package/src/helpers/telemetry.ts +505 -0
- package/src/helpers/toast.ts +17 -0
- package/src/i18n/index.ts +69 -0
- package/src/i18n/locales/en.json +1052 -0
- package/src/index.tsx +2336 -0
- package/src/native/NativeInspector.ts +397 -0
- package/src/native/NativeNetworkInspector.ts +24 -0
- package/src/network.ts +22 -0
- package/src/performance.ts +38 -0
- package/src/redux.ts +23 -0
- package/src/styles/AppColors.ts +408 -0
- package/src/styles/AppFonts.ts +8 -0
- package/src/styles/common.ts +209 -0
- package/src/styles/index.ts +1570 -0
- package/src/types/enums.ts +194 -0
- package/src/types/index.ts +34 -0
- package/src/types/interfaces.ts +515 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for console logs to ignore.
|
|
3
|
+
* Logs matching any of these starting prefixes will be filtered out.
|
|
4
|
+
*/
|
|
5
|
+
export const IGNORED_LOG_PREFIXES: Record<'info' | 'warn' | 'error', string[]> =
|
|
6
|
+
{
|
|
7
|
+
info: [
|
|
8
|
+
// Add prefixes of info logs you want to ignore, e.g.:
|
|
9
|
+
// 'Starting server',
|
|
10
|
+
'VirtualizedList: You have a large list that is slow to update',
|
|
11
|
+
],
|
|
12
|
+
warn: [
|
|
13
|
+
// Add prefixes of warning logs you want to ignore, e.g.:
|
|
14
|
+
// 'Require cycle:',
|
|
15
|
+
// 'ViewPropTypes will be removed',
|
|
16
|
+
'This method is deprecated (as well as all React Native Firebase namespaced API) and will be removed in the next major release as part of move to match Firebase Web modular SDK API.',
|
|
17
|
+
'SerializableStateInvariantMiddleware took',
|
|
18
|
+
'Non-serializable values were found in the navigation state.',
|
|
19
|
+
'SafeAreaView has been deprecated and will be removed in a future release.',
|
|
20
|
+
'Clipboard has been extracted from react-native core and will be removed in a future release.',
|
|
21
|
+
'You should always pass contentWidth prop to properly handle screen rotations and have a seamless support for images scaling.',
|
|
22
|
+
'Selector unknown returned a different result when called with the same parameters.',
|
|
23
|
+
'You seem to update props of the "TRenderEngineProvider" component in short periods of time',
|
|
24
|
+
'A non-serializable value was detected in an action',
|
|
25
|
+
],
|
|
26
|
+
error: [
|
|
27
|
+
// Add prefixes of error logs you want to ignore, e.g.:
|
|
28
|
+
// 'Warning: Each child in a list should have a unique',
|
|
29
|
+
'A non-serializable value was detected in the state, in the path: `tierStatusCalculator.date`',
|
|
30
|
+
'VirtualizedLists should never be nested inside plain ScrollViews with the same orientation because it can break windowing and other functionality - use another VirtualizedList-backed container instead.',
|
|
31
|
+
],
|
|
32
|
+
};
|
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import {setupGlobalCrashHandler} from "./crashHandler";
|
|
3
|
+
|
|
4
|
+
type NetworkLog = {
|
|
5
|
+
id: number;
|
|
6
|
+
url: string;
|
|
7
|
+
method: string;
|
|
8
|
+
status?: number;
|
|
9
|
+
request?: any;
|
|
10
|
+
response?: any;
|
|
11
|
+
duration?: number;
|
|
12
|
+
startTime: number;
|
|
13
|
+
caller?: string; // ✅ Captures the file and line number
|
|
14
|
+
client?: string; // ✅ Captures request client: axios, fetch, xhr, apollo, etc.
|
|
15
|
+
requestHeaders?: Record<string, string>;
|
|
16
|
+
responseHeaders?: Record<string, string>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
let logs: NetworkLog[] = [];
|
|
20
|
+
let listeners: ((logs: NetworkLog[]) => void)[] = [];
|
|
21
|
+
let counter = 0;
|
|
22
|
+
let isNetworkModuleEnabled = true;
|
|
23
|
+
|
|
24
|
+
export const setNetworkModuleEnabled = (enabled: boolean) => {
|
|
25
|
+
isNetworkModuleEnabled = enabled;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const getNetworkModuleEnabled = () => isNetworkModuleEnabled;
|
|
29
|
+
|
|
30
|
+
const ALLOWED_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
31
|
+
|
|
32
|
+
const IGNORED_URL_PATTERNS: RegExp[] = [
|
|
33
|
+
/\/symbolicate(?:[/?#]|$)/i,
|
|
34
|
+
/\/index\.bundle(?:\?|$)/i,
|
|
35
|
+
/\/hot(?:\?|$)/i,
|
|
36
|
+
/\/message(?:\?|$)/i,
|
|
37
|
+
/\/open-debugger(?:\?|$)/i,
|
|
38
|
+
/\/status(?:\?|$)/i,
|
|
39
|
+
/127\.0\.0\.1:(?:8081|8082|8083|19000|19001|19002|3000|8000)/i,
|
|
40
|
+
/localhost:(?:8081|8082|8083|19000|19001|19002|3000|8000)\/index\.bundle/i,
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
function shouldIgnoreUrl(url: string | undefined | null): boolean {
|
|
44
|
+
if (!url) return false;
|
|
45
|
+
return IGNORED_URL_PATTERNS.some((re) => re.test(url));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
function normaliseHeaders(
|
|
51
|
+
raw: Headers | undefined | null,
|
|
52
|
+
): Record<string, string> | undefined {
|
|
53
|
+
if (!raw) return undefined;
|
|
54
|
+
|
|
55
|
+
if (typeof (raw as Headers).forEach === "function") {
|
|
56
|
+
const result: Record<string, string> = {};
|
|
57
|
+
(raw as Headers).forEach((value: string, key: string | number) => {
|
|
58
|
+
result[key] = value;
|
|
59
|
+
});
|
|
60
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (Array.isArray(raw)) {
|
|
64
|
+
const result: Record<string, string> = {};
|
|
65
|
+
(raw as string[][]).forEach(([key, value]) => {
|
|
66
|
+
result[key] = value;
|
|
67
|
+
});
|
|
68
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const obj = raw as any as Record<string, string>;
|
|
72
|
+
const result: Record<string, string> = {};
|
|
73
|
+
Object.entries(obj).forEach(([key, value]) => {
|
|
74
|
+
if (value != null) {
|
|
75
|
+
result[key] = String(value);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ✅ Parse FormData for File Upload previews
|
|
82
|
+
function parseRequestData(data: any): any {
|
|
83
|
+
if (!data) return data;
|
|
84
|
+
|
|
85
|
+
if (data && data._parts && Array.isArray(data._parts)) {
|
|
86
|
+
const parsedFormData: any = {};
|
|
87
|
+
data._parts.forEach((part: any) => {
|
|
88
|
+
const key = part[0];
|
|
89
|
+
const value = part[1];
|
|
90
|
+
|
|
91
|
+
if (value && typeof value === "object" && value.uri) {
|
|
92
|
+
parsedFormData[key] = {
|
|
93
|
+
_isFile: true,
|
|
94
|
+
name: value.name || "unknown",
|
|
95
|
+
type: value.type || "unknown",
|
|
96
|
+
uri: value.uri,
|
|
97
|
+
};
|
|
98
|
+
} else {
|
|
99
|
+
parsedFormData[key] = value;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
return { _isFormData: true, ...parsedFormData };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return data;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ✅ Magic function to extract file and line number from the call stack
|
|
109
|
+
function getCallerFromStack(): string {
|
|
110
|
+
try {
|
|
111
|
+
const stack = new Error().stack;
|
|
112
|
+
if (!stack) return "Unknown";
|
|
113
|
+
const lines = stack.split("\n");
|
|
114
|
+
for (let i = 0; i < lines.length; i++) {
|
|
115
|
+
const line = lines[i];
|
|
116
|
+
// Skip internal react-native network modules and the logger itself
|
|
117
|
+
if (
|
|
118
|
+
line.includes("networkLogger") ||
|
|
119
|
+
line.includes("node_modules") ||
|
|
120
|
+
line.includes("Error") ||
|
|
121
|
+
line.includes("regeneratorRuntime")
|
|
122
|
+
) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
return line.trim().replace(/^at /, "");
|
|
126
|
+
}
|
|
127
|
+
} catch (e) {}
|
|
128
|
+
return "Unknown";
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ─── Subscribe ────────────────────────────────────────────────────────────────
|
|
132
|
+
|
|
133
|
+
export const subscribeNetworkLogs = (
|
|
134
|
+
callback: (logs: NetworkLog[]) => void,
|
|
135
|
+
) => {
|
|
136
|
+
listeners.push(callback);
|
|
137
|
+
callback([...logs]);
|
|
138
|
+
return () => {
|
|
139
|
+
listeners = listeners.filter((l) => l !== callback);
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export const clearNetworkLogs = () => {
|
|
144
|
+
logs = [];
|
|
145
|
+
notify();
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export const getNetworkLogs = () => [...logs];
|
|
149
|
+
|
|
150
|
+
let maxNetworkLogsLimit = 100;
|
|
151
|
+
|
|
152
|
+
export const setMaxNetworkLogsLimit = (limit: number): void => {
|
|
153
|
+
maxNetworkLogsLimit = Math.max(10, limit);
|
|
154
|
+
if (logs.length > maxNetworkLogsLimit) {
|
|
155
|
+
logs = logs.slice(0, maxNetworkLogsLimit);
|
|
156
|
+
notify();
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export const getMaxNetworkLogsLimit = (): number => maxNetworkLogsLimit;
|
|
161
|
+
|
|
162
|
+
export const pruneNetworkLogs = (targetCount?: number): number => {
|
|
163
|
+
const countToKeep = targetCount !== undefined ? Math.max(0, targetCount) : Math.floor(logs.length / 2);
|
|
164
|
+
const pruned = logs.length - countToKeep;
|
|
165
|
+
if (pruned > 0) {
|
|
166
|
+
logs = logs.slice(0, countToKeep);
|
|
167
|
+
notify();
|
|
168
|
+
}
|
|
169
|
+
return Math.max(0, pruned);
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// ─── Internal ─────────────────────────────────────────────────────────────────
|
|
173
|
+
|
|
174
|
+
const notify = () => {
|
|
175
|
+
const snapshot = [...logs];
|
|
176
|
+
listeners.forEach((cb) => cb(snapshot));
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const addOrUpdateLog = (log: NetworkLog) => {
|
|
180
|
+
if (!isNetworkModuleEnabled) return;
|
|
181
|
+
const method = log.method?.toUpperCase();
|
|
182
|
+
|
|
183
|
+
if (!ALLOWED_METHODS.includes(method)) return;
|
|
184
|
+
|
|
185
|
+
if (shouldIgnoreUrl(log.url)) return;
|
|
186
|
+
|
|
187
|
+
const index = logs.findIndex((l) => l.id === log.id);
|
|
188
|
+
|
|
189
|
+
if (index >= 0) {
|
|
190
|
+
logs[index] = { ...logs[index], ...log };
|
|
191
|
+
} else {
|
|
192
|
+
logs.unshift(log);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
logs = logs.slice(0, maxNetworkLogsLimit);
|
|
196
|
+
notify();
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// ─── Setup ────────────────────────────────────────────────────────────────────
|
|
200
|
+
|
|
201
|
+
export const setupNetworkLogger = () => {
|
|
202
|
+
if ((globalThis as any).__NETWORK_LOGGER_INITIALIZED__) return;
|
|
203
|
+
(globalThis as any).__NETWORK_LOGGER__ = addOrUpdateLog;
|
|
204
|
+
|
|
205
|
+
const originalFetch = (globalThis as any).fetch;
|
|
206
|
+
|
|
207
|
+
if (originalFetch) {
|
|
208
|
+
(globalThis as any).fetch = async (url: any, options: any = {}) => {
|
|
209
|
+
if (!isNetworkModuleEnabled) return originalFetch(url, options);
|
|
210
|
+
const method = (options?.method || "GET").toUpperCase();
|
|
211
|
+
if (!ALLOWED_METHODS.includes(method)) return originalFetch(url, options);
|
|
212
|
+
|
|
213
|
+
const id = counter++;
|
|
214
|
+
const start = Date.now();
|
|
215
|
+
const finalUrl = typeof url === "string" ? url : url?.url;
|
|
216
|
+
|
|
217
|
+
if (shouldIgnoreUrl(finalUrl)) return originalFetch(url, options);
|
|
218
|
+
|
|
219
|
+
let caller = "Unknown";
|
|
220
|
+
let requestHeaders: Record<string, string> | undefined;
|
|
221
|
+
let client = 'fetch';
|
|
222
|
+
|
|
223
|
+
try {
|
|
224
|
+
requestHeaders = normaliseHeaders(options?.headers);
|
|
225
|
+
caller = getCallerFromStack(); // ✅ Capture call line
|
|
226
|
+
|
|
227
|
+
if (requestHeaders?.['apollographql-client-name'] || finalUrl?.toLowerCase().includes('/graphql')) {
|
|
228
|
+
client = 'apollo';
|
|
229
|
+
} else if (requestHeaders?.['x-requested-with']?.toLowerCase().includes('xmlhttprequest')) {
|
|
230
|
+
client = 'xhr';
|
|
231
|
+
} else if (caller?.toLowerCase().includes('axios')) {
|
|
232
|
+
client = 'axios';
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
addOrUpdateLog({
|
|
236
|
+
id,
|
|
237
|
+
url: finalUrl,
|
|
238
|
+
method,
|
|
239
|
+
startTime: start,
|
|
240
|
+
caller,
|
|
241
|
+
client,
|
|
242
|
+
request: method === "GET" ? undefined : parseRequestData(options?.body),
|
|
243
|
+
requestHeaders,
|
|
244
|
+
});
|
|
245
|
+
} catch {}
|
|
246
|
+
|
|
247
|
+
try {
|
|
248
|
+
const response = await originalFetch(url, options);
|
|
249
|
+
const duration = Date.now() - start;
|
|
250
|
+
|
|
251
|
+
try {
|
|
252
|
+
const responseHeaders = normaliseHeaders(response.headers);
|
|
253
|
+
let data: any = null;
|
|
254
|
+
const contentType =
|
|
255
|
+
responseHeaders?.["content-type"] ||
|
|
256
|
+
responseHeaders?.["Content-Type"] ||
|
|
257
|
+
"";
|
|
258
|
+
if (contentType.includes("image/")) {
|
|
259
|
+
data = "[Image Data]";
|
|
260
|
+
} else {
|
|
261
|
+
try {
|
|
262
|
+
const clone = response.clone();
|
|
263
|
+
const text = await clone.text();
|
|
264
|
+
try {
|
|
265
|
+
data = JSON.parse(text);
|
|
266
|
+
} catch {
|
|
267
|
+
data = text;
|
|
268
|
+
}
|
|
269
|
+
} catch {}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
addOrUpdateLog({
|
|
273
|
+
id,
|
|
274
|
+
url: finalUrl,
|
|
275
|
+
method,
|
|
276
|
+
status: response.status,
|
|
277
|
+
response: data,
|
|
278
|
+
duration,
|
|
279
|
+
startTime: start,
|
|
280
|
+
caller,
|
|
281
|
+
client,
|
|
282
|
+
responseHeaders,
|
|
283
|
+
});
|
|
284
|
+
} catch {}
|
|
285
|
+
|
|
286
|
+
return response;
|
|
287
|
+
} catch (error) {
|
|
288
|
+
try {
|
|
289
|
+
addOrUpdateLog({
|
|
290
|
+
id,
|
|
291
|
+
url: finalUrl,
|
|
292
|
+
method,
|
|
293
|
+
status: 0,
|
|
294
|
+
startTime: start,
|
|
295
|
+
response: error,
|
|
296
|
+
caller,
|
|
297
|
+
client,
|
|
298
|
+
duration: Date.now() - start,
|
|
299
|
+
});
|
|
300
|
+
} catch {}
|
|
301
|
+
throw error;
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Hook Axios — patches both the default instance and any future axios.create() instances
|
|
307
|
+
try {
|
|
308
|
+
if (axios) {
|
|
309
|
+
addAxiosInterceptors(axios);
|
|
310
|
+
const originalCreate = axios.create;
|
|
311
|
+
if (typeof originalCreate === "function") {
|
|
312
|
+
axios.create = function (...args: any[]) {
|
|
313
|
+
const instance = originalCreate.apply(this, args);
|
|
314
|
+
addAxiosInterceptors(instance);
|
|
315
|
+
return instance;
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
} catch (_e) {
|
|
320
|
+
// Axios not available — fetch-only mode
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
try {
|
|
324
|
+
setupGlobalCrashHandler();
|
|
325
|
+
} catch {}
|
|
326
|
+
|
|
327
|
+
(globalThis as any).__NETWORK_LOGGER_INITIALIZED__ = true;
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
// ─── Axios interceptor helper ─────────────────────────────────────────────────
|
|
331
|
+
export const addAxiosInterceptors = (axiosInstance: any) => {
|
|
332
|
+
axiosInstance.interceptors.request.use(async (config: any) => {
|
|
333
|
+
const method = (config.method || "GET").toUpperCase();
|
|
334
|
+
if (!ALLOWED_METHODS.includes(method)) return config;
|
|
335
|
+
|
|
336
|
+
const id = counter++;
|
|
337
|
+
const start = Date.now();
|
|
338
|
+
const caller = getCallerFromStack(); // ✅ Capture call line
|
|
339
|
+
|
|
340
|
+
let url = config.url ?? "";
|
|
341
|
+
if (!url.startsWith("http")) url = `${config.baseURL ?? ""}${url}`;
|
|
342
|
+
|
|
343
|
+
// ✅ Leave config untagged so the response interceptor skips it too.
|
|
344
|
+
if (shouldIgnoreUrl(url)) return config;
|
|
345
|
+
|
|
346
|
+
config.__logId = id;
|
|
347
|
+
config.__logStart = start;
|
|
348
|
+
config.__logCaller = caller;
|
|
349
|
+
|
|
350
|
+
addOrUpdateLog({
|
|
351
|
+
id,
|
|
352
|
+
url,
|
|
353
|
+
method,
|
|
354
|
+
startTime: start,
|
|
355
|
+
caller,
|
|
356
|
+
client: 'axios',
|
|
357
|
+
request: method === "GET" ? undefined : parseRequestData(config.data),
|
|
358
|
+
requestHeaders: normaliseHeaders(config.headers),
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
return config;
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
axiosInstance.interceptors.response.use(
|
|
365
|
+
(response: any) => {
|
|
366
|
+
const config = response.config || {};
|
|
367
|
+
const id = config.__logId;
|
|
368
|
+
const start = config.__logStart;
|
|
369
|
+
const caller = config.__logCaller;
|
|
370
|
+
const method = (config.method || "GET").toUpperCase();
|
|
371
|
+
|
|
372
|
+
if (id == null || !ALLOWED_METHODS.includes(method)) return response;
|
|
373
|
+
|
|
374
|
+
let url = config.url ?? "";
|
|
375
|
+
if (!url.startsWith("http")) url = `${config.baseURL ?? ""}${url}`;
|
|
376
|
+
|
|
377
|
+
addOrUpdateLog({
|
|
378
|
+
id,
|
|
379
|
+
url,
|
|
380
|
+
method,
|
|
381
|
+
status: response.status,
|
|
382
|
+
response: response.data,
|
|
383
|
+
startTime: start || Date.now(),
|
|
384
|
+
duration: start != null ? Date.now() - start : undefined,
|
|
385
|
+
caller,
|
|
386
|
+
client: 'axios',
|
|
387
|
+
responseHeaders: normaliseHeaders(response.headers),
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
return response;
|
|
391
|
+
},
|
|
392
|
+
(error: any) => {
|
|
393
|
+
const config = error.config || {};
|
|
394
|
+
const id = config.__logId;
|
|
395
|
+
const start = config.__logStart;
|
|
396
|
+
const caller = config.__logCaller;
|
|
397
|
+
const method = (config.method || "GET").toUpperCase();
|
|
398
|
+
|
|
399
|
+
if (id != null && ALLOWED_METHODS.includes(method)) {
|
|
400
|
+
let url = config.url ?? "";
|
|
401
|
+
if (!url.startsWith("http")) url = `${config.baseURL ?? ""}${url}`;
|
|
402
|
+
|
|
403
|
+
addOrUpdateLog({
|
|
404
|
+
id,
|
|
405
|
+
url,
|
|
406
|
+
method,
|
|
407
|
+
status: error.response?.status ?? 0,
|
|
408
|
+
response: error.response?.data ?? error.message,
|
|
409
|
+
startTime: start || Date.now(),
|
|
410
|
+
duration: start != null ? Date.now() - start : undefined,
|
|
411
|
+
caller,
|
|
412
|
+
client: 'axios',
|
|
413
|
+
responseHeaders: normaliseHeaders(error.response?.headers),
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
return Promise.reject(error);
|
|
417
|
+
},
|
|
418
|
+
);
|
|
419
|
+
};
|