react-native-inapp-inspector 1.0.13 → 1.0.15

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.
@@ -19,3 +19,4 @@ export declare const logAnalyticsEvent: (name: string, params?: Record<string, a
19
19
  * setupAnalyticsLogger(analytics());
20
20
  */
21
21
  export declare const setupAnalyticsLogger: (analyticsInstance: any) => void;
22
+ export declare const autoSetupAnalyticsLogger: () => boolean;
@@ -30,7 +30,7 @@ let currentUserId;
30
30
  // ─── Core helpers ─────────────────────────────────────────────────────────────
31
31
  const notify = () => {
32
32
  const snapshot = [...events];
33
- listeners.forEach((cb) => cb(snapshot));
33
+ listeners.forEach(cb => cb(snapshot));
34
34
  };
35
35
  const addEvent = (event) => {
36
36
  events.unshift(event);
@@ -42,7 +42,7 @@ export const subscribeAnalyticsEvents = (callback) => {
42
42
  listeners.push(callback);
43
43
  callback([...events]);
44
44
  return () => {
45
- listeners = listeners.filter((l) => l !== callback);
45
+ listeners = listeners.filter(l => l !== callback);
46
46
  };
47
47
  };
48
48
  export const clearAnalyticsEvents = () => {
@@ -62,10 +62,10 @@ export const logAnalyticsEvent = (name, params = {}, userProperties = {}) => {
62
62
  params,
63
63
  userProperties: { ...currentUserProperties, ...userProperties },
64
64
  timestamp: Date.now(),
65
- source: "manual",
66
- userId: currentUserId ?? "",
67
- screenName: "",
68
- screenClass: "",
65
+ source: 'manual',
66
+ userId: currentUserId ?? '',
67
+ screenName: '',
68
+ screenClass: '',
69
69
  });
70
70
  };
71
71
  // ─── Firebase Analytics instance patcher ─────────────────────────────────────
@@ -82,7 +82,7 @@ export const logAnalyticsEvent = (name, params = {}, userProperties = {}) => {
82
82
  */
83
83
  export const setupAnalyticsLogger = (analyticsInstance) => {
84
84
  if (!analyticsInstance) {
85
- console.warn("[AnalyticsLogger] No analytics instance provided — skipping setup.");
85
+ console.warn('[AnalyticsLogger] No analytics instance provided — skipping setup.');
86
86
  return;
87
87
  }
88
88
  // Guard against double-patching the same instance
@@ -98,10 +98,10 @@ export const setupAnalyticsLogger = (analyticsInstance) => {
98
98
  params: params ?? {},
99
99
  userProperties: { ...currentUserProperties },
100
100
  timestamp: Date.now(),
101
- source: "firebase",
102
- userId: currentUserId ?? "",
103
- screenName: "",
104
- screenClass: "",
101
+ source: 'firebase',
102
+ userId: currentUserId ?? '',
103
+ screenName: '',
104
+ screenClass: '',
105
105
  });
106
106
  return originalLogEvent(name, params);
107
107
  };
@@ -110,14 +110,14 @@ export const setupAnalyticsLogger = (analyticsInstance) => {
110
110
  analyticsInstance.logScreenView = async (params) => {
111
111
  addEvent({
112
112
  id: counter++,
113
- name: "screen_view",
113
+ name: 'screen_view',
114
114
  params: params ?? {},
115
115
  userProperties: { ...currentUserProperties },
116
116
  timestamp: Date.now(),
117
- source: "firebase",
118
- screenName: params?.screen_name ?? "",
119
- screenClass: params?.screen_class ?? "",
120
- userId: currentUserId ?? "",
117
+ source: 'firebase',
118
+ screenName: params?.screen_name ?? '',
119
+ screenClass: params?.screen_class ?? '',
120
+ userId: currentUserId ?? '',
121
121
  });
122
122
  return originalLogScreenView(params);
123
123
  };
@@ -150,3 +150,42 @@ export const setupAnalyticsLogger = (analyticsInstance) => {
150
150
  return originalSetUserId(id);
151
151
  };
152
152
  };
153
+ export const autoSetupAnalyticsLogger = () => {
154
+ if (globalThis.__INSPECTOR_ANALYTICS_AUTOSETUP__)
155
+ return true;
156
+ let mod;
157
+ try {
158
+ mod = require('@react-native-firebase/analytics'); // optional dep
159
+ }
160
+ catch {
161
+ return false; // GA not installed — silent no-op
162
+ }
163
+ const accessor = mod?.default ?? mod;
164
+ if (typeof accessor !== 'function')
165
+ return false;
166
+ try {
167
+ setupAnalyticsLogger(accessor());
168
+ }
169
+ catch { } // patch default-app instance
170
+ if (!accessor.__INSPECTOR_WRAPPED__) {
171
+ // patch future/named instances
172
+ const wrapped = function (...args) {
173
+ const instance = accessor.apply(this, args);
174
+ try {
175
+ setupAnalyticsLogger(instance);
176
+ }
177
+ catch { }
178
+ return instance;
179
+ };
180
+ Object.setPrototypeOf(wrapped, accessor);
181
+ Object.assign(wrapped, accessor);
182
+ wrapped.__INSPECTOR_WRAPPED__ = true;
183
+ try {
184
+ if (mod.default !== undefined)
185
+ mod.default = wrapped;
186
+ }
187
+ catch { }
188
+ }
189
+ globalThis.__INSPECTOR_ANALYTICS_AUTOSETUP__ = true;
190
+ return true;
191
+ };
@@ -1,4 +1,4 @@
1
- import './webViewLogger';
1
+ import "./webViewLogger";
2
2
  type NetworkLog = {
3
3
  id: number;
4
4
  url: string;
@@ -1,13 +1,20 @@
1
- import './webViewLogger';
1
+ import "./webViewLogger";
2
+ import axios from "axios";
2
3
  let logs = [];
3
4
  let listeners = [];
4
5
  let counter = 0;
5
- const ALLOWED_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
6
+ const ALLOWED_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
7
+ const IGNORED_URL_PATTERNS = [/\/symbolicate(?:[/?#]|$)/];
8
+ function shouldIgnoreUrl(url) {
9
+ if (!url)
10
+ return false;
11
+ return IGNORED_URL_PATTERNS.some((re) => re.test(url));
12
+ }
6
13
  // ─── Helpers ──────────────────────────────────────────────────────────────────
7
14
  function normaliseHeaders(raw) {
8
15
  if (!raw)
9
16
  return undefined;
10
- if (typeof raw.forEach === 'function') {
17
+ if (typeof raw.forEach === "function") {
11
18
  const result = {};
12
19
  raw.forEach((value, key) => {
13
20
  result[key] = value;
@@ -39,11 +46,11 @@ function parseRequestData(data) {
39
46
  data._parts.forEach((part) => {
40
47
  const key = part[0];
41
48
  const value = part[1];
42
- if (value && typeof value === 'object' && value.uri) {
49
+ if (value && typeof value === "object" && value.uri) {
43
50
  parsedFormData[key] = {
44
51
  _isFile: true,
45
- name: value.name || 'unknown',
46
- type: value.type || 'unknown',
52
+ name: value.name || "unknown",
53
+ type: value.type || "unknown",
47
54
  uri: value.uri,
48
55
  };
49
56
  }
@@ -60,29 +67,29 @@ function getCallerFromStack() {
60
67
  try {
61
68
  const stack = new Error().stack;
62
69
  if (!stack)
63
- return 'Unknown';
64
- const lines = stack.split('\n');
70
+ return "Unknown";
71
+ const lines = stack.split("\n");
65
72
  for (let i = 0; i < lines.length; i++) {
66
73
  const line = lines[i];
67
74
  // Skip internal react-native network modules and the logger itself
68
- if (line.includes('networkLogger') ||
69
- line.includes('node_modules') ||
70
- line.includes('Error') ||
71
- line.includes('regeneratorRuntime')) {
75
+ if (line.includes("networkLogger") ||
76
+ line.includes("node_modules") ||
77
+ line.includes("Error") ||
78
+ line.includes("regeneratorRuntime")) {
72
79
  continue;
73
80
  }
74
- return line.trim().replace(/^at /, '');
81
+ return line.trim().replace(/^at /, "");
75
82
  }
76
83
  }
77
84
  catch (e) { }
78
- return 'Unknown';
85
+ return "Unknown";
79
86
  }
80
87
  // ─── Subscribe ────────────────────────────────────────────────────────────────
81
88
  export const subscribeNetworkLogs = (callback) => {
82
89
  listeners.push(callback);
83
90
  callback([...logs]);
84
91
  return () => {
85
- listeners = listeners.filter(l => l !== callback);
92
+ listeners = listeners.filter((l) => l !== callback);
86
93
  };
87
94
  };
88
95
  export const clearNetworkLogs = () => {
@@ -93,13 +100,15 @@ export const getNetworkLogs = () => [...logs];
93
100
  // ─── Internal ─────────────────────────────────────────────────────────────────
94
101
  const notify = () => {
95
102
  const snapshot = [...logs];
96
- listeners.forEach(cb => cb(snapshot));
103
+ listeners.forEach((cb) => cb(snapshot));
97
104
  };
98
105
  const addOrUpdateLog = (log) => {
99
106
  const method = log.method?.toUpperCase();
100
107
  if (!ALLOWED_METHODS.includes(method))
101
108
  return;
102
- const index = logs.findIndex(l => l.id === log.id);
109
+ if (shouldIgnoreUrl(log.url))
110
+ return;
111
+ const index = logs.findIndex((l) => l.id === log.id);
103
112
  if (index >= 0) {
104
113
  logs[index] = { ...logs[index], ...log };
105
114
  }
@@ -117,12 +126,14 @@ export const setupNetworkLogger = () => {
117
126
  const originalFetch = globalThis.fetch;
118
127
  if (originalFetch) {
119
128
  globalThis.fetch = async (url, options = {}) => {
120
- const method = (options?.method || 'GET').toUpperCase();
129
+ const method = (options?.method || "GET").toUpperCase();
121
130
  if (!ALLOWED_METHODS.includes(method))
122
131
  return originalFetch(url, options);
123
132
  const id = counter++;
124
133
  const start = Date.now();
125
- const finalUrl = typeof url === 'string' ? url : url?.url;
134
+ const finalUrl = typeof url === "string" ? url : url?.url;
135
+ if (shouldIgnoreUrl(finalUrl))
136
+ return originalFetch(url, options);
126
137
  const requestHeaders = normaliseHeaders(options?.headers);
127
138
  const caller = getCallerFromStack(); // ✅ Capture call line
128
139
  addOrUpdateLog({
@@ -131,7 +142,7 @@ export const setupNetworkLogger = () => {
131
142
  method,
132
143
  startTime: start,
133
144
  caller,
134
- request: method === 'GET' ? undefined : parseRequestData(options?.body),
145
+ request: method === "GET" ? undefined : parseRequestData(options?.body),
135
146
  requestHeaders,
136
147
  });
137
148
  try {
@@ -139,11 +150,11 @@ export const setupNetworkLogger = () => {
139
150
  const duration = Date.now() - start;
140
151
  const responseHeaders = normaliseHeaders(response.headers);
141
152
  let data = null;
142
- const contentType = responseHeaders?.['content-type'] ||
143
- responseHeaders?.['Content-Type'] ||
144
- '';
145
- if (contentType.includes('image/')) {
146
- data = '[Image Data]';
153
+ const contentType = responseHeaders?.["content-type"] ||
154
+ responseHeaders?.["Content-Type"] ||
155
+ "";
156
+ if (contentType.includes("image/")) {
157
+ data = "[Image Data]";
147
158
  }
148
159
  else {
149
160
  try {
@@ -186,52 +197,50 @@ export const setupNetworkLogger = () => {
186
197
  }
187
198
  };
188
199
  }
189
- // Auto-detect and hook Axios dynamically without requiring manual setup
200
+ // Hook Axios patches both the default instance and any future axios.create() instances
190
201
  try {
191
- const req = typeof require !== 'undefined' ? require : undefined;
192
- if (req) {
193
- const axios = Function('r', 'try { return r("axios"); } catch(e) { return null; }')(req);
194
- const targetAxios = axios && (axios.default || axios);
195
- if (targetAxios) {
196
- addAxiosInterceptors(targetAxios);
197
- const originalCreate = targetAxios.create;
198
- if (typeof originalCreate === 'function') {
199
- targetAxios.create = function (...args) {
200
- const instance = originalCreate.apply(this, args);
201
- addAxiosInterceptors(instance);
202
- return instance;
203
- };
204
- }
202
+ if (axios) {
203
+ addAxiosInterceptors(axios);
204
+ const originalCreate = axios.create;
205
+ if (typeof originalCreate === "function") {
206
+ axios.create = function (...args) {
207
+ const instance = originalCreate.apply(this, args);
208
+ addAxiosInterceptors(instance);
209
+ return instance;
210
+ };
205
211
  }
206
212
  }
207
213
  }
208
- catch (e) {
209
- // Silent fail
214
+ catch (_e) {
215
+ // Axios not available — fetch-only mode
210
216
  }
211
217
  globalThis.__NETWORK_LOGGER_INITIALIZED__ = true;
212
218
  };
213
219
  // ─── Axios interceptor helper ─────────────────────────────────────────────────
214
220
  export const addAxiosInterceptors = (axiosInstance) => {
215
221
  axiosInstance.interceptors.request.use(async (config) => {
216
- const method = (config.method || 'GET').toUpperCase();
222
+ const method = (config.method || "GET").toUpperCase();
217
223
  if (!ALLOWED_METHODS.includes(method))
218
224
  return config;
219
225
  const id = counter++;
220
226
  const start = Date.now();
221
227
  const caller = getCallerFromStack(); // ✅ Capture call line
228
+ let url = config.url ?? "";
229
+ if (!url.startsWith("http"))
230
+ url = `${config.baseURL ?? ""}${url}`;
231
+ // ✅ Leave config untagged so the response interceptor skips it too.
232
+ if (shouldIgnoreUrl(url))
233
+ return config;
222
234
  config.__logId = id;
223
235
  config.__logStart = start;
224
236
  config.__logCaller = caller;
225
- let url = config.url ?? '';
226
- if (!url.startsWith('http'))
227
- url = `${config.baseURL ?? ''}${url}`;
228
237
  addOrUpdateLog({
229
238
  id,
230
239
  url,
231
240
  method,
232
241
  startTime: start,
233
242
  caller,
234
- request: method === 'GET' ? undefined : parseRequestData(config.data),
243
+ request: method === "GET" ? undefined : parseRequestData(config.data),
235
244
  requestHeaders: normaliseHeaders(config.headers),
236
245
  });
237
246
  return config;
@@ -241,12 +250,12 @@ export const addAxiosInterceptors = (axiosInstance) => {
241
250
  const id = config.__logId;
242
251
  const start = config.__logStart;
243
252
  const caller = config.__logCaller;
244
- const method = (config.method || 'GET').toUpperCase();
253
+ const method = (config.method || "GET").toUpperCase();
245
254
  if (id == null || !ALLOWED_METHODS.includes(method))
246
255
  return response;
247
- let url = config.url ?? '';
248
- if (!url.startsWith('http'))
249
- url = `${config.baseURL ?? ''}${url}`;
256
+ let url = config.url ?? "";
257
+ if (!url.startsWith("http"))
258
+ url = `${config.baseURL ?? ""}${url}`;
250
259
  addOrUpdateLog({
251
260
  id,
252
261
  url,
@@ -264,11 +273,11 @@ export const addAxiosInterceptors = (axiosInstance) => {
264
273
  const id = config.__logId;
265
274
  const start = config.__logStart;
266
275
  const caller = config.__logCaller;
267
- const method = (config.method || 'GET').toUpperCase();
276
+ const method = (config.method || "GET").toUpperCase();
268
277
  if (id != null && ALLOWED_METHODS.includes(method)) {
269
- let url = config.url ?? '';
270
- if (!url.startsWith('http'))
271
- url = `${config.baseURL ?? ''}${url}`;
278
+ let url = config.url ?? "";
279
+ if (!url.startsWith("http"))
280
+ url = `${config.baseURL ?? ""}${url}`;
272
281
  addOrUpdateLog({
273
282
  id,
274
283
  url,
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  declare const NetworkInspectorWrapper: (props: any) => React.JSX.Element;
3
3
  export default NetworkInspectorWrapper;
4
- export { setupNetworkLogger, clearNetworkLogs, subscribeNetworkLogs, } from './customHooks/networkLogger';
4
+ export { setupNetworkLogger, clearNetworkLogs, subscribeNetworkLogs, addAxiosInterceptors, } from './customHooks/networkLogger';
5
5
  export { setupConsoleLogger, clearConsoleLogs, subscribeConsoleLogs, } from './customHooks/consoleLogger';
6
6
  export { setupAnalyticsLogger, logAnalyticsEvent, subscribeAnalyticsEvents, clearAnalyticsEvents, } from './customHooks/analyticsLogger';
7
7
  export { WebView, getWebViewLogs, getWebViewNavHistory, getWebViewHtml, getWebViewCss, getWebViewJs, getWebViewHtmlUrl, clearWebViewData, subscribeWebView, } from './customHooks/webViewLogger';