react-native-inapp-inspector 1.1.24 → 1.1.26

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 (114) hide show
  1. package/android/build.gradle +36 -0
  2. package/android/src/main/AndroidManifest.xml +3 -0
  3. package/android/src/main/java/com/inappinspector/NetworkInspectorModule.java +114 -0
  4. package/android/src/main/java/com/inappinspector/NetworkInspectorPackage.java +28 -0
  5. package/dist/commonjs/components/AnalyticsEventCard.js +94 -88
  6. package/dist/commonjs/components/ConsoleLogCard.js +49 -25
  7. package/dist/commonjs/components/ErrorBoundary.d.ts +1 -1
  8. package/dist/commonjs/components/ErrorBoundary.js +9 -145
  9. package/dist/commonjs/components/Inspector/AnalyticsFilterModal.d.ts +7 -0
  10. package/dist/commonjs/components/Inspector/AnalyticsFilterModal.js +1002 -0
  11. package/dist/commonjs/components/Inspector/AnalyticsTab.js +637 -10
  12. package/dist/commonjs/components/Inspector/BundleTab.d.ts +1 -1
  13. package/dist/commonjs/components/Inspector/BundleTab.js +826 -406
  14. package/dist/commonjs/components/Inspector/CrashDetail.d.ts +3 -0
  15. package/dist/commonjs/components/Inspector/CrashDetail.js +796 -0
  16. package/dist/commonjs/components/Inspector/CrashFilterModal.d.ts +20 -0
  17. package/dist/commonjs/components/Inspector/CrashFilterModal.js +597 -0
  18. package/dist/commonjs/components/Inspector/CrashTab.d.ts +3 -0
  19. package/dist/commonjs/components/Inspector/CrashTab.js +727 -0
  20. package/dist/commonjs/components/Inspector/InspectorContext.js +6 -1
  21. package/dist/commonjs/components/Inspector/InspectorHeader.js +65 -28
  22. package/dist/commonjs/components/Inspector/LogDetail.js +227 -114
  23. package/dist/commonjs/components/Inspector/MainScreen.js +13 -4
  24. package/dist/commonjs/components/Inspector/NetworkDetail.js +131 -81
  25. package/dist/commonjs/components/Inspector/PerformanceTab.js +20 -10
  26. package/dist/commonjs/components/Inspector/SettingsPanel.js +90 -1
  27. package/dist/commonjs/components/Inspector/TabBar.js +15 -3
  28. package/dist/commonjs/components/NetworkIcons.d.ts +25 -0
  29. package/dist/commonjs/components/NetworkIcons.js +188 -1
  30. package/dist/commonjs/components/SegmentedTabs.js +33 -23
  31. package/dist/commonjs/components/TreeNode.js +13 -12
  32. package/dist/commonjs/constants/version.d.ts +1 -1
  33. package/dist/commonjs/constants/version.js +1 -1
  34. package/dist/commonjs/customHooks/analyticsLogger.js +70 -44
  35. package/dist/commonjs/customHooks/bundleAnalyzer.d.ts +5 -1
  36. package/dist/commonjs/customHooks/bundleAnalyzer.js +497 -126
  37. package/dist/commonjs/customHooks/consoleLogger.d.ts +1 -0
  38. package/dist/commonjs/customHooks/consoleLogger.js +153 -51
  39. package/dist/commonjs/customHooks/crashHandler.d.ts +64 -0
  40. package/dist/commonjs/customHooks/crashHandler.js +681 -0
  41. package/dist/commonjs/customHooks/networkLogger.js +74 -49
  42. package/dist/commonjs/customHooks/performanceTracker.d.ts +8 -0
  43. package/dist/commonjs/customHooks/performanceTracker.js +44 -3
  44. package/dist/commonjs/decorators/index.d.ts +49 -0
  45. package/dist/commonjs/decorators/index.js +142 -0
  46. package/dist/commonjs/helpers/gaAnalyticsRegistry.d.ts +18 -0
  47. package/dist/commonjs/helpers/gaAnalyticsRegistry.js +174 -0
  48. package/dist/commonjs/helpers/index.d.ts +7 -4
  49. package/dist/commonjs/helpers/index.js +102 -64
  50. package/dist/commonjs/i18n/locales/en.json +182 -4
  51. package/dist/commonjs/index.d.ts +6 -0
  52. package/dist/commonjs/index.js +310 -8
  53. package/dist/commonjs/styles/index.d.ts +4 -1
  54. package/dist/commonjs/styles/index.js +22 -19
  55. package/dist/commonjs/types/enums.d.ts +156 -9
  56. package/dist/commonjs/types/enums.js +139 -2
  57. package/dist/commonjs/types/interfaces.d.ts +70 -1
  58. package/dist/esm/components/AnalyticsEventCard.js +95 -89
  59. package/dist/esm/components/ConsoleLogCard.js +49 -25
  60. package/dist/esm/components/ErrorBoundary.d.ts +1 -1
  61. package/dist/esm/components/ErrorBoundary.js +10 -113
  62. package/dist/esm/components/Inspector/AnalyticsFilterModal.d.ts +7 -0
  63. package/dist/esm/components/Inspector/AnalyticsFilterModal.js +964 -0
  64. package/dist/esm/components/Inspector/AnalyticsTab.js +639 -12
  65. package/dist/esm/components/Inspector/BundleTab.d.ts +1 -1
  66. package/dist/esm/components/Inspector/BundleTab.js +827 -407
  67. package/dist/esm/components/Inspector/CrashDetail.d.ts +3 -0
  68. package/dist/esm/components/Inspector/CrashDetail.js +758 -0
  69. package/dist/esm/components/Inspector/CrashFilterModal.d.ts +20 -0
  70. package/dist/esm/components/Inspector/CrashFilterModal.js +557 -0
  71. package/dist/esm/components/Inspector/CrashTab.d.ts +3 -0
  72. package/dist/esm/components/Inspector/CrashTab.js +689 -0
  73. package/dist/esm/components/Inspector/InspectorContext.js +1 -0
  74. package/dist/esm/components/Inspector/InspectorHeader.js +66 -29
  75. package/dist/esm/components/Inspector/LogDetail.js +227 -114
  76. package/dist/esm/components/Inspector/MainScreen.js +14 -5
  77. package/dist/esm/components/Inspector/NetworkDetail.js +132 -49
  78. package/dist/esm/components/Inspector/PerformanceTab.js +20 -10
  79. package/dist/esm/components/Inspector/SettingsPanel.js +91 -2
  80. package/dist/esm/components/Inspector/TabBar.js +16 -4
  81. package/dist/esm/components/NetworkIcons.d.ts +25 -0
  82. package/dist/esm/components/NetworkIcons.js +161 -0
  83. package/dist/esm/components/SegmentedTabs.js +33 -23
  84. package/dist/esm/components/TreeNode.js +13 -12
  85. package/dist/esm/constants/version.d.ts +1 -1
  86. package/dist/esm/constants/version.js +1 -1
  87. package/dist/esm/customHooks/analyticsLogger.js +70 -44
  88. package/dist/esm/customHooks/bundleAnalyzer.d.ts +5 -1
  89. package/dist/esm/customHooks/bundleAnalyzer.js +493 -125
  90. package/dist/esm/customHooks/consoleLogger.d.ts +1 -0
  91. package/dist/esm/customHooks/consoleLogger.js +151 -50
  92. package/dist/esm/customHooks/crashHandler.d.ts +64 -0
  93. package/dist/esm/customHooks/crashHandler.js +659 -0
  94. package/dist/esm/customHooks/networkLogger.js +74 -49
  95. package/dist/esm/customHooks/performanceTracker.d.ts +8 -0
  96. package/dist/esm/customHooks/performanceTracker.js +38 -1
  97. package/dist/esm/decorators/index.d.ts +49 -0
  98. package/dist/esm/decorators/index.js +137 -0
  99. package/dist/esm/helpers/gaAnalyticsRegistry.d.ts +18 -0
  100. package/dist/esm/helpers/gaAnalyticsRegistry.js +169 -0
  101. package/dist/esm/helpers/index.d.ts +7 -4
  102. package/dist/esm/helpers/index.js +100 -63
  103. package/dist/esm/i18n/locales/en.json +182 -4
  104. package/dist/esm/index.d.ts +6 -0
  105. package/dist/esm/index.js +262 -8
  106. package/dist/esm/styles/index.d.ts +4 -1
  107. package/dist/esm/styles/index.js +22 -19
  108. package/dist/esm/types/enums.d.ts +156 -9
  109. package/dist/esm/types/enums.js +138 -3
  110. package/dist/esm/types/interfaces.d.ts +70 -1
  111. package/ios/NetworkInspectorModule.h +6 -0
  112. package/ios/NetworkInspectorModule.m +125 -0
  113. package/package.json +5 -2
  114. package/react-native-inapp-inspector.podspec +18 -0
@@ -5,11 +5,21 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.addAxiosInterceptors = exports.setupNetworkLogger = exports.getNetworkLogs = exports.clearNetworkLogs = exports.subscribeNetworkLogs = void 0;
7
7
  const axios_1 = __importDefault(require("axios"));
8
+ const crashHandler_1 = require("./crashHandler");
8
9
  let logs = [];
9
10
  let listeners = [];
10
11
  let counter = 0;
11
12
  const ALLOWED_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
12
- const IGNORED_URL_PATTERNS = [/\/symbolicate(?:[/?#]|$)/];
13
+ const IGNORED_URL_PATTERNS = [
14
+ /\/symbolicate(?:[/?#]|$)/i,
15
+ /\/index\.bundle(?:\?|$)/i,
16
+ /\/hot(?:\?|$)/i,
17
+ /\/message(?:\?|$)/i,
18
+ /\/open-debugger(?:\?|$)/i,
19
+ /\/status(?:\?|$)/i,
20
+ /127\.0\.0\.1:(?:8081|8082|8083|19000|19001|19002|3000|8000)/i,
21
+ /localhost:(?:8081|8082|8083|19000|19001|19002|3000|8000)\/index\.bundle/i,
22
+ ];
13
23
  function shouldIgnoreUrl(url) {
14
24
  if (!url)
15
25
  return false;
@@ -142,65 +152,76 @@ const setupNetworkLogger = () => {
142
152
  const finalUrl = typeof url === "string" ? url : url?.url;
143
153
  if (shouldIgnoreUrl(finalUrl))
144
154
  return originalFetch(url, options);
145
- const requestHeaders = normaliseHeaders(options?.headers);
146
- const caller = getCallerFromStack(); // ✅ Capture call line
147
- addOrUpdateLog({
148
- id,
149
- url: finalUrl,
150
- method,
151
- startTime: start,
152
- caller,
153
- request: method === "GET" ? undefined : parseRequestData(options?.body),
154
- requestHeaders,
155
- });
155
+ let caller = "Unknown";
156
+ let requestHeaders;
156
157
  try {
157
- const response = await originalFetch(url, options);
158
- const duration = Date.now() - start;
159
- const responseHeaders = normaliseHeaders(response.headers);
160
- let data = null;
161
- const contentType = responseHeaders?.["content-type"] ||
162
- responseHeaders?.["Content-Type"] ||
163
- "";
164
- if (contentType.includes("image/")) {
165
- data = "[Image Data]";
166
- }
167
- else {
168
- try {
169
- const clone = response.clone();
170
- const text = await clone.text();
171
- try {
172
- data = JSON.parse(text);
173
- }
174
- catch {
175
- data = text;
176
- }
177
- }
178
- catch { }
179
- }
158
+ requestHeaders = normaliseHeaders(options?.headers);
159
+ caller = getCallerFromStack(); // ✅ Capture call line
180
160
  addOrUpdateLog({
181
161
  id,
182
162
  url: finalUrl,
183
163
  method,
184
- status: response.status,
185
- response: data,
186
- duration,
187
164
  startTime: start,
188
165
  caller,
189
- responseHeaders,
166
+ request: method === "GET" ? undefined : parseRequestData(options?.body),
167
+ requestHeaders,
190
168
  });
169
+ }
170
+ catch { }
171
+ try {
172
+ const response = await originalFetch(url, options);
173
+ const duration = Date.now() - start;
174
+ try {
175
+ const responseHeaders = normaliseHeaders(response.headers);
176
+ let data = null;
177
+ const contentType = responseHeaders?.["content-type"] ||
178
+ responseHeaders?.["Content-Type"] ||
179
+ "";
180
+ if (contentType.includes("image/")) {
181
+ data = "[Image Data]";
182
+ }
183
+ else {
184
+ try {
185
+ const clone = response.clone();
186
+ const text = await clone.text();
187
+ try {
188
+ data = JSON.parse(text);
189
+ }
190
+ catch {
191
+ data = text;
192
+ }
193
+ }
194
+ catch { }
195
+ }
196
+ addOrUpdateLog({
197
+ id,
198
+ url: finalUrl,
199
+ method,
200
+ status: response.status,
201
+ response: data,
202
+ duration,
203
+ startTime: start,
204
+ caller,
205
+ responseHeaders,
206
+ });
207
+ }
208
+ catch { }
191
209
  return response;
192
210
  }
193
211
  catch (error) {
194
- addOrUpdateLog({
195
- id,
196
- url: finalUrl,
197
- method,
198
- status: 0,
199
- startTime: start,
200
- response: error,
201
- caller,
202
- duration: Date.now() - start,
203
- });
212
+ try {
213
+ addOrUpdateLog({
214
+ id,
215
+ url: finalUrl,
216
+ method,
217
+ status: 0,
218
+ startTime: start,
219
+ response: error,
220
+ caller,
221
+ duration: Date.now() - start,
222
+ });
223
+ }
224
+ catch { }
204
225
  throw error;
205
226
  }
206
227
  };
@@ -222,6 +243,10 @@ const setupNetworkLogger = () => {
222
243
  catch (_e) {
223
244
  // Axios not available — fetch-only mode
224
245
  }
246
+ try {
247
+ (0, crashHandler_1.setupGlobalCrashHandler)();
248
+ }
249
+ catch { }
225
250
  globalThis.__NETWORK_LOGGER_INITIALIZED__ = true;
226
251
  };
227
252
  exports.setupNetworkLogger = setupNetworkLogger;
@@ -54,6 +54,7 @@ export interface ComponentRenderProfile {
54
54
  fixKeys: PerformanceFixKey[];
55
55
  severity: 'optimal' | 'warning' | 'critical';
56
56
  }
57
+ export declare const INITIAL_EVENTS: PerformanceEvent[];
57
58
  export declare const usePerformanceTracker: () => {
58
59
  isRecording: boolean;
59
60
  setIsRecording: import("react").Dispatch<import("react").SetStateAction<boolean>>;
@@ -82,3 +83,10 @@ export declare const usePerformanceTracker: () => {
82
83
  clearEvents: () => void;
83
84
  triggerGc: () => void;
84
85
  };
86
+ export declare const logPerformanceEvent: (event: Omit<PerformanceEvent, "id" | "timestamp"> & {
87
+ id?: string;
88
+ timestamp?: number;
89
+ }) => PerformanceEvent;
90
+ export declare const clearPerformanceEvents: () => void;
91
+ export declare const subscribePerformanceEvents: (listener: (events: PerformanceEvent[]) => void) => () => void;
92
+ export declare const getPerformanceEvents: () => PerformanceEvent[];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.usePerformanceTracker = void 0;
3
+ exports.getPerformanceEvents = exports.subscribePerformanceEvents = exports.clearPerformanceEvents = exports.logPerformanceEvent = exports.usePerformanceTracker = exports.INITIAL_EVENTS = void 0;
4
4
  const AppColors_1 = require("../styles/AppColors");
5
5
  const react_1 = require("react");
6
6
  const INITIAL_RENDER_PROFILES = [
@@ -173,7 +173,7 @@ const INITIAL_RENDER_PROFILES = [
173
173
  severity: 'optimal',
174
174
  },
175
175
  ];
176
- const INITIAL_EVENTS = [
176
+ exports.INITIAL_EVENTS = [
177
177
  {
178
178
  id: 'perf-1',
179
179
  timestamp: Date.now() - 48000,
@@ -351,7 +351,7 @@ const usePerformanceTracker = () => {
351
351
  allocationRateMbPerSec: 1.8,
352
352
  });
353
353
  const [renderProfiles, setRenderProfiles] = (0, react_1.useState)(INITIAL_RENDER_PROFILES);
354
- const [events, setEvents] = (0, react_1.useState)(INITIAL_EVENTS);
354
+ const [events, setEvents] = (0, react_1.useState)(exports.INITIAL_EVENTS);
355
355
  const lastFrameTimeRef = (0, react_1.useRef)(Date.now());
356
356
  const rafIdRef = (0, react_1.useRef)(null);
357
357
  // Live Frame Measurement Loop
@@ -539,3 +539,44 @@ const usePerformanceTracker = () => {
539
539
  };
540
540
  };
541
541
  exports.usePerformanceTracker = usePerformanceTracker;
542
+ const globalPerformanceEvents = [...exports.INITIAL_EVENTS];
543
+ const performanceListeners = new Set();
544
+ const logPerformanceEvent = (event) => {
545
+ const fullEvent = {
546
+ id: event.id || `perf-${Date.now()}-${Math.random().toString(36).substring(2, 6)}`,
547
+ timestamp: event.timestamp || Date.now(),
548
+ ...event,
549
+ };
550
+ globalPerformanceEvents.unshift(fullEvent);
551
+ if (globalPerformanceEvents.length > 100) {
552
+ globalPerformanceEvents.pop();
553
+ }
554
+ performanceListeners.forEach(listener => {
555
+ try {
556
+ listener([...globalPerformanceEvents]);
557
+ }
558
+ catch { }
559
+ });
560
+ return fullEvent;
561
+ };
562
+ exports.logPerformanceEvent = logPerformanceEvent;
563
+ const clearPerformanceEvents = () => {
564
+ globalPerformanceEvents.length = 0;
565
+ performanceListeners.forEach(listener => {
566
+ try {
567
+ listener([]);
568
+ }
569
+ catch { }
570
+ });
571
+ };
572
+ exports.clearPerformanceEvents = clearPerformanceEvents;
573
+ const subscribePerformanceEvents = (listener) => {
574
+ performanceListeners.add(listener);
575
+ listener([...globalPerformanceEvents]);
576
+ return () => {
577
+ performanceListeners.delete(listener);
578
+ };
579
+ };
580
+ exports.subscribePerformanceEvents = subscribePerformanceEvents;
581
+ const getPerformanceEvents = () => [...globalPerformanceEvents];
582
+ exports.getPerformanceEvents = getPerformanceEvents;
@@ -0,0 +1,49 @@
1
+ export interface InspectLogOptions {
2
+ tag?: string;
3
+ logArgs?: boolean;
4
+ logResult?: boolean;
5
+ logDuration?: boolean;
6
+ }
7
+ /**
8
+ * `@InspectLog`: Automatically logs method execution, arguments, duration, and return values
9
+ * to the In-App Inspector Console.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * class UserService {
14
+ * @InspectLog({ tag: 'API', logArgs: true, logDuration: true })
15
+ * async fetchUser(id: string) {
16
+ * return api.get(`/users/${id}`);
17
+ * }
18
+ * }
19
+ * ```
20
+ */
21
+ export declare function InspectLog(options?: InspectLogOptions): (_target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
22
+ /**
23
+ * `@InspectTrackTime`: Measures and logs execution duration for critical functions.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * class FeedManager {
28
+ * @InspectTrackTime('Feed Data Processing')
29
+ * processFeedItems(items: FeedItem[]) { ... }
30
+ * }
31
+ * ```
32
+ */
33
+ export declare function InspectTrackTime(label?: string): (_target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
34
+ /**
35
+ * `@InspectCatch`: Safely catches unhandled exceptions thrown inside the method,
36
+ * logs them to the In-App Inspector, and returns a fallback value.
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * class AuthService {
41
+ * @InspectCatch({ fallback: null, tag: 'AUTH' })
42
+ * async getCachedToken() { ... }
43
+ * }
44
+ * ```
45
+ */
46
+ export declare function InspectCatch(options?: {
47
+ fallback?: any;
48
+ tag?: string;
49
+ }): (_target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ // ─── Method & Class Decorators for React Native In-App Inspector ─────────────
3
+ //
4
+ // Clean TypeScript decorators to seamlessly annotate methods, asynchronous actions,
5
+ // and API services with automatic inspection, logging, timing, and error boundaries.
6
+ // ─────────────────────────────────────────────────────────────────────────────
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.InspectLog = InspectLog;
9
+ exports.InspectTrackTime = InspectTrackTime;
10
+ exports.InspectCatch = InspectCatch;
11
+ /**
12
+ * `@InspectLog`: Automatically logs method execution, arguments, duration, and return values
13
+ * to the In-App Inspector Console.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * class UserService {
18
+ * @InspectLog({ tag: 'API', logArgs: true, logDuration: true })
19
+ * async fetchUser(id: string) {
20
+ * return api.get(`/users/${id}`);
21
+ * }
22
+ * }
23
+ * ```
24
+ */
25
+ function InspectLog(options = {}) {
26
+ const { tag = 'Inspect', logArgs = true, logResult = true, logDuration = true, } = options;
27
+ return function (_target, propertyKey, descriptor) {
28
+ const originalMethod = descriptor.value;
29
+ descriptor.value = function (...args) {
30
+ const start = Date.now();
31
+ const prefix = `[${tag}] ${propertyKey}`;
32
+ if (logArgs && args.length > 0) {
33
+ console.log(`${prefix} called with arguments:`, ...args);
34
+ }
35
+ else {
36
+ console.log(`${prefix} invoked`);
37
+ }
38
+ try {
39
+ const result = originalMethod.apply(this, args);
40
+ if (result && typeof result.then === 'function') {
41
+ return result
42
+ .then((asyncResult) => {
43
+ const elapsed = Date.now() - start;
44
+ if (logResult) {
45
+ console.log(`${prefix} resolved${logDuration ? ` in ${elapsed}ms` : ''}:`, asyncResult);
46
+ }
47
+ return asyncResult;
48
+ })
49
+ .catch((err) => {
50
+ const elapsed = Date.now() - start;
51
+ console.error(`${prefix} rejected${logDuration ? ` in ${elapsed}ms` : ''}:`, err);
52
+ throw err;
53
+ });
54
+ }
55
+ const elapsed = Date.now() - start;
56
+ if (logResult) {
57
+ console.log(`${prefix} returned${logDuration ? ` in ${elapsed}ms` : ''}:`, result);
58
+ }
59
+ return result;
60
+ }
61
+ catch (error) {
62
+ const elapsed = Date.now() - start;
63
+ console.error(`${prefix} failed${logDuration ? ` in ${elapsed}ms` : ''}:`, error);
64
+ throw error;
65
+ }
66
+ };
67
+ return descriptor;
68
+ };
69
+ }
70
+ /**
71
+ * `@InspectTrackTime`: Measures and logs execution duration for critical functions.
72
+ *
73
+ * @example
74
+ * ```ts
75
+ * class FeedManager {
76
+ * @InspectTrackTime('Feed Data Processing')
77
+ * processFeedItems(items: FeedItem[]) { ... }
78
+ * }
79
+ * ```
80
+ */
81
+ function InspectTrackTime(label) {
82
+ return function (_target, propertyKey, descriptor) {
83
+ const originalMethod = descriptor.value;
84
+ const metricLabel = label || propertyKey;
85
+ descriptor.value = function (...args) {
86
+ const start = Date.now();
87
+ try {
88
+ const result = originalMethod.apply(this, args);
89
+ if (result && typeof result.then === 'function') {
90
+ return result.finally(() => {
91
+ const duration = Date.now() - start;
92
+ console.log(`[PERF] ⚡ ${metricLabel} took ${duration}ms`);
93
+ });
94
+ }
95
+ const duration = Date.now() - start;
96
+ console.log(`[PERF] ⚡ ${metricLabel} took ${duration}ms`);
97
+ return result;
98
+ }
99
+ catch (err) {
100
+ const duration = Date.now() - start;
101
+ console.error(`[PERF] ⚡ ${metricLabel} failed after ${duration}ms:`, err);
102
+ throw err;
103
+ }
104
+ };
105
+ return descriptor;
106
+ };
107
+ }
108
+ /**
109
+ * `@InspectCatch`: Safely catches unhandled exceptions thrown inside the method,
110
+ * logs them to the In-App Inspector, and returns a fallback value.
111
+ *
112
+ * @example
113
+ * ```ts
114
+ * class AuthService {
115
+ * @InspectCatch({ fallback: null, tag: 'AUTH' })
116
+ * async getCachedToken() { ... }
117
+ * }
118
+ * ```
119
+ */
120
+ function InspectCatch(options = {}) {
121
+ const { fallback = undefined, tag = 'Catch' } = options;
122
+ return function (_target, propertyKey, descriptor) {
123
+ const originalMethod = descriptor.value;
124
+ descriptor.value = function (...args) {
125
+ try {
126
+ const result = originalMethod.apply(this, args);
127
+ if (result && typeof result.then === 'function') {
128
+ return result.catch((err) => {
129
+ console.error(`[${tag}] Error caught in ${propertyKey}:`, err);
130
+ return fallback;
131
+ });
132
+ }
133
+ return result;
134
+ }
135
+ catch (err) {
136
+ console.error(`[${tag}] Error caught in ${propertyKey}:`, err);
137
+ return fallback;
138
+ }
139
+ };
140
+ return descriptor;
141
+ };
142
+ }
@@ -0,0 +1,18 @@
1
+ import { GAEventCategory } from '../types/enums';
2
+ export { GAEventCategory };
3
+ export interface GAPlugin {
4
+ name: string;
5
+ resolveCategory?: (eventName: string, params?: Record<string, any>) => GAEventCategory | string | null | undefined;
6
+ }
7
+ /**
8
+ * Register a dynamic Google Analytics / Firebase plugin or custom resolver.
9
+ */
10
+ export declare const registerGAPlugin: (plugin: GAPlugin) => void;
11
+ /**
12
+ * Dynamically resolves the GA4 event category using:
13
+ * 1. Registered dynamic GA plugins
14
+ * 2. Runtime Firebase Analytics inspection
15
+ * 3. GA4 standard event taxonomies (O(1) Set lookup)
16
+ * 4. Semantic pattern & prefix analysis
17
+ */
18
+ export declare const getEventCategory: (name: string, params?: Record<string, any>) => GAEventCategory;
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ // ─── Google Analytics (GA4) & Firebase Analytics Dynamic Registry ─────────────
3
+ //
4
+ // Dynamically inspects GA4 / Firebase Analytics runtime schemas, auto-detects
5
+ // standard GA4 event taxonomies, and supports dynamic GA plugins.
6
+ // ─────────────────────────────────────────────────────────────────────────────
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.getEventCategory = exports.registerGAPlugin = exports.GAEventCategory = void 0;
9
+ const enums_1 = require("../types/enums");
10
+ Object.defineProperty(exports, "GAEventCategory", { enumerable: true, get: function () { return enums_1.GAEventCategory; } });
11
+ // ─── Official GA4 & Firebase Standard Event Sets ─────────────────────────────
12
+ const GA4_PAGE_VIEW_EVENTS = new Set([
13
+ 'screen_view',
14
+ 'page_view',
15
+ 'screen_active',
16
+ 'screen_inactive',
17
+ 'view_search_results',
18
+ 'search',
19
+ ]);
20
+ const GA4_ECOMMERCE_EVENTS = new Set([
21
+ 'purchase',
22
+ 'refund',
23
+ 'add_to_cart',
24
+ 'remove_from_cart',
25
+ 'view_cart',
26
+ 'begin_checkout',
27
+ 'add_shipping_info',
28
+ 'add_payment_info',
29
+ 'view_item',
30
+ 'view_item_list',
31
+ 'select_item',
32
+ 'select_promotion',
33
+ 'view_promotion',
34
+ 'add_to_wishlist',
35
+ 'generate_lead',
36
+ 'in_app_purchase',
37
+ 'earn_virtual_currency',
38
+ 'spend_virtual_currency',
39
+ 'join_group',
40
+ 'level_up',
41
+ 'level_start',
42
+ 'level_end',
43
+ 'post_score',
44
+ 'select_content',
45
+ 'tutorial_begin',
46
+ 'tutorial_complete',
47
+ 'unlock_achievement',
48
+ ]);
49
+ const GA4_SYSTEM_EVENTS = new Set([
50
+ 'first_open',
51
+ 'first_visit',
52
+ 'session_start',
53
+ 'user_engagement',
54
+ 'app_clear_data',
55
+ 'app_exception',
56
+ 'app_remove',
57
+ 'app_store_refund',
58
+ 'app_store_subscription_cancel',
59
+ 'app_store_subscription_convert',
60
+ 'app_store_subscription_renew',
61
+ 'app_update',
62
+ 'os_update',
63
+ 'notification_receive',
64
+ 'notification_open',
65
+ 'notification_dismiss',
66
+ 'notification_foreground',
67
+ 'dynamic_link_first_open',
68
+ 'dynamic_link_app_open',
69
+ 'dynamic_link_app_update',
70
+ 'ad_impression',
71
+ 'ad_click',
72
+ 'ad_reward',
73
+ 'ad_query',
74
+ 'ad_exposure',
75
+ ]);
76
+ // ─── Registered Dynamic Plugins ──────────────────────────────────────────────
77
+ const registeredPlugins = [];
78
+ /**
79
+ * Register a dynamic Google Analytics / Firebase plugin or custom resolver.
80
+ */
81
+ const registerGAPlugin = (plugin) => {
82
+ if (!registeredPlugins.some(p => p.name === plugin.name)) {
83
+ registeredPlugins.push(plugin);
84
+ }
85
+ };
86
+ exports.registerGAPlugin = registerGAPlugin;
87
+ /**
88
+ * Attempt dynamic inspection of host runtime Firebase / Google Analytics modules.
89
+ */
90
+ const tryInspectRuntimeFirebaseAnalytics = () => {
91
+ try {
92
+ const firebaseAnalytics = require('@react-native-firebase/analytics');
93
+ const mod = firebaseAnalytics?.default || firebaseAnalytics;
94
+ if (mod?.EventNames) {
95
+ Object.keys(mod.EventNames).forEach(k => {
96
+ const val = mod.EventNames[k]?.toLowerCase();
97
+ if (val) {
98
+ if (val.includes('cart') ||
99
+ val.includes('checkout') ||
100
+ val.includes('purchase') ||
101
+ val.includes('item')) {
102
+ GA4_ECOMMERCE_EVENTS.add(val);
103
+ }
104
+ else if (val.includes('screen') || val.includes('page')) {
105
+ GA4_PAGE_VIEW_EVENTS.add(val);
106
+ }
107
+ }
108
+ });
109
+ }
110
+ }
111
+ catch {
112
+ // Optional dependency - safe fallback to built-in GA4 taxonomy
113
+ }
114
+ };
115
+ // Initialize dynamic runtime inspection once
116
+ tryInspectRuntimeFirebaseAnalytics();
117
+ /**
118
+ * Dynamically resolves the GA4 event category using:
119
+ * 1. Registered dynamic GA plugins
120
+ * 2. Runtime Firebase Analytics inspection
121
+ * 3. GA4 standard event taxonomies (O(1) Set lookup)
122
+ * 4. Semantic pattern & prefix analysis
123
+ */
124
+ const getEventCategory = (name, params) => {
125
+ if (!name || typeof name !== 'string')
126
+ return 'custom';
127
+ const cleanName = name.trim().toLowerCase();
128
+ // 1. Run through registered dynamic plugins
129
+ for (const plugin of registeredPlugins) {
130
+ if (plugin.resolveCategory) {
131
+ const category = plugin.resolveCategory(cleanName, params);
132
+ if (category)
133
+ return category;
134
+ }
135
+ }
136
+ // 2. Exact GA4 taxonomy matching (O(1))
137
+ if (GA4_PAGE_VIEW_EVENTS.has(cleanName)) {
138
+ return 'page_view';
139
+ }
140
+ if (GA4_ECOMMERCE_EVENTS.has(cleanName)) {
141
+ return 'ecommerce';
142
+ }
143
+ if (GA4_SYSTEM_EVENTS.has(cleanName)) {
144
+ return 'system';
145
+ }
146
+ // 3. Prefix & namespace detection
147
+ if (cleanName.startsWith('firebase_') ||
148
+ cleanName.startsWith('ga_') ||
149
+ cleanName.startsWith('gtag_') ||
150
+ cleanName.startsWith('_') ||
151
+ cleanName.startsWith('google_')) {
152
+ return 'system';
153
+ }
154
+ // 4. Semantic pattern matching
155
+ if (cleanName.endsWith('_view') ||
156
+ cleanName.endsWith('_screen') ||
157
+ cleanName.startsWith('screen_') ||
158
+ cleanName.startsWith('page_') ||
159
+ cleanName.includes('screen_view') ||
160
+ cleanName.includes('page_view')) {
161
+ return 'page_view';
162
+ }
163
+ if (cleanName.includes('cart') ||
164
+ cleanName.includes('checkout') ||
165
+ cleanName.includes('purchase') ||
166
+ cleanName.includes('payment') ||
167
+ cleanName.includes('order') ||
168
+ cleanName.includes('refund') ||
169
+ cleanName.includes('shipping')) {
170
+ return 'ecommerce';
171
+ }
172
+ return 'custom';
173
+ };
174
+ exports.getEventCategory = getEventCategory;
@@ -1,4 +1,4 @@
1
- import { NetworkLog, RouteInfo, DiffResult, JsonContent } from '../types';
1
+ import { NetworkLog, RouteInfo, DiffResult, JsonContent, StackFrameType } from '../types';
2
2
  export declare const getDomainColor: (domain: string) => string;
3
3
  export declare const formatDateTime: (timestamp: number) => string;
4
4
  export declare const getStatusColor: (status: number | null) => string;
@@ -40,17 +40,20 @@ export interface ParsedStackFrame {
40
40
  functionName: string;
41
41
  fileName: string;
42
42
  fullPath: string;
43
- fileExt?: 'tsx' | 'jsx' | 'ts' | 'js' | 'other';
44
- isUserCode?: boolean;
43
+ fileExt: string;
44
+ frameType: StackFrameType | 'app' | 'dependency' | 'runtime' | 'native';
45
+ isUserCode: boolean;
46
+ isRuntimeNoise: boolean;
45
47
  lineNumber?: string;
46
48
  columnNumber?: string;
47
49
  isOrigin?: boolean;
50
+ copyableLocation: string;
48
51
  }
49
52
  /** Parses a stack trace line to extract function name, file name, extension (.tsx/.jsx/.ts), line, and column numbers */
50
53
  export declare const parseStackLine: (rawLine: string, isOrigin?: boolean) => ParsedStackFrame;
51
54
  export declare const ANALYTICS_EVENT_PALETTE: string[];
52
55
  export declare const getEventColor: (name: string) => string;
53
- export declare const getEventCategory: (name: string) => "page_view" | "ecommerce" | "system" | "custom";
56
+ export { getEventCategory, registerGAPlugin, type GAEventCategory, type GAPlugin, } from './gaAnalyticsRegistry';
54
57
  export declare const getCategoryColors: (category: string) => {
55
58
  bg: string;
56
59
  border: string;