@luciq/react-native 19.6.0 → 19.7.0

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.
@@ -3,11 +3,6 @@ import { NetworkData, ProgressCallback } from '../utils/XhrNetworkInterceptor';
3
3
  import { NetworkListenerType } from '../native/NativeNetworkLogger';
4
4
  export type { NetworkData };
5
5
  export type NetworkDataObfuscationHandler = (data: NetworkData) => Promise<NetworkData>;
6
- /**
7
- * Sets whether network logs should be sent with bug reports.
8
- * It is enabled by default.
9
- * @param isEnabled
10
- */
11
6
  export declare const setEnabled: (isEnabled: boolean) => void;
12
7
  /**
13
8
  * @internal
@@ -20,21 +20,25 @@ function getPortFromUrl(url) {
20
20
  * It is enabled by default.
21
21
  * @param isEnabled
22
22
  */
23
+ const NET_TAG = 'LCQ-RN-NET:';
23
24
  export const setEnabled = (isEnabled) => {
24
25
  if (isEnabled) {
25
26
  xhr.enableInterception();
26
27
  xhr.setOnDoneCallback(async (network) => {
28
+ Logger.debug(NET_TAG, `[NetworkLogger] onDoneCallback received: ${network.method} ${network.url}, status=${network.responseCode}`);
27
29
  // eslint-disable-next-line no-new-func
28
30
  const predicate = Function('network', 'return ' + _requestFilterExpression);
29
31
  if (!predicate(network)) {
30
32
  const MAX_NETWORK_BODY_SIZE_IN_BYTES = await NativeLuciq.getNetworkBodyMaxSize();
31
33
  try {
32
34
  if (_networkDataObfuscationHandler) {
35
+ Logger.debug(NET_TAG, `[NetworkLogger] Running obfuscation handler for ${network.url}`);
33
36
  network = await _networkDataObfuscationHandler(network);
34
37
  }
35
38
  if (__DEV__) {
36
39
  const urlPort = getPortFromUrl(network.url);
37
40
  if (urlPort === LuciqRNConfig.metroDevServerPort) {
41
+ Logger.debug(NET_TAG, `[NetworkLogger] Skipping Metro dev server request: ${network.url}`);
38
42
  return;
39
43
  }
40
44
  }
@@ -54,12 +58,16 @@ export const setEnabled = (isEnabled) => {
54
58
  network.responseBody = `Body is omitted because content type ${network.contentType} isn't supported`;
55
59
  Logger.warn(`LCQ-RN: The response body for the network request with URL ${network.url} has been omitted because the content type ${network.contentType} isn't supported.`);
56
60
  }
61
+ Logger.debug(NET_TAG, `[NetworkLogger] Reporting network log to native: ${network.method} ${network.url}`);
57
62
  reportNetworkLog(network);
58
63
  }
59
64
  catch (e) {
60
- Logger.error(e);
65
+ Logger.error(NET_TAG, `[NetworkLogger] Error processing network log for ${network.url}:`, e);
61
66
  }
62
67
  }
68
+ else {
69
+ Logger.debug(NET_TAG, `[NetworkLogger] Request filtered out by predicate: ${network.method} ${network.url}, expression="${_requestFilterExpression}"`);
70
+ }
63
71
  });
64
72
  }
65
73
  else {
@@ -1,3 +1,9 @@
1
+ export declare function initFeatureFlagsCache(): Promise<void>;
2
+ export declare function getCachedW3cFlags(): {
3
+ isW3cExternalTraceIDEnabled: boolean;
4
+ isW3cExternalGeneratedHeaderEnabled: boolean;
5
+ isW3cCaughtHeaderEnabled: boolean;
6
+ };
1
7
  export declare const FeatureFlags: {
2
8
  isW3ExternalTraceID: () => Promise<boolean>;
3
9
  isW3ExternalGeneratedHeader: () => Promise<boolean>;
@@ -1,5 +1,34 @@
1
1
  import { NativeLuciq } from '../native/NativeLuciq';
2
2
  import { _registerFeatureFlagsChangeListener } from '../modules/Luciq';
3
+ import { Logger } from './logger';
4
+ const TAG = 'LCQ-RN-NET:';
5
+ let cachedW3cFlags = {
6
+ isW3cExternalTraceIDEnabled: false,
7
+ isW3cExternalGeneratedHeaderEnabled: false,
8
+ isW3cCaughtHeaderEnabled: false,
9
+ };
10
+ export async function initFeatureFlagsCache() {
11
+ Logger.debug(TAG, '[FeatureFlags] Initializing W3C feature flags cache from native bridge...');
12
+ try {
13
+ const [traceID, generatedHeader, caughtHeader] = await Promise.all([
14
+ NativeLuciq.isW3ExternalTraceIDEnabled(),
15
+ NativeLuciq.isW3ExternalGeneratedHeaderEnabled(),
16
+ NativeLuciq.isW3CaughtHeaderEnabled(),
17
+ ]);
18
+ cachedW3cFlags = {
19
+ isW3cExternalTraceIDEnabled: traceID,
20
+ isW3cExternalGeneratedHeaderEnabled: generatedHeader,
21
+ isW3cCaughtHeaderEnabled: caughtHeader,
22
+ };
23
+ Logger.debug(TAG, `[FeatureFlags] Cache initialized: traceID=${traceID}, generatedHeader=${generatedHeader}, caughtHeader=${caughtHeader}`);
24
+ }
25
+ catch (e) {
26
+ Logger.debug(TAG, '[FeatureFlags] Failed to initialize cache, using defaults (all false):', e);
27
+ }
28
+ }
29
+ export function getCachedW3cFlags() {
30
+ return cachedW3cFlags;
31
+ }
3
32
  export const FeatureFlags = {
4
33
  isW3ExternalTraceID: () => NativeLuciq.isW3ExternalTraceIDEnabled(),
5
34
  isW3ExternalGeneratedHeader: () => NativeLuciq.isW3ExternalGeneratedHeaderEnabled(),
@@ -8,6 +37,12 @@ export const FeatureFlags = {
8
37
  };
9
38
  export const registerFeatureFlagsListener = () => {
10
39
  _registerFeatureFlagsChangeListener((res) => {
40
+ Logger.debug(TAG, `[FeatureFlags] Flags updated from native listener: traceID=${res.isW3ExternalTraceIDEnabled}, generatedHeader=${res.isW3ExternalGeneratedHeaderEnabled}, caughtHeader=${res.isW3CaughtHeaderEnabled}, bodyLimit=${res.networkBodyLimit}`);
41
+ cachedW3cFlags = {
42
+ isW3cExternalTraceIDEnabled: res.isW3ExternalTraceIDEnabled,
43
+ isW3cExternalGeneratedHeaderEnabled: res.isW3ExternalGeneratedHeaderEnabled,
44
+ isW3cCaughtHeaderEnabled: res.isW3CaughtHeaderEnabled,
45
+ };
11
46
  FeatureFlags.isW3ExternalTraceID = async () => {
12
47
  return res.isW3ExternalTraceIDEnabled;
13
48
  };
@@ -3,6 +3,7 @@ import parseErrorStackLib from 'react-native/Libraries/Core/Devtools/parseErrorS
3
3
  import { NativeCrashReporting } from '../native/NativeCrashReporting';
4
4
  import { NativeLuciq } from '../native/NativeLuciq';
5
5
  import { NativeAPM } from '../native/NativeAPM';
6
+ import { Logger } from './logger';
6
7
  import * as NetworkLogger from '../modules/NetworkLogger';
7
8
  import { NativeNetworkLogger, NativeNetworkLoggerEvent, NetworkListenerType, NetworkLoggerEmitter, } from '../native/NativeNetworkLogger';
8
9
  let apmFlags = {
@@ -181,10 +182,12 @@ export const reportNetworkLog = (network) => {
181
182
  if (Platform.OS === 'android') {
182
183
  const requestHeaders = JSON.stringify(network.requestHeaders);
183
184
  const responseHeaders = JSON.stringify(network.responseHeaders);
185
+ Logger.debug('LCQ-RN-NET:', `[reportNetworkLog] Sending to NativeLuciq.networkLogAndroid: ${network.method} ${network.url}, status=${network.responseCode}, duration=${network.duration}ms, error=${network.errorDomain || 'none'}`);
184
186
  NativeLuciq.networkLogAndroid(network.url, network.requestBody, network.responseBody, network.method, network.responseCode, requestHeaders, responseHeaders, network.duration);
185
187
  if (!apmFlags.isNativeInterceptionFeatureEnabled ||
186
188
  !apmFlags.hasAPMNetworkPlugin ||
187
189
  !apmFlags.shouldEnableNativeInterception) {
190
+ Logger.debug('LCQ-RN-NET:', `[reportNetworkLog] Also sending to NativeAPM.networkLogAndroid (native interception disabled): ${network.method} ${network.url}`);
188
191
  NativeAPM.networkLogAndroid(network.startTime, network.duration, requestHeaders, network.requestBody, network.requestBodySize, network.method, network.url, network.requestContentType, responseHeaders, network.responseBody, network.responseBodySize, network.responseCode, network.contentType, network.errorDomain, {
189
192
  isW3cHeaderFound: network.isW3cHeaderFound,
190
193
  partialId: network.partialId,
@@ -193,8 +196,12 @@ export const reportNetworkLog = (network) => {
193
196
  w3cCaughtHeader: network.w3cCaughtHeader,
194
197
  }, network.gqlQueryName, network.serverErrorMessage);
195
198
  }
199
+ else {
200
+ Logger.debug('LCQ-RN-NET:', `[reportNetworkLog] Skipping NativeAPM.networkLogAndroid (native interception enabled): nativeFeature=${apmFlags.isNativeInterceptionFeatureEnabled}, hasPlugin=${apmFlags.hasAPMNetworkPlugin}, shouldEnable=${apmFlags.shouldEnableNativeInterception}`);
201
+ }
196
202
  }
197
203
  else {
204
+ Logger.debug('LCQ-RN-NET:', `[reportNetworkLog] Sending to NativeLuciq.networkLogIOS: ${network.method} ${network.url}, status=${network.responseCode}, duration=${network.duration}ms, error=${network.errorDomain || 'none'}`);
198
205
  NativeLuciq.networkLogIOS(network.url, network.method, network.requestBody, network.requestBodySize, network.responseBody, network.responseBodySize, network.responseCode, network.requestHeaders, network.responseHeaders, network.contentType, network.errorDomain, network.errorCode, network.startTime, network.duration, network.gqlQueryName, network.serverErrorMessage, {
199
206
  isW3cHeaderFound: network.isW3cHeaderFound,
200
207
  partialId: network.partialId,
@@ -1,6 +1,8 @@
1
1
  import LuciqConstants from './LuciqConstants';
2
2
  import { stringifyIfNotString, generateW3CHeader } from './LuciqUtils';
3
- import { FeatureFlags } from '../utils/FeatureFlags';
3
+ import { getCachedW3cFlags } from './FeatureFlags';
4
+ import { Logger } from './logger';
5
+ const TAG = 'LCQ-RN-NET:';
4
6
  const XMLHttpRequest = global.XMLHttpRequest;
5
7
  let originalXHROpen = XMLHttpRequest.prototype.open;
6
8
  let originalXHRSend = XMLHttpRequest.prototype.send;
@@ -8,40 +10,34 @@ let originalXHRSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
8
10
  let onProgressCallback;
9
11
  let onDoneCallback;
10
12
  let isInterceptorEnabled = false;
11
- let network;
12
- const _reset = () => {
13
- network = {
14
- id: '',
15
- url: '',
16
- method: '',
17
- requestBody: '',
18
- requestBodySize: 0,
19
- responseBody: '',
20
- responseBodySize: 0,
21
- responseCode: 0,
22
- requestHeaders: {},
23
- responseHeaders: {},
24
- contentType: '',
25
- errorDomain: '',
26
- errorCode: 0,
27
- startTime: 0,
28
- duration: 0,
29
- gqlQueryName: '',
30
- serverErrorMessage: '',
31
- requestContentType: '',
32
- isW3cHeaderFound: null,
33
- partialId: null,
34
- networkStartTimeInSeconds: null,
35
- w3cGeneratedHeader: null,
36
- w3cCaughtHeader: null,
37
- };
38
- };
39
- const getTraceparentHeader = async (networkData) => {
40
- const [isW3cExternalTraceIDEnabled, isW3cExternalGeneratedHeaderEnabled, isW3cCaughtHeaderEnabled,] = await Promise.all([
41
- FeatureFlags.isW3ExternalTraceID(),
42
- FeatureFlags.isW3ExternalGeneratedHeader(),
43
- FeatureFlags.isW3CaughtHeader(),
44
- ]);
13
+ const networkMap = new WeakMap();
14
+ const createNetworkData = () => ({
15
+ id: '',
16
+ url: '',
17
+ method: '',
18
+ requestBody: '',
19
+ requestBodySize: 0,
20
+ responseBody: '',
21
+ responseBodySize: 0,
22
+ responseCode: 0,
23
+ requestHeaders: {},
24
+ responseHeaders: {},
25
+ contentType: '',
26
+ errorDomain: '',
27
+ errorCode: 0,
28
+ startTime: 0,
29
+ duration: 0,
30
+ gqlQueryName: '',
31
+ serverErrorMessage: '',
32
+ requestContentType: '',
33
+ isW3cHeaderFound: null,
34
+ partialId: null,
35
+ networkStartTimeInSeconds: null,
36
+ w3cGeneratedHeader: null,
37
+ w3cCaughtHeader: null,
38
+ });
39
+ const getTraceparentHeader = (networkData) => {
40
+ const { isW3cExternalTraceIDEnabled, isW3cExternalGeneratedHeaderEnabled, isW3cCaughtHeaderEnabled, } = getCachedW3cFlags();
45
41
  return injectHeaders(networkData, {
46
42
  isW3cExternalTraceIDEnabled,
47
43
  isW3cExternalGeneratedHeaderEnabled,
@@ -85,39 +81,57 @@ export default {
85
81
  onProgressCallback = callback;
86
82
  },
87
83
  enableInterception() {
88
- // Prevents infinite calls to XMLHttpRequest.open when enabling interception multiple times
89
84
  if (isInterceptorEnabled) {
85
+ Logger.debug(TAG, 'enableInterception called but already enabled, skipping');
90
86
  return;
91
87
  }
88
+ Logger.debug(TAG, 'Enabling XHR network interception');
92
89
  originalXHROpen = XMLHttpRequest.prototype.open;
93
90
  originalXHRSend = XMLHttpRequest.prototype.send;
94
91
  originalXHRSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
95
92
  // An error code that signifies an issue with the RN client.
96
93
  const clientErrorCode = 9876;
97
94
  XMLHttpRequest.prototype.open = function (method, url, ...args) {
98
- _reset();
99
- network.url = url;
100
- network.method = method;
95
+ const networkData = createNetworkData();
96
+ networkData.url = url;
97
+ networkData.method = method;
98
+ networkMap.set(this, networkData);
99
+ Logger.debug(TAG, `[open] ${method} ${url}`);
101
100
  originalXHROpen.apply(this, [method, url, ...args]);
102
101
  };
103
102
  XMLHttpRequest.prototype.setRequestHeader = function (header, value) {
104
- // According to the HTTP RFC, headers are case-insensitive, so we convert
105
- // them to lower-case to make accessing headers predictable.
106
- // This avoid issues like failing to get the Content-Type header for a request
107
- // because the header is set as 'Content-Type' instead of 'content-type'.
108
103
  const key = header.toLowerCase();
109
- network.requestHeaders[key] = stringifyIfNotString(value);
104
+ const networkData = networkMap.get(this);
105
+ if (networkData) {
106
+ networkData.requestHeaders[key] = stringifyIfNotString(value);
107
+ }
108
+ else {
109
+ Logger.debug(TAG, `[setRequestHeader] No networkData found in WeakMap for header "${key}" — request may have been GC'd or open() was not called`);
110
+ }
110
111
  originalXHRSetRequestHeader.apply(this, [header, value]);
111
112
  };
112
- XMLHttpRequest.prototype.send = async function (data) {
113
- const cloneNetwork = JSON.parse(JSON.stringify(network));
113
+ XMLHttpRequest.prototype.send = function (data) {
114
+ const networkData = networkMap.get(this);
115
+ if (!networkData) {
116
+ Logger.debug(TAG, '[send] No networkData found in WeakMap — falling back to original send (open() was not intercepted)');
117
+ originalXHRSend.apply(this, [data]);
118
+ return;
119
+ }
120
+ Logger.debug(TAG, `[send] ${networkData.method} ${networkData.url}`);
121
+ const cloneNetwork = JSON.parse(JSON.stringify(networkData));
114
122
  cloneNetwork.requestBody = data ? data : '';
115
123
  if (typeof cloneNetwork.requestBody !== 'string') {
116
124
  cloneNetwork.requestBody = JSON.stringify(cloneNetwork.requestBody);
117
125
  }
126
+ let isReported = false;
118
127
  if (this.addEventListener) {
119
128
  this.addEventListener('readystatechange', async () => {
120
129
  if (!isInterceptorEnabled) {
130
+ Logger.debug(TAG, `[readystatechange] Interceptor disabled, ignoring state=${this.readyState} for ${cloneNetwork.url}`);
131
+ return;
132
+ }
133
+ if (isReported) {
134
+ Logger.debug(TAG, `[readystatechange] Already reported, ignoring state=${this.readyState} for ${cloneNetwork.url}`);
121
135
  return;
122
136
  }
123
137
  if (this.readyState === this.HEADERS_RECEIVED) {
@@ -146,6 +160,7 @@ export default {
146
160
  cloneNetwork.requestContentType =
147
161
  cloneNetwork.requestHeaders['content-type'].split(';')[0];
148
162
  }
163
+ Logger.debug(TAG, `[readystatechange] HEADERS_RECEIVED for ${cloneNetwork.url}, contentType=${cloneNetwork.contentType}`);
149
164
  }
150
165
  if (this.readyState === this.DONE) {
151
166
  cloneNetwork.duration = Date.now() - cloneNetwork.startTime;
@@ -166,11 +181,11 @@ export default {
166
181
  cloneNetwork.requestBody =
167
182
  typeof _response === 'string' ? _response : JSON.stringify(_response);
168
183
  cloneNetwork.responseBody = '';
169
- // Detect a more descriptive error message.
170
184
  if (typeof _response === 'string' && _response.length > 0) {
171
185
  cloneNetwork.errorDomain = _response;
172
186
  }
173
187
  cloneNetwork.responseBody = `ERROR: ${cloneNetwork.errorDomain}`;
188
+ Logger.debug(TAG, `[readystatechange] DONE with client error for ${cloneNetwork.url}, errorDomain=${cloneNetwork.errorDomain}`);
174
189
  // @ts-ignore
175
190
  }
176
191
  else if (this._timedOut) {
@@ -179,6 +194,7 @@ export default {
179
194
  cloneNetwork.responseCode = 0;
180
195
  cloneNetwork.contentType = 'text/plain';
181
196
  cloneNetwork.responseBody = `ERROR: ${cloneNetwork.errorDomain}`;
197
+ Logger.debug(TAG, `[readystatechange] DONE with timeout for ${cloneNetwork.url}`);
182
198
  }
183
199
  // Only set response body if not already set by error handlers
184
200
  if (!cloneNetwork.errorDomain) {
@@ -225,16 +241,20 @@ export default {
225
241
  else {
226
242
  delete cloneNetwork.gqlQueryName;
227
243
  }
244
+ isReported = true;
245
+ Logger.debug(TAG, `[readystatechange] DONE for ${cloneNetwork.method} ${cloneNetwork.url} — status=${cloneNetwork.responseCode}, duration=${cloneNetwork.duration}ms, hasCallback=${!!onDoneCallback}`);
228
246
  if (onDoneCallback) {
229
247
  onDoneCallback(cloneNetwork);
230
248
  }
249
+ else {
250
+ Logger.debug(TAG, `[readystatechange] WARNING: onDoneCallback is null, network log for ${cloneNetwork.url} will be LOST`);
251
+ }
231
252
  }
232
253
  });
233
254
  const downloadUploadProgressCallback = (event) => {
234
255
  if (!isInterceptorEnabled) {
235
256
  return;
236
257
  }
237
- // check if will be able to compute progress
238
258
  if (event.lengthComputable && onProgressCallback) {
239
259
  const totalBytesSent = event.loaded;
240
260
  const totalBytesExpectedToSend = event.total - event.loaded;
@@ -243,31 +263,43 @@ export default {
243
263
  };
244
264
  this.addEventListener('progress', downloadUploadProgressCallback);
245
265
  this.upload.addEventListener('progress', downloadUploadProgressCallback);
246
- // Handler for abort events (works with fetch, Axios, and any XHR-based requests)
247
266
  this.addEventListener('abort', () => {
248
267
  if (!isInterceptorEnabled) {
268
+ Logger.debug(TAG, `[abort] Interceptor disabled, ignoring abort for ${cloneNetwork.url}`);
269
+ return;
270
+ }
271
+ if (isReported) {
272
+ Logger.debug(TAG, `[abort] Already reported via readystatechange DONE, ignoring duplicate abort for ${cloneNetwork.url}`);
249
273
  return;
250
274
  }
275
+ isReported = true;
251
276
  cloneNetwork.duration = Date.now() - cloneNetwork.startTime;
252
277
  cloneNetwork.responseCode = 0;
253
278
  cloneNetwork.errorCode = clientErrorCode;
254
279
  cloneNetwork.errorDomain = 'cancelled';
255
280
  cloneNetwork.responseBody = `ERROR: ${cloneNetwork.errorDomain}`;
281
+ Logger.debug(TAG, `[abort] Request cancelled: ${cloneNetwork.method} ${cloneNetwork.url}, duration=${cloneNetwork.duration}ms, hasCallback=${!!onDoneCallback}`);
282
+ if (onDoneCallback) {
283
+ onDoneCallback(cloneNetwork);
284
+ }
285
+ else {
286
+ Logger.debug(TAG, `[abort] WARNING: onDoneCallback is null, cancelled log for ${cloneNetwork.url} will be LOST`);
287
+ }
256
288
  });
257
289
  }
258
290
  cloneNetwork.startTime = Date.now();
259
- const traceparent = await getTraceparentHeader(cloneNetwork);
291
+ const traceparent = getTraceparentHeader(cloneNetwork);
260
292
  if (traceparent) {
261
293
  this.setRequestHeader('Traceparent', traceparent);
262
- }
263
- if (this.readyState === this.UNSENT) {
264
- return; // Prevent sending the request if not opened
294
+ Logger.debug(TAG, `[send] Injected traceparent header for ${cloneNetwork.url}`);
265
295
  }
266
296
  originalXHRSend.apply(this, [data]);
267
297
  };
268
298
  isInterceptorEnabled = true;
299
+ Logger.debug(TAG, 'XHR network interception enabled');
269
300
  },
270
301
  disableInterception() {
302
+ Logger.debug(TAG, 'Disabling XHR network interception');
271
303
  isInterceptorEnabled = false;
272
304
  XMLHttpRequest.prototype.send = originalXHRSend;
273
305
  XMLHttpRequest.prototype.open = originalXHROpen;
@@ -6,10 +6,13 @@
6
6
  //
7
7
  #import "LuciqNetworkLoggerBridge.h"
8
8
  #import "Util/LCQNetworkLogger+CP.h"
9
+ #import "Util/LuciqRNLogger.h"
9
10
 
10
11
  #import <React/RCTLog.h>
11
12
  #import <React/RCTConvert.h>
12
13
 
14
+ static NSString *const LCQRNNetTag = @"LCQ-RN-NET";
15
+
13
16
  // Extend RCTConvert to handle NetworkListenerType enum conversion
14
17
  @implementation RCTConvert (NetworkListenerType)
15
18
 
@@ -60,22 +63,27 @@ bool lcq_hasListeners = NO;
60
63
  // Will be called when this module's first listener is added.
61
64
  -(void)startObserving {
62
65
  lcq_hasListeners = YES;
66
+ [LuciqRNLogger d:LCQRNNetTag format:@"[EventEmitter] startObserving - LCQNetworkLogger listeners ON"];
63
67
  // Set up any upstream listeners or background tasks as necessary
64
68
  }
65
69
 
66
70
  // Will be called when this module's last listener is removed, or on dealloc.
67
71
  -(void)stopObserving {
68
72
  lcq_hasListeners = NO;
73
+ [LuciqRNLogger d:LCQRNNetTag format:@"[EventEmitter] stopObserving - LCQNetworkLogger listeners OFF"];
69
74
  // Remove upstream listeners, stop unnecessary background tasks
70
75
  }
71
76
 
72
77
  RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(isNativeInterceptionEnabled) {
73
- return @(LCQNetworkLogger.isNativeNetworkInterceptionFeatureEnabled);
78
+ BOOL enabled = LCQNetworkLogger.isNativeNetworkInterceptionFeatureEnabled;
79
+ [LuciqRNLogger d:LCQRNNetTag format:@"[isNativeInterceptionEnabled] Result=%d", enabled];
80
+ return @(enabled);
74
81
  }
75
82
 
76
83
 
77
84
 
78
85
  RCT_EXPORT_METHOD(registerNetworkLogsListener: (NetworkListenerType) listenerType) {
86
+ [LuciqRNLogger d:LCQRNNetTag format:@"[registerNetworkLogsListener] listenerType=%ld", (long)listenerType];
79
87
  switch (listenerType) {
80
88
  case NetworkListenerTypeFiltering:
81
89
  [self setupRequestFilteringHandler];
@@ -91,7 +99,7 @@ RCT_EXPORT_METHOD(registerNetworkLogsListener: (NetworkListenerType) listenerTyp
91
99
  break;
92
100
 
93
101
  default:
94
- NSLog(@"Unknown NetworkListenerType");
102
+ [LuciqRNLogger e:LCQRNNetTag format:@"[registerNetworkLogsListener] Unknown NetworkListenerType=%ld", (long)listenerType];
95
103
  break;
96
104
  }
97
105
  }
@@ -105,10 +113,12 @@ RCT_EXPORT_METHOD(updateNetworkLogSnapshot:(NSString * _Nonnull)url
105
113
  requestHeaders:(NSDictionary * _Nullable)requestHeaders
106
114
  responseHeaders:(NSDictionary * _Nullable)responseHeaders)
107
115
  {
116
+ [LuciqRNLogger d:LCQRNNetTag format:@"[updateNetworkLogSnapshot] callbackID=%@, url=%@, responseCode=%d, obfuscationMapSize=%lu", callbackID, url, (int)responseCode, (unsigned long)self.requestObfuscationCompletionDictionary.count];
117
+
108
118
  // Validate and construct the URL
109
119
  NSURL *requestURL = [NSURL URLWithString:url];
110
120
  if (!requestURL) {
111
- NSLog(@"Invalid URL: %@", url);
121
+ [LuciqRNLogger e:LCQRNNetTag format:@"[updateNetworkLogSnapshot] Invalid URL: %@", url];
112
122
  return;
113
123
  }
114
124
 
@@ -124,7 +134,7 @@ RCT_EXPORT_METHOD(updateNetworkLogSnapshot:(NSString * _Nonnull)url
124
134
  if (requestHeaders && [requestHeaders isKindOfClass:[NSDictionary class]]) {
125
135
  request.allHTTPHeaderFields = requestHeaders;
126
136
  } else {
127
- NSLog(@"Invalid requestHeaders format, expected NSDictionary.");
137
+ [LuciqRNLogger e:LCQRNNetTag format:@"[updateNetworkLogSnapshot] Invalid requestHeaders format, expected NSDictionary - url=%@", url];
128
138
  }
129
139
 
130
140
  // Ensure callbackID is valid and the completion handler exists
@@ -132,18 +142,20 @@ RCT_EXPORT_METHOD(updateNetworkLogSnapshot:(NSString * _Nonnull)url
132
142
  if (callbackID && [callbackID isKindOfClass:[NSString class]] && completionHandler) {
133
143
  // Call the completion handler with the constructed request
134
144
  completionHandler(request);
145
+ [LuciqRNLogger d:LCQRNNetTag format:@"[updateNetworkLogSnapshot] Obfuscation completion invoked for callbackID=%@", callbackID];
135
146
  } else {
136
- NSLog(@"CallbackID not found or completion handler is unavailable for CallbackID: %@", callbackID);
147
+ [LuciqRNLogger e:LCQRNNetTag format:@"[updateNetworkLogSnapshot] CallbackID not found or completion handler unavailable for callbackID=%@, mapSize=%lu", callbackID, (unsigned long)self.requestObfuscationCompletionDictionary.count];
137
148
  }
138
149
  }
139
150
 
140
151
  RCT_EXPORT_METHOD(setNetworkLoggingRequestFilterPredicateIOS: (NSString * _Nonnull) callbackID : (BOOL)value ){
152
+ [LuciqRNLogger d:LCQRNNetTag format:@"[setNetworkLoggingRequestFilterPredicateIOS] callbackID=%@, save=%d, filteringMapSize=%lu", callbackID, value, (unsigned long)self.requestFilteringCompletionDictionary.count];
141
153
 
142
154
  if (self.requestFilteringCompletionDictionary[callbackID] != nil) {
143
155
  // ⬇️ YES == Request will be saved, NO == will be ignored
144
156
  ((LCQURLRequestResponseAsyncFilteringCompletedHandler)self.requestFilteringCompletionDictionary[callbackID])(value);
145
157
  } else {
146
- NSLog(@"Not Available Completion");
158
+ [LuciqRNLogger e:LCQRNNetTag format:@"[setNetworkLoggingRequestFilterPredicateIOS] Filtering completion not found for callbackID=%@", callbackID];
147
159
  }
148
160
  }
149
161
 
@@ -152,13 +164,18 @@ RCT_EXPORT_METHOD(setNetworkLoggingRequestFilterPredicateIOS: (NSString * _Nonnu
152
164
 
153
165
  // Set up the filtering handler
154
166
  - (void)setupRequestFilteringHandler {
167
+ [LuciqRNLogger d:LCQRNNetTag format:@"[setupRequestFilteringHandler] Registering filtering handler with LCQNetworkLogger"];
155
168
  [LCQNetworkLogger setCPRequestFilteringHandler:^(NSURLRequest * _Nonnull request, void (^ _Nonnull completion)(BOOL)) {
156
169
  NSString *callbackID = [[[NSUUID alloc] init] UUIDString];
157
170
  self.requestFilteringCompletionDictionary[callbackID] = completion;
171
+ [LuciqRNLogger d:LCQRNNetTag format:@"[FilteringHandler] Received request - callbackID=%@, url=%@, mapSize=%lu", callbackID, request.URL.absoluteString, (unsigned long)self.requestFilteringCompletionDictionary.count];
158
172
 
159
173
  NSDictionary *dict = [self createNetworkRequestDictForRequest:request callbackID:callbackID];
160
174
  if(lcq_hasListeners){
161
175
  [self sendEventWithName:@"LCQNetworkLoggerHandler" body:dict];
176
+ [LuciqRNLogger d:LCQRNNetTag format:@"[FilteringHandler] Sent event to JS for url=%@", request.URL.absoluteString];
177
+ } else {
178
+ [LuciqRNLogger w:LCQRNNetTag format:@"[FilteringHandler] Event DROPPED (no JS listeners) for url=%@", request.URL.absoluteString];
162
179
  }
163
180
 
164
181
  }];
@@ -166,14 +183,19 @@ RCT_EXPORT_METHOD(setNetworkLoggingRequestFilterPredicateIOS: (NSString * _Nonnu
166
183
 
167
184
  // Set up the obfuscation handler
168
185
  - (void)setupRequestObfuscationHandler {
186
+ [LuciqRNLogger d:LCQRNNetTag format:@"[setupRequestObfuscationHandler] Registering obfuscation handler with LCQNetworkLogger"];
169
187
  [LCQNetworkLogger setCPRequestAsyncObfuscationHandler:^(NSURLRequest * _Nonnull request, void (^ _Nonnull completion)(NSURLRequest * _Nonnull)) {
170
188
  NSString *callbackID = [[[NSUUID alloc] init] UUIDString];
171
189
  self.requestObfuscationCompletionDictionary[callbackID] = completion;
190
+ [LuciqRNLogger d:LCQRNNetTag format:@"[ObfuscationHandler] Received request - callbackID=%@, url=%@, mapSize=%lu", callbackID, request.URL.absoluteString, (unsigned long)self.requestObfuscationCompletionDictionary.count];
172
191
 
173
192
 
174
193
  NSDictionary *dict = [self createNetworkRequestDictForRequest:request callbackID:callbackID];
175
194
  if (lcq_hasListeners) {
176
195
  [self sendEventWithName:@"LCQNetworkLoggerHandler" body:dict];
196
+ [LuciqRNLogger d:LCQRNNetTag format:@"[ObfuscationHandler] Sent event to JS for url=%@", request.URL.absoluteString];
197
+ } else {
198
+ [LuciqRNLogger w:LCQRNNetTag format:@"[ObfuscationHandler] Event DROPPED (no JS listeners) for url=%@", request.URL.absoluteString];
177
199
  }
178
200
 
179
201
  }];
@@ -194,10 +216,12 @@ RCT_EXPORT_METHOD(setNetworkLoggingRequestFilterPredicateIOS: (NSString * _Nonnu
194
216
  }
195
217
 
196
218
  RCT_EXPORT_METHOD(forceStartNetworkLoggingIOS) {
219
+ [LuciqRNLogger d:LCQRNNetTag format:@"[forceStartNetworkLoggingIOS] Starting native network logging"];
197
220
  [LCQNetworkLogger forceStartNetworkLogging];
198
221
  }
199
222
 
200
223
  RCT_EXPORT_METHOD(forceStopNetworkLoggingIOS) {
224
+ [LuciqRNLogger d:LCQRNNetTag format:@"[forceStopNetworkLoggingIOS] Stopping native network logging"];
201
225
  [LCQNetworkLogger forceStopNetworkLogging];
202
226
  }
203
227
 
@@ -15,6 +15,9 @@
15
15
  #import <React/RCTUIManager.h>
16
16
  #import "RNLuciq.h"
17
17
  #import "Util/LCQNetworkLogger+CP.h"
18
+ #import "Util/LuciqRNLogger.h"
19
+
20
+ static NSString *const LCQRNNetTag = @"LCQ-RN-NET";
18
21
 
19
22
  @interface Luciq (PrivateWillSendAPI)
20
23
  + (void)setWillSendReportHandler_private:(void(^)(LCQReport *report, void(^reportCompletionHandler)(LCQReport *)))willSendReportHandler_private;
@@ -46,6 +49,8 @@ RCT_EXPORT_METHOD(init:(NSString *)token
46
49
  options:(nullable NSDictionary *)options
47
50
  overAirVersion :(NSDictionary *)overAirVersion
48
51
  ) {
52
+ [LuciqRNLogger setLevel:sdkDebugLogsLevel];
53
+ [LuciqRNLogger d:LCQRNNetTag format:@"[init] Called - logLevel=%ld, useNativeNetworkInterception=%d, codePushVersion=%@, appVariant=%@", (long)sdkDebugLogsLevel, useNativeNetworkInterception, codePushVersion, appVariant];
49
54
 
50
55
  if(appVariant != nil){
51
56
  Luciq.appVariant = appVariant;
@@ -65,6 +70,7 @@ RCT_EXPORT_METHOD(init:(NSString *)token
65
70
  invocationEvents:invocationEvents
66
71
  debugLogsLevel:sdkDebugLogsLevel
67
72
  useNativeNetworkInterception:useNativeNetworkInterception];
73
+ [LuciqRNLogger d:LCQRNNetTag format:@"[init] SDK build complete"];
68
74
  }
69
75
 
70
76
  RCT_EXPORT_METHOD(setCodePushVersion:(NSString *)version) {
@@ -409,11 +415,13 @@ RCT_EXPORT_METHOD(networkLogIOS:(NSString * _Nonnull)url
409
415
  gqlQueryName:(NSString * _Nullable)gqlQueryName
410
416
  serverErrorMessage:(NSString * _Nullable)serverErrorMessage
411
417
  w3cExternalTraceAttributes:(NSDictionary * _Nullable)w3cExternalTraceAttributes){
418
+ [LuciqRNLogger d:LCQRNNetTag format:@"[networkLogIOS] Received from JS: %@ %@, status=%d, duration=%.0fms, startTime=%.0f, error=%@, gqlQuery=%@, reqBodyLen=%lu, resBodyLen=%lu", method, url, (int)responseCode, duration * 1000, startTime, errorDomain, gqlQueryName, (unsigned long)requestBody.length, (unsigned long)responseBody.length];
412
419
  NSNumber *isW3cCaught = (w3cExternalTraceAttributes[@"isW3cHeaderFound"] != [NSNull null]) ? w3cExternalTraceAttributes[@"isW3cHeaderFound"] : nil;
413
420
  NSNumber * partialID = (w3cExternalTraceAttributes[@"partialId"] != [NSNull null]) ? w3cExternalTraceAttributes[@"partialId"] : nil;
414
421
  NSNumber * timestamp = (w3cExternalTraceAttributes[@"networkStartTimeInSeconds"] != [NSNull null]) ? w3cExternalTraceAttributes[@"networkStartTimeInSeconds"] : nil;
415
422
  NSString * generatedW3CTraceparent = (w3cExternalTraceAttributes[@"w3cGeneratedHeader"] != [NSNull null]) ? w3cExternalTraceAttributes[@"w3cGeneratedHeader"] : nil;
416
423
  NSString * caughtW3CTraceparent = (w3cExternalTraceAttributes[@"w3cCaughtHeader"] != [NSNull null]) ? w3cExternalTraceAttributes[@"w3cCaughtHeader"] : nil;
424
+ [LuciqRNLogger d:LCQRNNetTag format:@"[networkLogIOS] W3C attrs - isW3cCaughted=%@, partialID=%@, timestamp=%@, generatedHeader=%@, caughtHeader=%@", isW3cCaught, partialID, timestamp, generatedW3CTraceparent, caughtW3CTraceparent];
417
425
 
418
426
  [LCQNetworkLogger addNetworkLogWithUrl:url
419
427
  method:method
@@ -437,6 +445,7 @@ RCT_EXPORT_METHOD(networkLogIOS:(NSString * _Nonnull)url
437
445
  generatedW3CTraceparent:generatedW3CTraceparent
438
446
  caughtedW3CTraceparent:caughtW3CTraceparent
439
447
  ];
448
+ [LuciqRNLogger d:LCQRNNetTag format:@"[networkLogIOS] Forwarded to LCQNetworkLogger: %@ %@", method, url];
440
449
  }
441
450
 
442
451
  RCT_EXPORT_METHOD(addPrivateView: (nonnull NSNumber *)reactTag) {
@@ -501,13 +510,19 @@ RCT_EXPORT_METHOD(willRedirectToStore){
501
510
  }
502
511
 
503
512
  RCT_EXPORT_METHOD(isW3ExternalTraceIDEnabled:(RCTPromiseResolveBlock)resolve :(RCTPromiseRejectBlock)reject) {
504
- resolve(@(LCQNetworkLogger.w3ExternalTraceIDEnabled));
513
+ BOOL enabled = LCQNetworkLogger.w3ExternalTraceIDEnabled;
514
+ [LuciqRNLogger d:LCQRNNetTag format:@"[isW3ExternalTraceIDEnabled] Result=%d", enabled];
515
+ resolve(@(enabled));
505
516
  }
506
517
  RCT_EXPORT_METHOD(isW3ExternalGeneratedHeaderEnabled:(RCTPromiseResolveBlock)resolve :(RCTPromiseRejectBlock)reject) {
507
- resolve(@(LCQNetworkLogger.w3ExternalGeneratedHeaderEnabled));
518
+ BOOL enabled = LCQNetworkLogger.w3ExternalGeneratedHeaderEnabled;
519
+ [LuciqRNLogger d:LCQRNNetTag format:@"[isW3ExternalGeneratedHeaderEnabled] Result=%d", enabled];
520
+ resolve(@(enabled));
508
521
  }
509
522
  RCT_EXPORT_METHOD(isW3CaughtHeaderEnabled:(RCTPromiseResolveBlock)resolve :(RCTPromiseRejectBlock)reject) {
510
- resolve(@(LCQNetworkLogger.w3CaughtHeaderEnabled));
523
+ BOOL enabled = LCQNetworkLogger.w3CaughtHeaderEnabled;
524
+ [LuciqRNLogger d:LCQRNNetTag format:@"[isW3CaughtHeaderEnabled] Result=%d", enabled];
525
+ resolve(@(enabled));
511
526
  }
512
527
 
513
528
 
@@ -550,7 +565,9 @@ RCT_EXPORT_METHOD(enableAutoMasking:(NSArray *)autoMaskingTypes) {
550
565
  };
551
566
 
552
567
  RCT_EXPORT_METHOD(getNetworkBodyMaxSize:(RCTPromiseResolveBlock)resolve :(RCTPromiseRejectBlock)reject) {
553
- resolve(@(LCQNetworkLogger.getNetworkBodyMaxSize));
568
+ NSUInteger limit = LCQNetworkLogger.getNetworkBodyMaxSize;
569
+ [LuciqRNLogger d:LCQRNNetTag format:@"[getNetworkBodyMaxSize] Result=%lu", (unsigned long)limit];
570
+ resolve(@(limit));
554
571
  }
555
572
 
556
573
  RCT_EXPORT_METHOD(setNetworkLogBodyEnabled:(BOOL)isEnabled) {