@luciq/react-native 19.2.2 → 19.3.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.
Files changed (35) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +87 -0
  3. package/android/native.gradle +1 -1
  4. package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqAPMModule.java +202 -117
  5. package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqReactnativeModule.java +20 -0
  6. package/dist/constants/Strings.d.ts +9 -0
  7. package/dist/constants/Strings.js +12 -0
  8. package/dist/index.d.ts +2 -1
  9. package/dist/index.js +2 -1
  10. package/dist/models/CustomSpan.d.ts +47 -0
  11. package/dist/models/CustomSpan.js +82 -0
  12. package/dist/modules/APM.d.ts +58 -0
  13. package/dist/modules/APM.js +62 -0
  14. package/dist/native/NativeAPM.d.ts +3 -0
  15. package/dist/native/NativeLuciq.d.ts +1 -0
  16. package/dist/utils/CustomSpansManager.d.ts +38 -0
  17. package/dist/utils/CustomSpansManager.js +173 -0
  18. package/ios/RNLuciq/LuciqAPMBridge.h +13 -0
  19. package/ios/RNLuciq/LuciqAPMBridge.m +55 -0
  20. package/ios/RNLuciq/LuciqReactBridge.m +12 -0
  21. package/ios/RNLuciq/Util/LCQAPM+PrivateAPIs.h +1 -0
  22. package/ios/native.rb +1 -1
  23. package/package.json +1 -1
  24. package/scripts/releases/changelog_to_slack_formatter.sh +9 -0
  25. package/scripts/releases/get_job_approver.sh +60 -0
  26. package/scripts/releases/get_release_notes.sh +22 -0
  27. package/scripts/releases/get_sdk_version.sh +5 -0
  28. package/scripts/releases/get_slack_id_from_username.sh +24 -0
  29. package/src/constants/Strings.ts +24 -0
  30. package/src/index.ts +2 -0
  31. package/src/models/CustomSpan.ts +102 -0
  32. package/src/modules/APM.ts +72 -0
  33. package/src/native/NativeAPM.ts +7 -0
  34. package/src/native/NativeLuciq.ts +1 -0
  35. package/src/utils/CustomSpansManager.ts +202 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## [19.3.0](https://github.com/luciqai/luciq-reactnative-sdk/compare/v19.3.0...19.2.1)
4
+
5
+ ### Added
6
+
7
+ - **Custom Spans**: New feature to manually instrument code paths for performance tracking
8
+ - `APM.startCustomSpan(name)` - Start a custom span and return a span object
9
+ - `CustomSpan.end()` - End the span and report to SDK
10
+ - `APM.addCompletedCustomSpan(name, startDate, endDate)` - Record a pre-completed span
11
+ - Support for up to 100 concurrent spans
12
+ - Comprehensive validation (name length, empty checks, timestamp validation)
13
+ - Feature flag support to enable/disable custom spans
14
+
15
+ ### Changed
16
+
17
+ - Bump Luciq iOS SDK to v19.5.0 ([#37](https://github.com/luciqai/luciq-reactnative-sdk/pull/37)). [See release notes](https://github.com/luciqai/Luciq-iOS-sdk/releases/tag/19.5.0).
18
+
19
+ - Bump Luciq Android SDK to v19.3.0 ([#37](https://github.com/luciqai/luciq-reactnative-sdk/pull/37)). [See release notes](https://github.com/luciqai/Luciq-Android-sdk/releases/tag/v19.4.0).
20
+
3
21
  ## [19.2.2](https://github.com/luciqai/luciq-reactnative-sdk/compare/v19.2.2...19.2.1)
4
22
 
5
23
  ### Changed
package/README.md CHANGED
@@ -141,6 +141,93 @@ You can disable Repro Steps using the following API:
141
141
  Luciq.setReproStepsConfig({ all: ReproStepsMode.disabled });
142
142
  ```
143
143
 
144
+ ## Custom Spans
145
+
146
+ Custom spans allow you to manually instrument arbitrary code paths for performance tracking. This feature enables tracking of operations not covered by automatic instrumentation.
147
+
148
+ ### Starting and Ending a Span
149
+
150
+ ```javascript
151
+ import { APM } from '@luciq/react-native';
152
+
153
+ // Start a custom span
154
+ const span = await APM.startCustomSpan('Load User Profile');
155
+
156
+ if (span) {
157
+ try {
158
+ // Perform your operation
159
+ await loadUserProfile();
160
+ } finally {
161
+ // Always end the span, even if operation fails
162
+ await span.end();
163
+ }
164
+ }
165
+ ```
166
+
167
+ ### Recording a Completed Span
168
+
169
+ ```javascript
170
+ const start = new Date();
171
+ // ... operation already completed ...
172
+ const end = new Date();
173
+
174
+ await APM.addCompletedCustomSpan('Cache Lookup', start, end);
175
+ ```
176
+
177
+ ### Important Notes
178
+
179
+ - **Span Limit**: Maximum of 100 concurrent spans at any time
180
+ - **Name Length**: Span names are truncated to 150 characters
181
+ - **Validation**: Empty names or invalid timestamps will be rejected
182
+ - **Idempotent**: Calling `span.end()` multiple times is safe
183
+ - **Feature Flags**: Spans are only created when SDK is initialized, APM is enabled, and custom spans feature is enabled
184
+
185
+ ### API Reference
186
+
187
+ #### `APM.startCustomSpan(name: string): Promise<CustomSpan | null>`
188
+
189
+ Starts a custom span for performance tracking.
190
+
191
+ **Parameters:**
192
+
193
+ - `name` (string): The name of the span. Cannot be empty. Max 150 characters.
194
+
195
+ **Returns:**
196
+
197
+ - `Promise<CustomSpan | null>`: The span object to end later, or `null` if the span could not be created.
198
+
199
+ **Example:**
200
+
201
+ ```javascript
202
+ const span = await APM.startCustomSpan('Database Query');
203
+ if (span) {
204
+ // ... perform operation ...
205
+ await span.end();
206
+ }
207
+ ```
208
+
209
+ #### `CustomSpan.end(): Promise<void>`
210
+
211
+ Ends the custom span and reports it to the SDK. This method is idempotent.
212
+
213
+ #### `APM.addCompletedCustomSpan(name: string, startDate: Date, endDate: Date): Promise<void>`
214
+
215
+ Records a completed custom span with pre-recorded timestamps.
216
+
217
+ **Parameters:**
218
+
219
+ - `name` (string): The name of the span. Cannot be empty. Max 150 characters.
220
+ - `startDate` (Date): The start time of the operation.
221
+ - `endDate` (Date): The end time of the operation (must be after startDate).
222
+
223
+ **Example:**
224
+
225
+ ```javascript
226
+ const start = new Date(Date.now() - 1500);
227
+ const end = new Date();
228
+ await APM.addCompletedCustomSpan('Background Task', start, end);
229
+ ```
230
+
144
231
  ## Documentation
145
232
 
146
233
  For more details about the supported APIs and how to use them, check our [**Documentation**](https://docs.luciq.ai/docs/react-native-overview).
@@ -1,5 +1,5 @@
1
1
  project.ext.luciq = [
2
- version: '19.2.2'
2
+ version: '19.3.0'
3
3
  ]
4
4
 
5
5
  dependencies {
@@ -13,18 +13,20 @@ import com.facebook.react.bridge.Promise;
13
13
  import com.facebook.react.bridge.ReactApplicationContext;
14
14
  import com.facebook.react.bridge.ReactMethod;
15
15
  import com.facebook.react.bridge.ReadableMap;
16
- import ai.luciq.apm.APM;
17
- import ai.luciq.apm.networking.APMNetworkLogger;
18
- import ai.luciq.apm.networkinterception.cp.APMCPNetworkLog;
19
- import ai.luciq.reactlibrary.utils.EventEmitterModule;
20
- import ai.luciq.reactlibrary.utils.MainThreadHandler;
21
16
 
22
17
  import java.lang.reflect.Method;
23
- import java.util.HashMap;
18
+ import java.util.Date;
24
19
 
25
20
  import javax.annotation.Nonnull;
26
21
 
27
- import static ai.luciq.reactlibrary.utils.LuciqUtil.getMethod;
22
+ import ai.luciq.apm.APM;
23
+ import ai.luciq.apm.InternalAPM;
24
+ import ai.luciq.apm.configuration.cp.APMFeature;
25
+ import ai.luciq.apm.configuration.cp.FeatureAvailabilityCallback;
26
+ import ai.luciq.apm.networking.APMNetworkLogger;
27
+ import ai.luciq.apm.networkinterception.cp.APMCPNetworkLog;
28
+ import ai.luciq.reactlibrary.utils.EventEmitterModule;
29
+ import ai.luciq.reactlibrary.utils.MainThreadHandler;
28
30
 
29
31
  public class RNLuciqAPMModule extends EventEmitterModule {
30
32
 
@@ -240,73 +242,73 @@ public class RNLuciqAPMModule extends EventEmitterModule {
240
242
  });
241
243
  }
242
244
 
243
- /**
244
- * The `networkLogAndroid` function logs network-related information using APMNetworkLogger in a React
245
- * Native module.
246
- *
247
- * @param requestStartTime The `requestStartTime` parameter in the `networkLogAndroid` method
248
- * represents the timestamp when the network request started. It is of type `double` and is passed as
249
- * a parameter to log network-related information.
250
- * @param requestDuration The `requestDuration` parameter in the `networkLogAndroid` method represents
251
- * the duration of the network request in milliseconds. It indicates the time taken for the request to
252
- * complete from the moment it was initiated until the response was received. This parameter helps in
253
- * measuring the performance of network requests and identifying any potential
254
- * @param requestHeaders requestHeaders is a string parameter that contains the headers of the network
255
- * request. It typically includes information such as the content type, authorization token, and any
256
- * other headers that were sent with the request.
257
- * @param requestBody The `requestBody` parameter in the `networkLogAndroid` method represents the
258
- * body of the HTTP request being logged. It contains the data that is sent as part of the request to
259
- * the server. This could include form data, JSON payload, XML data, or any other content that is
260
- * being transmitted
261
- * @param requestBodySize The `requestBodySize` parameter in the `networkLogAndroid` method represents
262
- * the size of the request body in bytes. It is a double value that indicates the size of the request
263
- * body being sent in the network request. This parameter is used to log information related to the
264
- * network request, including details
265
- * @param requestMethod The `requestMethod` parameter in the `networkLogAndroid` method represents the
266
- * HTTP method used in the network request, such as GET, POST, PUT, DELETE, etc. It indicates the type
267
- * of operation that the client is requesting from the server.
268
- * @param requestUrl The `requestUrl` parameter in the `networkLogAndroid` method represents the URL
269
- * of the network request being logged. It typically contains the address of the server to which the
270
- * request is being made, along with any additional path or query parameters required for the request.
271
- * This URL is essential for identifying the
272
- * @param requestContentType The `requestContentType` parameter in the `networkLogAndroid` method
273
- * represents the content type of the request being made. This could be values like
274
- * "application/json", "application/xml", "text/plain", etc., indicating the format of the data being
275
- * sent in the request body. It helps in specifying
276
- * @param responseHeaders The `responseHeaders` parameter in the `networkLogAndroid` method represents
277
- * the headers of the response received from a network request. These headers typically include
278
- * information such as content type, content length, server information, and any other metadata
279
- * related to the response. The `responseHeaders` parameter is expected to
280
- * @param responseBody The `responseBody` parameter in the `networkLogAndroid` method represents the
281
- * body of the response received from a network request. It contains the data or content sent back by
282
- * the server in response to the request made by the client. This could be in various formats such as
283
- * JSON, XML, HTML
284
- * @param responseBodySize The `responseBodySize` parameter in the `networkLogAndroid` method
285
- * represents the size of the response body in bytes. It is a double value that indicates the size of
286
- * the response body received from the network request. This parameter is used to log information
287
- * related to the network request and response, including
288
- * @param statusCode The `statusCode` parameter in the `networkLogAndroid` method represents the HTTP
289
- * status code of the network request/response. It indicates the status of the HTTP response, such as
290
- * success (200), redirection (3xx), client errors (4xx), or server errors (5xx). This parameter is
291
- * @param responseContentType The `responseContentType` parameter in the `networkLogAndroid` method
292
- * represents the content type of the response received from the network request. It indicates the
293
- * format of the data in the response, such as JSON, XML, HTML, etc. This information is useful for
294
- * understanding how to parse and handle the
295
- * @param errorDomain The `errorDomain` parameter in the `networkLogAndroid` method is used to specify
296
- * the domain of an error, if any occurred during the network request. If there was no error, this
297
- * parameter will be `null`.
298
- * @param w3cAttributes The `w3cAttributes` parameter in the `networkLogAndroid` method is a
299
- * ReadableMap object that contains additional attributes related to W3C external trace. It may
300
- * include the following key-value pairs:
301
- * @param gqLCQueryName The `gqLCQueryName` parameter in the `networkLogAndroid` method represents the
302
- * name of the GraphQL query being executed. It is a nullable parameter, meaning it can be null if no
303
- * GraphQL query name is provided. This parameter is used to log information related to GraphQL
304
- * queries in the network logging
305
- * @param serverErrorMessage The `serverErrorMessage` parameter in the `networkLogAndroid` method is
306
- * used to pass any error message received from the server during network communication. This message
307
- * can provide additional details about any errors that occurred on the server side, helping in
308
- * debugging and troubleshooting network-related issues.
309
- */
245
+ /**
246
+ * The `networkLogAndroid` function logs network-related information using APMNetworkLogger in a React
247
+ * Native module.
248
+ *
249
+ * @param requestStartTime The `requestStartTime` parameter in the `networkLogAndroid` method
250
+ * represents the timestamp when the network request started. It is of type `double` and is passed as
251
+ * a parameter to log network-related information.
252
+ * @param requestDuration The `requestDuration` parameter in the `networkLogAndroid` method represents
253
+ * the duration of the network request in milliseconds. It indicates the time taken for the request to
254
+ * complete from the moment it was initiated until the response was received. This parameter helps in
255
+ * measuring the performance of network requests and identifying any potential
256
+ * @param requestHeaders requestHeaders is a string parameter that contains the headers of the network
257
+ * request. It typically includes information such as the content type, authorization token, and any
258
+ * other headers that were sent with the request.
259
+ * @param requestBody The `requestBody` parameter in the `networkLogAndroid` method represents the
260
+ * body of the HTTP request being logged. It contains the data that is sent as part of the request to
261
+ * the server. This could include form data, JSON payload, XML data, or any other content that is
262
+ * being transmitted
263
+ * @param requestBodySize The `requestBodySize` parameter in the `networkLogAndroid` method represents
264
+ * the size of the request body in bytes. It is a double value that indicates the size of the request
265
+ * body being sent in the network request. This parameter is used to log information related to the
266
+ * network request, including details
267
+ * @param requestMethod The `requestMethod` parameter in the `networkLogAndroid` method represents the
268
+ * HTTP method used in the network request, such as GET, POST, PUT, DELETE, etc. It indicates the type
269
+ * of operation that the client is requesting from the server.
270
+ * @param requestUrl The `requestUrl` parameter in the `networkLogAndroid` method represents the URL
271
+ * of the network request being logged. It typically contains the address of the server to which the
272
+ * request is being made, along with any additional path or query parameters required for the request.
273
+ * This URL is essential for identifying the
274
+ * @param requestContentType The `requestContentType` parameter in the `networkLogAndroid` method
275
+ * represents the content type of the request being made. This could be values like
276
+ * "application/json", "application/xml", "text/plain", etc., indicating the format of the data being
277
+ * sent in the request body. It helps in specifying
278
+ * @param responseHeaders The `responseHeaders` parameter in the `networkLogAndroid` method represents
279
+ * the headers of the response received from a network request. These headers typically include
280
+ * information such as content type, content length, server information, and any other metadata
281
+ * related to the response. The `responseHeaders` parameter is expected to
282
+ * @param responseBody The `responseBody` parameter in the `networkLogAndroid` method represents the
283
+ * body of the response received from a network request. It contains the data or content sent back by
284
+ * the server in response to the request made by the client. This could be in various formats such as
285
+ * JSON, XML, HTML
286
+ * @param responseBodySize The `responseBodySize` parameter in the `networkLogAndroid` method
287
+ * represents the size of the response body in bytes. It is a double value that indicates the size of
288
+ * the response body received from the network request. This parameter is used to log information
289
+ * related to the network request and response, including
290
+ * @param statusCode The `statusCode` parameter in the `networkLogAndroid` method represents the HTTP
291
+ * status code of the network request/response. It indicates the status of the HTTP response, such as
292
+ * success (200), redirection (3xx), client errors (4xx), or server errors (5xx). This parameter is
293
+ * @param responseContentType The `responseContentType` parameter in the `networkLogAndroid` method
294
+ * represents the content type of the response received from the network request. It indicates the
295
+ * format of the data in the response, such as JSON, XML, HTML, etc. This information is useful for
296
+ * understanding how to parse and handle the
297
+ * @param errorDomain The `errorDomain` parameter in the `networkLogAndroid` method is used to specify
298
+ * the domain of an error, if any occurred during the network request. If there was no error, this
299
+ * parameter will be `null`.
300
+ * @param w3cAttributes The `w3cAttributes` parameter in the `networkLogAndroid` method is a
301
+ * ReadableMap object that contains additional attributes related to W3C external trace. It may
302
+ * include the following key-value pairs:
303
+ * @param gqLCQueryName The `gqLCQueryName` parameter in the `networkLogAndroid` method represents the
304
+ * name of the GraphQL query being executed. It is a nullable parameter, meaning it can be null if no
305
+ * GraphQL query name is provided. This parameter is used to log information related to GraphQL
306
+ * queries in the network logging
307
+ * @param serverErrorMessage The `serverErrorMessage` parameter in the `networkLogAndroid` method is
308
+ * used to pass any error message received from the server during network communication. This message
309
+ * can provide additional details about any errors that occurred on the server side, helping in
310
+ * debugging and troubleshooting network-related issues.
311
+ */
310
312
  @ReactMethod
311
313
  private void networkLogAndroid(final double requestStartTime,
312
314
  final double requestDuration,
@@ -325,15 +327,15 @@ public class RNLuciqAPMModule extends EventEmitterModule {
325
327
  @Nullable final ReadableMap w3cAttributes,
326
328
  @Nullable final String gqLCQueryName,
327
329
  @Nullable final String serverErrorMessage
328
- ) {
330
+ ) {
329
331
  try {
330
332
  APMNetworkLogger networkLogger = new APMNetworkLogger();
331
333
 
332
334
  final boolean hasError = errorDomain != null && !errorDomain.isEmpty();
333
335
  final String errorMessage = hasError ? errorDomain : null;
334
- Boolean isW3cHeaderFound=false;
335
- Long partialId=null;
336
- Long networkStartTimeInSeconds=null;
336
+ Boolean isW3cHeaderFound = false;
337
+ Long partialId = null;
338
+ Long networkStartTimeInSeconds = null;
337
339
 
338
340
 
339
341
  try {
@@ -342,7 +344,7 @@ public class RNLuciqAPMModule extends EventEmitterModule {
342
344
  }
343
345
 
344
346
  if (!w3cAttributes.isNull("partialId")) {
345
- partialId =(long) w3cAttributes.getDouble("partialId");
347
+ partialId = (long) w3cAttributes.getDouble("partialId");
346
348
  networkStartTimeInSeconds = (long) w3cAttributes.getDouble("networkStartTimeInSeconds");
347
349
  }
348
350
 
@@ -360,52 +362,135 @@ public class RNLuciqAPMModule extends EventEmitterModule {
360
362
  try {
361
363
  Method method = getMethod(Class.forName("ai.luciq.apm.networking.APMNetworkLogger"), "log", long.class, long.class, String.class, String.class, long.class, String.class, String.class, String.class, String.class, String.class, long.class, int.class, String.class, String.class, String.class, String.class, APMCPNetworkLog.W3CExternalTraceAttributes.class);
362
364
  if (method != null) {
363
- method.invoke(
364
- networkLogger,
365
- (long) requestStartTime * 1000,
366
- (long) requestDuration,
367
- requestHeaders,
368
- requestBody,
369
- (long) requestBodySize,
370
- requestMethod,
371
- requestUrl,
372
- requestContentType,
373
- responseHeaders,
374
- responseBody,
375
- (long)responseBodySize,
376
- (int) statusCode,
377
- responseContentType,
378
- errorMessage,
379
- gqLCQueryName,
380
- serverErrorMessage,
381
- w3cExternalTraceAttributes
382
- );
365
+ method.invoke(
366
+ networkLogger,
367
+ (long) requestStartTime * 1000,
368
+ (long) requestDuration,
369
+ requestHeaders,
370
+ requestBody,
371
+ (long) requestBodySize,
372
+ requestMethod,
373
+ requestUrl,
374
+ requestContentType,
375
+ responseHeaders,
376
+ responseBody,
377
+ (long) responseBodySize,
378
+ (int) statusCode,
379
+ responseContentType,
380
+ errorMessage,
381
+ gqLCQueryName,
382
+ serverErrorMessage,
383
+ w3cExternalTraceAttributes
384
+ );
383
385
  } else {
384
386
  Log.e("IB-CP-Bridge", "APMNetworkLogger.log was not found by reflection");
385
387
  }
386
388
  } catch (Throwable e) {
387
389
  e.printStackTrace();
388
390
  }
389
- } catch(Throwable e) {
391
+ } catch (Throwable e) {
390
392
  e.printStackTrace();
391
393
  }
392
394
  }
393
- /**
394
- * Enables or disables screen rendering
395
- *
396
- * @param isEnabled boolean indicating enabled or disabled.
397
- */
398
- @ReactMethod
399
- public void setScreenRenderingEnabled(boolean isEnabled) {
400
- MainThreadHandler.runOnMainThread(new Runnable() {
401
- @Override
402
- public void run() {
403
- try {
404
- APM.setScreenRenderingEnabled(isEnabled);
405
- } catch (Exception e) {
406
- e.printStackTrace();
407
- }
395
+
396
+ /**
397
+ * Enables or disables screen rendering
398
+ *
399
+ * @param isEnabled boolean indicating enabled or disabled.
400
+ */
401
+ @ReactMethod
402
+ public void setScreenRenderingEnabled(boolean isEnabled) {
403
+ MainThreadHandler.runOnMainThread(new Runnable() {
404
+ @Override
405
+ public void run() {
406
+ try {
407
+ APM.setScreenRenderingEnabled(isEnabled);
408
+ } catch (Exception e) {
409
+ e.printStackTrace();
408
410
  }
409
- });
410
- }
411
+ }
412
+ });
413
+ }
414
+
415
+ /**
416
+ * Syncs a custom span to the native SDK (currently logs only).
417
+ *
418
+ * @param name Name of the custom span
419
+ * @param startTimestamp Start time in microseconds since epoch
420
+ * @param endTimestamp End time in microseconds since epoch
421
+ * @param promise Promise to resolve when complete
422
+ */
423
+ @ReactMethod
424
+ public void syncCustomSpan(final String name,
425
+ final double startTimestamp,
426
+ final double endTimestamp,
427
+ final Promise promise) {
428
+ MainThreadHandler.runOnMainThread(new Runnable() {
429
+ @Override
430
+ public void run() {
431
+ try {
432
+ // Convert microseconds to milliseconds for Date objects
433
+ Date startDate = new Date((long) (startTimestamp / 1000));
434
+ Date endDate = new Date((long) (endTimestamp / 1000));
435
+
436
+ APM.addCompletedCustomSpan(name, startDate, endDate);
437
+
438
+ promise.resolve(true);
439
+ } catch (Exception e) {
440
+ Log.e("IB-CP-Bridge", "Error syncing span", e);
441
+ promise.resolve(false);
442
+ }
443
+ }
444
+ });
445
+ }
446
+
447
+ /**
448
+ * Checks if custom spans feature is enabled.
449
+ *
450
+ * @param promise Promise that resolves with boolean indicating if enabled
451
+ */
452
+ @ReactMethod
453
+ public void isCustomSpanEnabled(final Promise promise) {
454
+ MainThreadHandler.runOnMainThread(new Runnable() {
455
+ @Override
456
+ public void run() {
457
+ try {
458
+ InternalAPM._isFeatureEnabledCP(APMFeature.CUSTOM_SPANS, "LuciqCustomSpan", new FeatureAvailabilityCallback() {
459
+ @Override
460
+ public void invoke(boolean isEnabled) {
461
+ promise.resolve(isEnabled);
462
+ }
463
+ });
464
+ } catch (Exception e) {
465
+ Log.e("IB-CP-Bridge", "Error checking feature flag", e);
466
+ promise.resolve(false);
467
+ }
468
+ }
469
+ });
470
+ }
471
+
472
+ /**
473
+ * Checks if APM is enabled.
474
+ *
475
+ * @param promise Promise that resolves with boolean indicating if enabled
476
+ */
477
+ @ReactMethod
478
+ public void isAPMEnabled(final Promise promise) {
479
+ MainThreadHandler.runOnMainThread(new Runnable() {
480
+ @Override
481
+ public void run() {
482
+ try {
483
+ InternalAPM._isFeatureEnabledCP(APMFeature.APM, "APM", new FeatureAvailabilityCallback() {
484
+ @Override
485
+ public void invoke(boolean isEnabled) {
486
+ promise.resolve(isEnabled);
487
+ }
488
+ });
489
+ } catch (Exception e) {
490
+ Log.e("IB-CP-Bridge", "Error checking APM enabled", e);
491
+ promise.resolve(false);
492
+ }
493
+ }
494
+ });
495
+ }
411
496
  }
@@ -222,6 +222,26 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
222
222
  });
223
223
  }
224
224
 
225
+ /**
226
+ * Checks if the SDK is built or not.
227
+ *
228
+ * @param promise Promise that resolves with boolean indicating if enabled
229
+ */
230
+ @ReactMethod
231
+ public void isBuilt(final Promise promise) {
232
+ MainThreadHandler.runOnMainThread(new Runnable() {
233
+ @Override
234
+ public void run() {
235
+ try {
236
+ promise.resolve(Luciq.isBuilt());
237
+ } catch (Exception e) {
238
+ e.printStackTrace();
239
+ promise.resolve(false);
240
+ }
241
+ }
242
+ });
243
+ }
244
+
225
245
  @ReactMethod
226
246
  public void setOverAirVersion(@Nullable final ReadableMap overAirVersion) {
227
247
  MainThreadHandler.runOnMainThread(new Runnable() {
@@ -0,0 +1,9 @@
1
+ export declare class LuciqStrings {
2
+ static readonly customSpanAPMDisabledMessage: string;
3
+ static readonly customSpanDisabled: string;
4
+ static readonly customSpanSDKNotInitializedMessage: string;
5
+ static readonly customSpanNameEmpty: string;
6
+ static readonly customSpanEndTimeBeforeStartTime: string;
7
+ static readonly customSpanNameTruncated: string;
8
+ static readonly customSpanLimitReached: string;
9
+ }
@@ -0,0 +1,12 @@
1
+ export class LuciqStrings {
2
+ static customSpanAPMDisabledMessage = 'APM is disabled, custom span not created. Please enable APM by following the instructions at this link:\n' +
3
+ 'https://docs.luciq.ai/product-guides-and-integrations/product-guides/application-performance-monitoring';
4
+ static customSpanDisabled = 'Custom span is disabled, custom span not created. Please enable Custom Span by following the instructions at this link:\n' +
5
+ 'https://docs.luciq.ai/product-guides-and-integrations/product-guides/application-performance-monitoring';
6
+ static customSpanSDKNotInitializedMessage = 'Luciq API was called before the SDK is built. To build it, first by following the instructions at this link:\n' +
7
+ 'https://docs.luciq.ai/product-guides-and-integrations/product-guides/application-performance-monitoring';
8
+ static customSpanNameEmpty = 'Custom span name cannot be empty. Please provide a valid name for the custom span.';
9
+ static customSpanEndTimeBeforeStartTime = 'Custom span end time must be after start time. Please provide a valid start and end time for the custom span.';
10
+ static customSpanNameTruncated = 'Custom span name truncated to 150 characters';
11
+ static customSpanLimitReached = 'Maximum number of concurrent custom spans (100) reached. Please end some spans before starting new ones.';
12
+ }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { LuciqConfig } from './models/LuciqConfig';
2
2
  import Report from './models/Report';
3
3
  import type { ThemeConfig } from './models/ThemeConfig';
4
+ import { CustomSpan } from './models/CustomSpan';
4
5
  import * as APM from './modules/APM';
5
6
  import * as BugReporting from './modules/BugReporting';
6
7
  import * as CrashReporting from './modules/CrashReporting';
@@ -15,6 +16,6 @@ import * as Surveys from './modules/Surveys';
15
16
  import * as SessionReplay from './modules/SessionReplay';
16
17
  import type { SessionMetadata } from './models/SessionMetadata';
17
18
  export * from './utils/Enums';
18
- export { Report, APM, BugReporting, CrashReporting, FeatureRequests, NetworkLogger, SessionReplay, Replies, Surveys, ProactiveReportingConfigOptions, createProactiveReportingConfig, };
19
+ export { Report, CustomSpan, APM, BugReporting, CrashReporting, FeatureRequests, NetworkLogger, SessionReplay, Replies, Surveys, ProactiveReportingConfigOptions, createProactiveReportingConfig, };
19
20
  export type { LuciqConfig, Survey, NetworkData, NetworkDataObfuscationHandler, SessionMetadata, ThemeConfig, };
20
21
  export default Luciq;
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import Report from './models/Report';
2
+ import { CustomSpan } from './models/CustomSpan';
2
3
  // Modules
3
4
  import * as APM from './modules/APM';
4
5
  import * as BugReporting from './modules/BugReporting';
@@ -11,5 +12,5 @@ import * as Replies from './modules/Replies';
11
12
  import * as Surveys from './modules/Surveys';
12
13
  import * as SessionReplay from './modules/SessionReplay';
13
14
  export * from './utils/Enums';
14
- export { Report, APM, BugReporting, CrashReporting, FeatureRequests, NetworkLogger, SessionReplay, Replies, Surveys, createProactiveReportingConfig, };
15
+ export { Report, CustomSpan, APM, BugReporting, CrashReporting, FeatureRequests, NetworkLogger, SessionReplay, Replies, Surveys, createProactiveReportingConfig, };
15
16
  export default Luciq;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Callback to unregister a span from tracking
3
+ */
4
+ type UnregisterCallback = (span: CustomSpan) => void;
5
+ /**
6
+ * Callback to sync span data to native SDK
7
+ */
8
+ type SyncCallback = (name: string, startTimestamp: number, endTimestamp: number) => Promise<void>;
9
+ /**
10
+ * Represents a custom span for performance tracking.
11
+ * A span measures the duration of an operation and reports it to the native SDK.
12
+ */
13
+ export declare class CustomSpan {
14
+ private name;
15
+ private startTime;
16
+ private startMonotonic;
17
+ private endTime?;
18
+ private duration?;
19
+ private hasEnded;
20
+ private endPromise?;
21
+ private unregisterCallback;
22
+ private syncCallback;
23
+ /**
24
+ * Creates a new custom span. The span starts immediately upon creation.
25
+ * @internal - Use APM.startCustomSpan() instead
26
+ */
27
+ constructor(name: string, unregisterCallback: UnregisterCallback, syncCallback: SyncCallback);
28
+ /**
29
+ * Ends this custom span and reports it to the native SDK.
30
+ * This method is idempotent - calling it multiple times is safe.
31
+ * Subsequent calls will wait for the first call to complete.
32
+ */
33
+ end(): Promise<void>;
34
+ /**
35
+ * Get the span name
36
+ */
37
+ getName(): string;
38
+ /**
39
+ * Check if the span has ended
40
+ */
41
+ isEnded(): boolean;
42
+ /**
43
+ * Get the span duration in milliseconds (only available after end())
44
+ */
45
+ getDuration(): number | undefined;
46
+ }
47
+ export {};