diff --git a/.circleci/config.yml b/.circleci/config.yml index d613bf7c0..c7b8d3110 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -459,7 +459,6 @@ workflows: - e2e_android - hold_generate_snapshot: type: approval - requires: *release_dependencies - generate_snapshot: requires: - hold_generate_snapshot diff --git a/.eslintrc.js b/.eslintrc.js index 8c4e480df..3fb76ef2a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,7 +1,7 @@ /** @type {import('eslint').ESLint.ConfigData} */ module.exports = { extends: '@react-native-community', - plugins: ['prettier', 'jest'], + plugins: ['prettier', 'jest', 'jsdoc'], overrides: [ { // Jest Overrides @@ -27,6 +27,7 @@ module.exports = { }, ], rules: { + 'jsdoc/no-undefined-types': 'warn', 'prettier/prettier': 'error', 'prefer-const': 'error', }, diff --git a/CHANGELOG.md b/CHANGELOG.md index fbaf6c339..1822ad6b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ - Adds symbol files upload script ([#1137](https://github.com/Instabug/Instabug-React-Native/pull/1137)) - Support enabling NDK crash capturing on Android ([#1132](https://github.com/Instabug/Instabug-React-Native/pull/1132)). +- Add support for App Flows APIs `APM.startFlow`, `APM.setFlowAttribute` and `APM.endFlow` ([#1138](https://github.com/Instabug/Instabug-React-Native/pull/1138)). + +### Deprecated + +- Deprecate Execution Traces APIs `APM.startExecutionTrace`, `Trace.end` and `Trace.setAttribute` in favor of the new App Flows APIs ([#1138](https://github.com/Instabug/Instabug-React-Native/pull/1138)). ### Changed diff --git a/android/native.gradle b/android/native.gradle index ed8e9c976..5256d4525 100644 --- a/android/native.gradle +++ b/android/native.gradle @@ -1,5 +1,5 @@ project.ext.instabug = [ - version: '12.9.0' + version: '12.9.0.5679473-SNAPSHOT' ] dependencies { diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabugAPMModule.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabugAPMModule.java index b594a13f9..d7662c653 100644 --- a/android/src/main/java/com/instabug/reactlibrary/RNInstabugAPMModule.java +++ b/android/src/main/java/com/instabug/reactlibrary/RNInstabugAPMModule.java @@ -4,6 +4,7 @@ import android.os.SystemClock; import android.util.Log; +import androidx.annotation.NonNull; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; @@ -29,6 +30,8 @@ public class RNInstabugAPMModule extends ReactContextBaseJavaModule { public RNInstabugAPMModule(ReactApplicationContext reactApplicationContext) { super(reactApplicationContext); } + + @Deprecated HashMap traces = new HashMap(); @Nonnull @@ -121,10 +124,92 @@ public void run() { }); } + /** + * Starts an AppFlow with the specified name. + *
+ * On starting two flows with the same name the older flow will end with force abandon end reason. + * AppFlow name cannot exceed 150 characters otherwise it's truncated, + * leading and trailing whitespaces are also ignored. + * + * @param name AppFlow name. It can not be empty string or null. + * Starts a new AppFlow, if APM is enabled, feature is enabled + * and Instabug SDK is initialised. + */ + @ReactMethod + public void startFlow(@NonNull final String name) { + MainThreadHandler.runOnMainThread(new Runnable() { + @Override + public void run() { + try { + APM.startFlow(name); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + /** + * Sets custom attributes for AppFlow with a given name. + *
+ * Setting an attribute value to null will remove its corresponding key if it already exists. + *
+ * Attribute key name cannot exceed 30 characters. + * Leading and trailing whitespaces are also ignored. + * Does not accept empty strings or null. + *
+ * Attribute value name cannot exceed 60 characters, + * leading and trailing whitespaces are also ignored. + * Does not accept empty strings. + *
+ * If a trace is ended, attributes will not be added and existing ones will not be updated. + *
+ * + * @param name AppFlow name. It can not be empty string or null + * @param key AppFlow attribute key. It can not be empty string or null + * @param value AppFlow attribute value. It can not be empty string. Null to remove attribute + */ + @ReactMethod + public void setFlowAttribute(@NonNull final String name, @NonNull final String key, final String value) { + MainThreadHandler.runOnMainThread(new Runnable() { + @Override + public void run() { + try { + APM.setFlowAttribute(name, key, value); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + /** + * Ends AppFlow with a given name. + * + * @param name AppFlow name to be ended. It can not be empty string or null + */ + @ReactMethod + public void endFlow(@NonNull final String name) { + MainThreadHandler.runOnMainThread(new Runnable() { + @Override + public void run() { + try { + APM.endFlow(name); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + /** * Starts an execution trace + * * @param name string name of the trace. + * + * @deprecated see {@link #startFlow(String)} */ + @Deprecated @ReactMethod public void startExecutionTrace(final String name, final String id, final Promise promise) { MainThreadHandler.runOnMainThread(new Runnable() { @@ -148,10 +233,14 @@ public void run() { /** * Adds a new attribute to trace - * @param id String id of the trace. + * + * @param id String id of the trace. * @param key attribute key * @param value attribute value. Null to remove attribute + * + * @deprecated see {@link #setFlowAttribute} */ + @Deprecated @ReactMethod public void setExecutionTraceAttribute(final String id, final String key, final String value) { MainThreadHandler.runOnMainThread(new Runnable() { @@ -168,8 +257,12 @@ public void run() { /** * Ends a trace + * * @param id string id of the trace. + * + * @deprecated see {@link #endFlow} */ + @Deprecated @ReactMethod public void endExecutionTrace(final String id) { MainThreadHandler.runOnMainThread(new Runnable() { diff --git a/android/src/test/java/com/instabug/reactlibrary/RNInstabugAPMModuleTest.java b/android/src/test/java/com/instabug/reactlibrary/RNInstabugAPMModuleTest.java index e43dbb129..5045f929e 100644 --- a/android/src/test/java/com/instabug/reactlibrary/RNInstabugAPMModuleTest.java +++ b/android/src/test/java/com/instabug/reactlibrary/RNInstabugAPMModuleTest.java @@ -125,6 +125,37 @@ public void givenTruesetEnabled_whenQuery_thenShouldCallNativeApiWithEnabled() { verify(promise).resolve(any()); } + @Test + public void testStartFlow() { + String appFlowName = "appFlowName"; + + apmModule.startFlow(appFlowName); + + mockAPM.verify(() -> APM.startFlow(appFlowName)); + mockAPM.verifyNoMoreInteractions(); + } + + @Test + public void testEndFlow() { + String appFlowName = "appFlowName"; + + apmModule.endFlow(appFlowName); + + mockAPM.verify(() -> APM.endFlow(appFlowName)); + mockAPM.verifyNoMoreInteractions(); + } + + @Test + public void testSetFlowAttribute() { + String appFlowName = "appFlowName"; + String flowAttributeKey = "attributeKey"; + String flowAttributeValue = "attributeValue"; + apmModule.setFlowAttribute(appFlowName, flowAttributeKey, flowAttributeValue); + + mockAPM.verify(() -> APM.setFlowAttribute(appFlowName, flowAttributeKey, flowAttributeValue)); + mockAPM.verifyNoMoreInteractions(); + } + // @Test // public void givenString$setExecutionTraceAttribute_whenQuery_thenShouldCallNativeApiWithIntArgs() { // // given diff --git a/examples/default/ios/InstabugTests/InstabugAPMTests.m b/examples/default/ios/InstabugTests/InstabugAPMTests.m index d476602c8..dd96841de 100644 --- a/examples/default/ios/InstabugTests/InstabugAPMTests.m +++ b/examples/default/ios/InstabugTests/InstabugAPMTests.m @@ -62,7 +62,7 @@ - (void) testSetAPMEnabled { - (void) testSetAppLaunchEnabled { id mock = OCMClassMock([IBGAPM class]); BOOL isEnabled = YES; - + OCMStub([mock setColdAppLaunchEnabled:isEnabled]); [self.instabugBridge setAppLaunchEnabled:isEnabled]; OCMVerify([mock setColdAppLaunchEnabled:isEnabled]); @@ -70,7 +70,7 @@ - (void) testSetAppLaunchEnabled { - (void) testEndAppLaunch { id mock = OCMClassMock([IBGAPM class]); - + OCMStub([mock endAppLaunch]); [self.instabugBridge endAppLaunch]; OCMVerify([mock endAppLaunch]); @@ -79,7 +79,7 @@ - (void) testEndAppLaunch { - (void) testSetAutoUITraceEnabled { id mock = OCMClassMock([IBGAPM class]); BOOL isEnabled = YES; - + OCMStub([mock setAutoUITraceEnabled:isEnabled]); [self.instabugBridge setAutoUITraceEnabled:isEnabled]; OCMVerify([mock setAutoUITraceEnabled:isEnabled]); @@ -91,7 +91,7 @@ - (void) testStartExecutionTrace { NSString* traceKey = @"1"; RCTPromiseResolveBlock resolve = ^(id result) {}; RCTPromiseRejectBlock reject = ^(NSString *code, NSString *message, NSError *error) {}; - + OCMStub([mock startExecutionTraceWithName:traceName]); [self.instabugBridge startExecutionTrace:traceName :traceKey :resolve :reject]; OCMVerify([mock startExecutionTraceWithName:traceName]); @@ -107,10 +107,10 @@ - (void) testSetExecutionTraceAttribute { IBGExecutionTrace * trace = [IBGExecutionTrace alloc]; id mock = OCMClassMock([IBGAPM class]); id traceMock = OCMPartialMock(trace); - + OCMStub([mock startExecutionTraceWithName:traceName]).andReturn(trace); [self.instabugBridge startExecutionTrace:traceName :traceId :resolve :reject]; - + OCMStub([traceMock setAttributeWithKey:traceKey value:traceValue]); [self.instabugBridge setExecutionTraceAttribute:traceId :traceKey :traceValue]; OCMVerify([traceMock setAttributeWithKey:traceKey value:traceValue]); @@ -127,16 +127,42 @@ - (void) testEndExecutionTrace { OCMStub([apmMock startExecutionTraceWithName:traceName]).andReturn(trace); [self.instabugBridge startExecutionTrace:traceName :traceId :resolve :reject]; - + OCMStub([traceMock end]); [self.instabugBridge endExecutionTrace:traceId]; OCMVerify([traceMock end]); } +- (void) testStartFlow { + id mock = OCMClassMock([IBGAPM class]); + NSString* appFlowName = @"APP_Flow_1"; + + [self.instabugBridge startFlow:appFlowName]; + OCMVerify([mock startFlowWithName:appFlowName]); +} + +- (void) testEndFlow { + id mock = OCMClassMock([IBGAPM class]); + NSString* appFlowName = @"APP_Flow_1"; + + [self.instabugBridge endFlow:appFlowName]; + OCMVerify([mock endFlowWithName:appFlowName]); +} + +- (void) testSetFlowAttribute { + id mock = OCMClassMock([IBGAPM class]); + NSString* appFlowName = @"APP_Flow_1"; + NSString* attributeKey = @"Attribute_Key_1"; + NSString* attributeValue = @"Attribute_Value_1"; + + [self.instabugBridge setFlowAttribute:appFlowName :attributeKey :attributeValue]; + OCMVerify([mock setAttributeForFlowWithName:appFlowName key:attributeKey value:attributeValue]); +} + - (void) testStartUITrace { id mock = OCMClassMock([IBGAPM class]); NSString* traceName = @"UITrace_1"; - + OCMStub([mock startUITraceWithName:traceName]); [self.instabugBridge startUITrace:traceName]; OCMVerify([mock startUITraceWithName:traceName]); @@ -144,7 +170,7 @@ - (void) testStartUITrace { - (void) testEndUITrace { id mock = OCMClassMock([IBGAPM class]); - + OCMStub([mock endUITrace]); [self.instabugBridge endUITrace]; OCMVerify([mock endUITrace]); diff --git a/examples/default/ios/Podfile b/examples/default/ios/Podfile index 7fa5129f9..1e7daea78 100644 --- a/examples/default/ios/Podfile +++ b/examples/default/ios/Podfile @@ -24,6 +24,7 @@ end target 'InstabugExample' do config = use_native_modules! + pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/feature-app-flow/12.9.2/Instabug.podspec' rn_maps_path = '../node_modules/react-native-maps' pod 'react-native-google-maps', :path => rn_maps_path # Flags change depending on the env values. diff --git a/examples/default/ios/Podfile.lock b/examples/default/ios/Podfile.lock index 47be69d3d..5e25b4b01 100644 --- a/examples/default/ios/Podfile.lock +++ b/examples/default/ios/Podfile.lock @@ -97,7 +97,7 @@ PODS: - hermes-engine (0.72.3): - hermes-engine/Pre-built (= 0.72.3) - hermes-engine/Pre-built (0.72.3) - - Instabug (12.9.0) + - Instabug (12.9.2) - instabug-reactnative-ndk (0.1.0): - RCT-Folly (= 2021.07.22.00) - React-Core @@ -404,6 +404,8 @@ PODS: - React-jsinspector (0.72.3) - React-logger (0.72.3): - glog + - react-native-background-timer (2.4.1): + - React-Core - react-native-config (1.5.1): - react-native-config/App (= 1.5.1) - react-native-config/App (1.5.1): @@ -528,11 +530,13 @@ PODS: - React-jsi (= 0.72.3) - React-logger (= 0.72.3) - React-perflogger (= 0.72.3) + - RNCClipboard (1.5.1): + - React-Core - RNGestureHandler (2.13.4): - RCT-Folly (= 2021.07.22.00) - React-Core - RNInstabug (12.9.0): - - Instabug (= 12.9.0) + - Instabug - React-Core - RNReanimated (3.5.4): - DoubleConversion @@ -602,6 +606,7 @@ DEPENDENCIES: - FlipperKit/SKIOSNetworkPlugin (= 0.182.0) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) + - Instabug (from `https://ios-releases.instabug.com/custom/feature-app-flow/12.9.2/Instabug.podspec`) - instabug-reactnative-ndk (from `../node_modules/instabug-reactnative-ndk`) - libevent (~> 2.1.12) - OCMock @@ -623,6 +628,7 @@ DEPENDENCIES: - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) - React-logger (from `../node_modules/react-native/ReactCommon/logger`) + - react-native-background-timer (from `../node_modules/react-native-background-timer`) - react-native-config (from `../node_modules/react-native-config`) - react-native-google-maps (from `../node_modules/react-native-maps`) - react-native-maps (from `../node_modules/react-native-maps`) @@ -645,6 +651,7 @@ DEPENDENCIES: - React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`) - React-utils (from `../node_modules/react-native/ReactCommon/react/utils`) - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - "RNCClipboard (from `../node_modules/@react-native-community/clipboard`)" - RNGestureHandler (from `../node_modules/react-native-gesture-handler`) - RNInstabug (from `../node_modules/instabug-reactnative`) - RNReanimated (from `../node_modules/react-native-reanimated`) @@ -667,7 +674,6 @@ SPEC REPOS: - fmt - Google-Maps-iOS-Utils - GoogleMaps - - Instabug - libevent - OCMock - OpenSSL-Universal @@ -688,6 +694,8 @@ EXTERNAL SOURCES: hermes-engine: :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" :tag: hermes-2023-03-20-RNv0.72.0-49794cfc7c81fb8f69fd60c3bbf85a7480cc5a77 + Instabug: + :podspec: https://ios-releases.instabug.com/custom/feature-app-flow/12.9.2/Instabug.podspec instabug-reactnative-ndk: :path: "../node_modules/instabug-reactnative-ndk" RCT-Folly: @@ -720,6 +728,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/jsinspector" React-logger: :path: "../node_modules/react-native/ReactCommon/logger" + react-native-background-timer: + :path: "../node_modules/react-native-background-timer" react-native-config: :path: "../node_modules/react-native-config" react-native-google-maps: @@ -764,6 +774,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/react/utils" ReactCommon: :path: "../node_modules/react-native/ReactCommon" + RNCClipboard: + :path: "../node_modules/@react-native-community/clipboard" RNGestureHandler: :path: "../node_modules/react-native-gesture-handler" RNInstabug: @@ -798,7 +810,7 @@ SPEC CHECKSUMS: Google-Maps-iOS-Utils: f77eab4c4326d7e6a277f8e23a0232402731913a GoogleMaps: 032f676450ba0779bd8ce16840690915f84e57ac hermes-engine: 10fbd3f62405c41ea07e71973ea61e1878d07322 - Instabug: 8d39aa5f98999f4c0081fcdb38998eb368923d1a + Instabug: ec894f6efb54c736b58a8c61f25e6f01631c41f7 instabug-reactnative-ndk: 960119a69380cf4cbe47ccd007c453f757927d17 libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 OCMock: 300b1b1b9155cb6378660b981c2557448830bdc6 @@ -818,6 +830,7 @@ SPEC CHECKSUMS: React-jsiexecutor: 59d1eb03af7d30b7d66589c410f13151271e8006 React-jsinspector: b511447170f561157547bc0bef3f169663860be7 React-logger: c5b527272d5f22eaa09bb3c3a690fee8f237ae95 + react-native-background-timer: 17ea5e06803401a379ebf1f20505b793ac44d0fe react-native-config: 86038147314e2e6d10ea9972022aa171e6b1d4d8 react-native-google-maps: 1bcc1f9f13f798fcf230db7fe476f3566d0bc0a3 react-native-maps: 72a8a903f8a1b53e2c777ba79102078ab502e0bf @@ -840,8 +853,9 @@ SPEC CHECKSUMS: React-runtimescheduler: 837c1bebd2f84572db17698cd702ceaf585b0d9a React-utils: bcb57da67eec2711f8b353f6e3d33bd8e4b2efa3 ReactCommon: 3ccb8fb14e6b3277e38c73b0ff5e4a1b8db017a9 + RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495 RNGestureHandler: 6e46dde1f87e5f018a54fe5d40cd0e0b942b49ee - RNInstabug: 620175f228d29f6ec394a598502cf501bd9beace + RNInstabug: 72d292b472202eb121e3bdfd5d18d4374ed1f833 RNReanimated: ab2e96c6d5591c3dfbb38a464f54c8d17fb34a87 RNScreens: b21dc57dfa2b710c30ec600786a3fc223b1b92e7 RNSVG: 80584470ff1ffc7994923ea135a3e5ad825546b9 @@ -850,6 +864,6 @@ SPEC CHECKSUMS: Yoga: 8796b55dba14d7004f980b54bcc9833ee45b28ce YogaKit: f782866e155069a2cca2517aafea43200b01fd5a -PODFILE CHECKSUM: ad82a989387dcdb1ce80667f16b998a2644cf0b2 +PODFILE CHECKSUM: 41fca103b48ef76c281ecf04ce7a6864f9c2572e -COCOAPODS: 1.12.0 +COCOAPODS: 1.15.2 diff --git a/examples/default/package.json b/examples/default/package.json index 5c6b173c1..529521802 100644 --- a/examples/default/package.json +++ b/examples/default/package.json @@ -10,14 +10,19 @@ "postinstall": "patch-package" }, "dependencies": { + "@react-native-community/clipboard": "^1.5.1", "@react-native-community/slider": "^4.4.3", "@react-navigation/bottom-tabs": "^6.5.7", "@react-navigation/native": "^6.1.6", "@react-navigation/native-stack": "^6.9.12", + "graphql": "^16.8.1", + "graphql-request": "^6.1.0", "instabug-reactnative": "link:../..", + "instabug-reactnative-ndk": "github:https://github.com/Instabug/Instabug-React-Native-NDK", "native-base": "^3.4.28", "react": "18.2.0", "react-native": "0.72.3", + "react-native-background-timer": "^2.4.1", "react-native-config": "^1.5.1", "react-native-gesture-handler": "^2.13.4", "react-native-maps": "^1.10.3", @@ -26,7 +31,7 @@ "react-native-screens": "^3.20.0", "react-native-svg": "^13.9.0", "react-native-vector-icons": "^10.0.0", - "instabug-reactnative-ndk": "github:https://github.com/Instabug/Instabug-React-Native-NDK" + "react-query": "^3.39.3" }, "devDependencies": { "@babel/core": "^7.20.0", @@ -35,6 +40,7 @@ "@react-native/metro-config": "^0.73.1", "@types/jest": "^29.2.1", "@types/react": "^18.0.24", + "@types/react-native-background-timer": "^2.0.2", "@types/react-native-vector-icons": "^6.4.13", "@types/react-test-renderer": "^18.0.0", "babel-jest": "^29.2.1", diff --git a/examples/default/src/App.tsx b/examples/default/src/App.tsx index 4bc144705..d92db633c 100644 --- a/examples/default/src/App.tsx +++ b/examples/default/src/App.tsx @@ -15,6 +15,10 @@ import { RootTabNavigator } from './navigation/RootTab'; import { nativeBaseTheme } from './theme/nativeBaseTheme'; import { navigationTheme } from './theme/navigationTheme'; +import { QueryClient, QueryClientProvider } from 'react-query'; + +const queryClient = new QueryClient(); + export const App: React.FC = () => { useEffect(() => { Instabug.init({ @@ -32,9 +36,11 @@ export const App: React.FC = () => { return ( - - - + + + + + ); diff --git a/examples/default/src/components/ClipboardTextInput.tsx b/examples/default/src/components/ClipboardTextInput.tsx new file mode 100644 index 000000000..05d9c35ec --- /dev/null +++ b/examples/default/src/components/ClipboardTextInput.tsx @@ -0,0 +1,36 @@ +import React, { PropsWithChildren } from 'react'; +import { StyleProp, StyleSheet, TextStyle } from 'react-native'; +import PasteFromClipboardButton from './PasteFromClipboardButton'; +import { HStack } from 'native-base'; +import { InputField } from './InputField'; + +interface ClipboardTextInputProps extends PropsWithChildren { + placeholder?: string; + onChangeText?: (text: string) => void; + value?: string; + selectTextOnFocus?: boolean; + style?: StyleProp; +} + +export const ClipboardTextInput: React.FC = ({ + onChangeText, + style, + ...restProps +}) => { + return ( + + + + + ); + + function handleClipboardPress(text: string) { + onChangeText?.call(undefined, text); + } +}; + +export const styles = StyleSheet.create({ + inputField: { + flex: 1, + }, +}); diff --git a/examples/default/src/components/CustomButton.tsx b/examples/default/src/components/CustomButton.tsx new file mode 100644 index 000000000..07bcf9798 --- /dev/null +++ b/examples/default/src/components/CustomButton.tsx @@ -0,0 +1,31 @@ +import React, { PropsWithChildren } from 'react'; +import type { StyleProp, TextStyle } from 'react-native'; +import { Button } from 'native-base'; +import { CustomText } from './CustomText'; +import { StyleSheet } from 'react-native'; + +interface CustomButtonProps extends PropsWithChildren { + title?: string; + onPress?: () => void; + style?: StyleProp; +} + +export const CustomButton: React.FC = ({ + style, + title, + children, + ...restProps +}) => { + return ( + + ); +}; + +export const styles = StyleSheet.create({ + text: { + color: '#fff', + }, +}); diff --git a/examples/default/src/components/CustomImage.tsx b/examples/default/src/components/CustomImage.tsx new file mode 100644 index 000000000..5c5d051eb --- /dev/null +++ b/examples/default/src/components/CustomImage.tsx @@ -0,0 +1,17 @@ +import React, { PropsWithChildren } from 'react'; +import { StyleProp, StyleSheet, TextStyle, Text } from 'react-native'; + +interface CustomTextProps extends PropsWithChildren { + style?: StyleProp; +} + +export const CustomImage: React.FC = ({ style, children }) => { + return {children}; +}; + +export const styles = StyleSheet.create({ + text: { + fontSize: 16, + lineHeight: 24, + }, +}); diff --git a/examples/default/src/components/CustomText.tsx b/examples/default/src/components/CustomText.tsx new file mode 100644 index 000000000..5e3622128 --- /dev/null +++ b/examples/default/src/components/CustomText.tsx @@ -0,0 +1,17 @@ +import React, { PropsWithChildren } from 'react'; +import { StyleProp, StyleSheet, TextStyle, Text } from 'react-native'; + +interface CustomTextProps extends PropsWithChildren { + style?: StyleProp; +} + +export const CustomText: React.FC = ({ style, children }) => { + return {children}; +}; + +export const styles = StyleSheet.create({ + text: { + fontSize: 16, + lineHeight: 24, + }, +}); diff --git a/examples/default/src/components/InputField.tsx b/examples/default/src/components/InputField.tsx index 1a5700c27..feef8fd7b 100644 --- a/examples/default/src/components/InputField.tsx +++ b/examples/default/src/components/InputField.tsx @@ -1,13 +1,22 @@ import React, { forwardRef } from 'react'; -import { KeyboardTypeOptions, StyleSheet, TextInput, View } from 'react-native'; +import { + KeyboardTypeOptions, + StyleProp, + StyleSheet, + TextInput, + ViewStyle, + View, +} from 'react-native'; import { Text } from 'native-base'; interface InputFieldProps { placeholder?: string; value?: string; + style?: StyleProp; onChangeText?: (text: string) => void; keyboardType?: KeyboardTypeOptions; + selectTextOnFocus?: boolean | undefined; errorText?: string; maxLength?: number; accessibilityLabel?: string; @@ -19,6 +28,7 @@ export const InputField = forwardRef( { placeholder, value, + style, onChangeText, accessibilityLabel, maxLength, @@ -33,7 +43,7 @@ export const InputField = forwardRef( void; + style?: StyleProp; +} + +const PasteFromClipboardButton: React.FC = ({ onPress, style }) => { + const handlePress = async () => { + const text = await Clipboard.getString(); + onPress?.call(undefined, text); // Using call to pass the text to the callback + }; + + return ( + + + + ); +}; + +export default PasteFromClipboardButton; diff --git a/examples/default/src/navigation/HomeStack.tsx b/examples/default/src/navigation/HomeStack.tsx index 184e36f03..b4a8ca3e6 100644 --- a/examples/default/src/navigation/HomeStack.tsx +++ b/examples/default/src/navigation/HomeStack.tsx @@ -21,6 +21,10 @@ import { } from '../screens/user-steps/BackAndForthScreen'; import { GoogleMapsScreen } from '../screens/user-steps/GoogleMapsScreen'; import { LargeImageListScreen } from '../screens/user-steps/LargeImageListScreen'; +import { APMScreen } from '../screens/apm/APMScreen'; +import { TracesScreen } from '../screens/apm/TracesScreen'; +import { NetworkScreen } from '../screens/apm/NetworkScreen'; +import { FlowsScreen } from '../screens/apm/FlowsScreen'; import { SessionReplayScreen } from '../screens/SessionReplayScreen'; export type HomeStackParamList = { @@ -41,6 +45,12 @@ export type HomeStackParamList = { LargeImageList: undefined; SessionReplay: undefined; BackAndForthScreen: BackAndForthScreenProp; + + // APM // + APM: undefined; + NetworkTraces: undefined; + ExecutionTraces: undefined; + AppFlows: undefined; }; const HomeStack = createNativeStackNavigator(); @@ -65,7 +75,6 @@ export const HomeStackNavigator: React.FC = () => { options={{ title: 'Feature Requests' }} /> - { options={{ title: 'Large Image List' }} /> + + + + ); }; diff --git a/examples/default/src/screens/HomeScreen.tsx b/examples/default/src/screens/HomeScreen.tsx index 086dc0650..690d41cc2 100644 --- a/examples/default/src/screens/HomeScreen.tsx +++ b/examples/default/src/screens/HomeScreen.tsx @@ -17,6 +17,7 @@ export const HomeScreen: React.FC navigation.navigate('Replies')} /> navigation.navigate('Surveys')} /> navigation.navigate('UserSteps')} /> + navigation.navigate('APM')} /> navigation.navigate('SessionReplay')} /> ); diff --git a/examples/default/src/screens/apm/APMScreen.tsx b/examples/default/src/screens/apm/APMScreen.tsx new file mode 100644 index 000000000..2bc4dbca0 --- /dev/null +++ b/examples/default/src/screens/apm/APMScreen.tsx @@ -0,0 +1,17 @@ +import type { NativeStackScreenProps } from '@react-navigation/native-stack'; +import type { HomeStackParamList } from '../../navigation/HomeStack'; +import React from 'react'; +import { ListTile } from '../../components/ListTile'; +import { Screen } from '../../components/Screen'; + +export const APMScreen: React.FC> = ({ + navigation, +}) => { + return ( + + navigation.navigate('NetworkTraces')} /> + navigation.navigate('ExecutionTraces')} /> + navigation.navigate('AppFlows')} /> + + ); +}; diff --git a/examples/default/src/screens/apm/FlowsScreen.tsx b/examples/default/src/screens/apm/FlowsScreen.tsx new file mode 100644 index 000000000..be9b0fec7 --- /dev/null +++ b/examples/default/src/screens/apm/FlowsScreen.tsx @@ -0,0 +1,63 @@ +import React, { useState } from 'react'; +import { APM } from 'instabug-reactnative'; +import { ScrollView } from 'react-native'; +import { Section } from '../../components/Section'; +import { Screen } from '../../components/Screen'; +import { VStack } from 'native-base'; +import { InputField } from '../../components/InputField'; +import { CustomButton } from '../../components/CustomButton'; +import BackgroundTimer from 'react-native-background-timer'; + +export const FlowsScreen: React.FC = () => { + const [flowName, setFlowName] = useState(''); + const [flowAttributeKey, setFlowAttributeKey] = useState(''); + const [flowAttributeValue, setFlowAttributeValue] = useState(''); + + async function startFlow() { + return APM.startFlow(flowName); + } + + async function startDelayedFlow() { + return BackgroundTimer.setTimeout(() => { + APM.startFlow(flowName); + }, 5000); + } + + function setFlowAttribute() { + return APM.setFlowAttribute(flowName, flowAttributeKey, flowAttributeValue); + } + + function endFlow() { + APM.endFlow(flowName); + } + + return ( + + +
+ + setFlowName(text)} + value={flowName} + /> + + + setFlowAttributeKey(text)} + value={flowAttributeKey} + /> + setFlowAttributeValue(text)} + value={flowAttributeValue} + /> + + + +
+
+
+ ); +}; diff --git a/examples/default/src/screens/apm/NetworkScreen.tsx b/examples/default/src/screens/apm/NetworkScreen.tsx new file mode 100644 index 000000000..467a621f2 --- /dev/null +++ b/examples/default/src/screens/apm/NetworkScreen.tsx @@ -0,0 +1,110 @@ +import React, { useState } from 'react'; +import { Image, ScrollView, StyleSheet, Text, useWindowDimensions, View } from 'react-native'; +import { Section } from '../../components/Section'; +import { Screen } from '../../components/Screen'; +import { ClipboardTextInput } from '../../components/ClipboardTextInput'; +import { useQuery } from 'react-query'; +import { HStack, VStack } from 'native-base'; +import { gql, request } from 'graphql-request'; +import { CustomButton } from '../../components/CustomButton'; + +export const NetworkScreen: React.FC = () => { + const [endpointUrl, setEndpointUrl] = useState(''); + const { width, height } = useWindowDimensions(); + const defaultRequestUrl = 'https://jsonplaceholder.typicode.com/posts/1'; + const imageUrls = [ + 'https://fastly.picsum.photos/id/57/200/300.jpg?hmac=l908G1qVr4r7dP947-tak2mY8Vvic_vEYzCXUCKKskY', + 'https://fastly.picsum.photos/id/619/200/300.jpg?hmac=WqBGwlGjuY9RCdpzRaG9G-rc9Fi7TGUINX_-klAL2kA', + ]; + + async function sendRequestToUrl() { + let urlToSend = ''; + + if (endpointUrl.trim() !== '') { + urlToSend = endpointUrl; + console.log('Sending request to: ', endpointUrl); + } else { + // Use json placeholder URL as a default if endpointUrl is empty + console.log('sending request to default json placeholder'); + urlToSend = defaultRequestUrl; + } + + try { + // Perform the request using the urlToSend + const response = await fetch(urlToSend); + const data = await response.json(); + + // Format the JSON response for better logging + const formattedData = JSON.stringify(data, null, 2); + + // Log the formatted response + console.log('Response:', formattedData); + } catch (error) { + // Handle errors appropriately + console.error('Error:', error); + } + } + + const fetchGraphQlData = async () => { + const document = gql` + query { + country(code: "EG") { + emoji + name + } + } + `; + + return request<{ country: { emoji: string; name: string } }>( + 'https://countries.trevorblades.com/graphql', + document, + ); + }; + + const { data, isError, isSuccess, isLoading, refetch } = useQuery('helloQuery', fetchGraphQlData); + + return ( + + +
+ + setEndpointUrl(text)} + selectTextOnFocus={true} + value={endpointUrl} + /> + + refetch} title="Reload GraphQL" /> + + {isLoading && Loading...} + {isSuccess && GraphQL Data: {data.country.emoji}} + {isError && Error!} + + +
+
+ + {imageUrls.map((imageUrl) => ( + + ))} + +
+
+
+ ); +}; +const styles = StyleSheet.create({ + image: { + resizeMode: 'contain', + }, + // Todo: Text Component + // Todo: Button Component + // Todo: Image Component +}); diff --git a/examples/default/src/screens/apm/TracesScreen.tsx b/examples/default/src/screens/apm/TracesScreen.tsx new file mode 100644 index 000000000..bd3e41838 --- /dev/null +++ b/examples/default/src/screens/apm/TracesScreen.tsx @@ -0,0 +1,70 @@ +import React, { useState } from 'react'; +import { APM, Trace } from 'instabug-reactnative'; +import { ScrollView } from 'react-native'; +import { Section } from '../../components/Section'; +import { Screen } from '../../components/Screen'; +import { VStack } from 'native-base'; +import { InputField } from '../../components/InputField'; +import { CustomButton } from '../../components/CustomButton'; +import BackgroundTimer from 'react-native-background-timer'; + +export const TracesScreen: React.FC = () => { + const [traceName, setTraceName] = useState(''); + const [traceAttributeKey, setTraceAttributeKey] = useState(''); + const [traceAttributeValue, setTraceAttributeValue] = useState(''); + let executionTrace: Trace; + + async function startTrace() { + executionTrace = await APM.startExecutionTrace(traceName ?? ''); + } + + async function startDelayedTrace() { + return BackgroundTimer.setTimeout(async () => { + executionTrace = await APM.startExecutionTrace(traceName ?? ''); + }, 5000); + } + + function setTraceAttribute() { + if (!executionTrace) { + console.log('Please, start a trace before setting attributes.'); + } + return executionTrace.setAttribute(traceAttributeKey ?? '', traceAttributeValue ?? ''); + } + + function endExecutionTrace() { + if (!executionTrace) { + console.log('Please, start a trace before ending it.'); + } + return executionTrace.end(); + } + + return ( + + +
+ + setTraceName(text)} + value={traceName} + /> + + + setTraceAttributeKey(text)} + value={traceAttributeKey} + /> + setTraceAttributeValue(text)} + value={traceAttributeValue} + /> + + + +
+
+
+ ); +}; diff --git a/examples/default/yarn.lock b/examples/default/yarn.lock index 546abe80f..286d15893 100644 --- a/examples/default/yarn.lock +++ b/examples/default/yarn.lock @@ -1209,6 +1209,13 @@ dependencies: regenerator-runtime "^0.13.11" +"@babel/runtime@^7.23.8", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2": + version "7.23.9" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz#47791a15e4603bb5f905bc0753801cf21d6345f7" + integrity sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.0.0", "@babel/template@^7.22.5", "@babel/template@^7.3.3": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec" @@ -1303,6 +1310,11 @@ dependencies: tslib "^2.4.0" +"@graphql-typed-document-node/core@^3.2.0": + version "3.2.0" + resolved "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" + integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== + "@hapi/hoek@^9.0.0": version "9.3.0" resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" @@ -2198,6 +2210,11 @@ prompts "^2.4.0" semver "^6.3.0" +"@react-native-community/clipboard@^1.5.1": + version "1.5.1" + resolved "https://registry.npmjs.org/@react-native-community/clipboard/-/clipboard-1.5.1.tgz#32abb3ea2eb91ee3f9c5fb1d32d5783253c9fabe" + integrity sha512-AHAmrkLEH5UtPaDiRqoULERHh3oNv7Dgs0bTC0hO5Z2GdNokAMPT5w8ci8aMcRemcwbtdHjxChgtjbeA38GBdA== + "@react-native-community/slider@^4.4.3": version "4.4.3" resolved "https://registry.yarnpkg.com/@react-native-community/slider/-/slider-4.4.3.tgz#9b9dc639b88f5bfda72bd72a9dff55cbf9f777ed" @@ -2903,6 +2920,11 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== +"@types/react-native-background-timer@^2.0.2": + version "2.0.2" + resolved "https://registry.npmjs.org/@types/react-native-background-timer/-/react-native-background-timer-2.0.2.tgz#22f9126124068a0ee6a812e16f98e270c2b9b2c7" + integrity sha512-cMAep0M5yqUHjiiRPvGiviqiJYdI45KSjbI5ufsIFSQGFwHwrHJC/8yawNhy0G3Gix6fufWLsEj6jC5niUNHiQ== + "@types/react-native-vector-icons@^6.4.13": version "6.4.13" resolved "https://registry.yarnpkg.com/@types/react-native-vector-icons/-/react-native-vector-icons-6.4.13.tgz#28b34d15094e040718beefb67cb3eff0c4994cb6" @@ -3251,6 +3273,11 @@ base64-js@^1.1.2, base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +big-integer@^1.6.16: + version "1.6.52" + resolved "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85" + integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg== + bl@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" @@ -3292,6 +3319,20 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" +broadcast-channel@^3.4.1: + version "3.7.0" + resolved "https://registry.npmjs.org/broadcast-channel/-/broadcast-channel-3.7.0.tgz#2dfa5c7b4289547ac3f6705f9c00af8723889937" + integrity sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg== + dependencies: + "@babel/runtime" "^7.7.2" + detect-node "^2.1.0" + js-sha3 "0.8.0" + microseconds "0.2.0" + nano-time "1.0.0" + oblivious-set "1.0.0" + rimraf "3.0.2" + unload "2.2.0" + browser-process-hrtime@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" @@ -3665,6 +3706,13 @@ cosmiconfig@^5.0.5, cosmiconfig@^5.1.0: js-yaml "^3.13.1" parse-json "^4.0.0" +cross-fetch@^3.1.5: + version "3.1.8" + resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82" + integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg== + dependencies: + node-fetch "^2.6.12" + cross-spawn@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41" @@ -3807,6 +3855,11 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== +detect-node@^2.0.4, detect-node@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + detox@^20.9.0: version "20.11.2" resolved "https://registry.yarnpkg.com/detox/-/detox-20.11.2.tgz#7628ad7909b343069e164fbada428ac12464eb67" @@ -4300,6 +4353,19 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.2.0, resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== +graphql-request@^6.1.0: + version "6.1.0" + resolved "https://registry.npmjs.org/graphql-request/-/graphql-request-6.1.0.tgz#f4eb2107967af3c7a5907eb3131c671eac89be4f" + integrity sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw== + dependencies: + "@graphql-typed-document-node/core" "^3.2.0" + cross-fetch "^3.1.5" + +graphql@^16.8.1: + version "16.8.1" + resolved "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz#1930a965bef1170603702acdb68aedd3f3cf6f07" + integrity sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -5066,6 +5132,11 @@ js-queue@2.0.2: dependencies: easy-stack "^1.0.1" +js-sha3@0.8.0: + version "0.8.0" + resolved "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -5382,6 +5453,14 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" +match-sorter@^6.0.2: + version "6.3.4" + resolved "https://registry.npmjs.org/match-sorter/-/match-sorter-6.3.4.tgz#afa779d8e922c81971fbcb4781c7003ace781be7" + integrity sha512-jfZW7cWS5y/1xswZo8VBOdudUiSd9nifYRWphc9M5D/ee4w4AoXLgBEdRbgVaxbMuagBPeUC5y2Hi8DO6o9aDg== + dependencies: + "@babel/runtime" "^7.23.8" + remove-accents "0.5.0" + mdn-data@2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" @@ -5902,6 +5981,11 @@ micromatch@^4.0.2, micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" +microseconds@0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39" + integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA== + mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" @@ -6002,6 +6086,13 @@ nan@^2.14.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== +nano-time@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef" + integrity sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA== + dependencies: + big-integer "^1.6.16" + nanoid@^3.1.23: version "3.3.6" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" @@ -6092,6 +6183,13 @@ node-fetch@^2.2.0, node-fetch@^2.6.0: dependencies: whatwg-url "^5.0.0" +node-fetch@^2.6.12: + version "2.7.0" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -6165,6 +6263,11 @@ object-keys@^1.1.1: resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== +oblivious-set@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566" + integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw== + on-finished@2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" @@ -6512,6 +6615,11 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== +react-native-background-timer@^2.4.1: + version "2.4.1" + resolved "https://registry.npmjs.org/react-native-background-timer/-/react-native-background-timer-2.4.1.tgz#a3bc1cafa8c1e3aeefd0611de120298b67978a0f" + integrity sha512-TE4Kiy7jUyv+hugxDxitzu38sW1NqjCk4uE5IgU2WevLv7sZacaBc6PZKOShNRPGirLl1NWkaG3LDEkdb9Um5g== + react-native-config@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/react-native-config/-/react-native-config-1.5.1.tgz#73c94f511493e9b7ff9350cdf351d203a1b05acc" @@ -6616,6 +6724,15 @@ react-native@0.72.3: ws "^6.2.2" yargs "^17.6.2" +react-query@^3.39.3: + version "3.39.3" + resolved "https://registry.npmjs.org/react-query/-/react-query-3.39.3.tgz#4cea7127c6c26bdea2de5fb63e51044330b03f35" + integrity sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g== + dependencies: + "@babel/runtime" "^7.5.5" + broadcast-channel "^3.4.1" + match-sorter "^6.0.2" + react-refresh@^0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e" @@ -6704,6 +6821,11 @@ regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.2: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + regenerator-transform@^0.15.1: version "0.15.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.1.tgz#f6c4e99fc1b4591f780db2586328e4d9a9d8dc56" @@ -6730,6 +6852,11 @@ regjsparser@^0.9.1: dependencies: jsesc "~0.5.0" +remove-accents@0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz#77991f37ba212afba162e375b627631315bed687" + integrity sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A== + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -6789,6 +6916,13 @@ retry@^0.12.0: resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== +rimraf@3.0.2, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + rimraf@^2.6.3: version "2.7.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -6796,13 +6930,6 @@ rimraf@^2.6.3: dependencies: glob "^7.1.3" -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - rimraf@~2.4.0: version "2.4.5" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.4.5.tgz#ee710ce5d93a8fdb856fb5ea8ff0e2d75934b2da" @@ -7376,6 +7503,14 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== +unload@2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7" + integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA== + dependencies: + "@babel/runtime" "^7.6.2" + detect-node "^2.0.4" + unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" diff --git a/ios/RNInstabug/InstabugAPMBridge.h b/ios/RNInstabug/InstabugAPMBridge.h index 30dec6a84..b15788d50 100644 --- a/ios/RNInstabug/InstabugAPMBridge.h +++ b/ios/RNInstabug/InstabugAPMBridge.h @@ -17,10 +17,13 @@ - (void)setAutoUITraceEnabled:(BOOL)isEnabled; - (void)startExecutionTrace:(NSString *)name :(NSString *)id :(RCTPromiseResolveBlock)resolve - :(RCTPromiseRejectBlock)reject; + :(RCTPromiseRejectBlock)reject DEPRECATED_MSG_ATTRIBUTE("Please use APM.startFlow instead."); - (void)setExecutionTraceAttribute:(NSString *)id:(NSString *)key - :(NSString *)value; -- (void)endExecutionTrace:(NSString *)id; + :(NSString *)value DEPRECATED_MSG_ATTRIBUTE("Please use APM.setTraceAttribute instead."); +- (void)endExecutionTrace:(NSString *)id DEPRECATED_MSG_ATTRIBUTE("Please use APM.endFlow instead."); +- (void)startFlow:(NSString *)name; +- (void)endFlow:(NSString *)name; +- (void)setFlowAttribute:(NSString *)name :(NSString *)key :(NSString *_Nullable)value; - (void)startUITrace:(NSString *)name; - (void)endUITrace; diff --git a/ios/RNInstabug/InstabugAPMBridge.m b/ios/RNInstabug/InstabugAPMBridge.m index f72e029d7..0324be4a8 100644 --- a/ios/RNInstabug/InstabugAPMBridge.m +++ b/ios/RNInstabug/InstabugAPMBridge.m @@ -88,6 +88,19 @@ - (id) init } } +RCT_EXPORT_METHOD(startFlow: (NSString *)name) { + [IBGAPM startFlowWithName:name]; +} + +RCT_EXPORT_METHOD(endFlow: (NSString *)name) { + [IBGAPM endFlowWithName:name]; +} + + +RCT_EXPORT_METHOD(setFlowAttribute:(NSString *)name :(NSString *)key :(NSString *_Nullable)value) { + [IBGAPM setAttributeForFlowWithName:name key:key value:value]; +} + RCT_EXPORT_METHOD(startUITrace:(NSString *)name) { [IBGAPM startUITraceWithName:name]; } diff --git a/ios/native.rb b/ios/native.rb index c2fc6bb97..d215d2b6e 100644 --- a/ios/native.rb +++ b/ios/native.rb @@ -1,4 +1,4 @@ -$instabug = { :version => '12.9.0' } +$instabug = { :version => '12.9.2' } def use_instabug! (spec = nil) version = $instabug[:version] @@ -6,7 +6,7 @@ def use_instabug! (spec = nil) if (!spec) pod 'Instabug', version else - spec.dependency 'Instabug', version + spec.dependency 'Instabug' end $instabug diff --git a/package.json b/package.json index c3824f320..c48a5b596 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "commander": "^11.0.0", "danger": "^11.2.5", "eslint": "^8.24.0", + "eslint-plugin-jsdoc": "^48.1.0", "eslint-plugin-prettier": "^5.0.0", "esprima": "^4.0.1", "form-data": "^4.0.0", diff --git a/src/models/Trace.ts b/src/models/Trace.ts index 6baa5aec2..19cd26d58 100644 --- a/src/models/Trace.ts +++ b/src/models/Trace.ts @@ -1,4 +1,5 @@ import { NativeAPM } from '../native/NativeAPM'; +import type * as APM from '../modules/APM'; export default class Trace { constructor( @@ -8,9 +9,12 @@ export default class Trace { ) {} /** - * Add an attribute with key and value to the Trace to be sent. - * @param key - * @param value + * Adds an attribute with a specified key and value to the Trace to be sent. + * + * @param key - The key of the attribute. + * @param value - The value of the attribute. + * + * @deprecated Please migrate to the App Flows APIs: {@link APM.startFlow}, {@link APM.endFlow}, and {@link APM.setFlowAttribute}. */ setAttribute(key: string, value: string) { NativeAPM.setExecutionTraceAttribute(this.id, key, value); @@ -18,8 +22,11 @@ export default class Trace { } /** - * End Execution Trace + * Ends the execution trace. + * + * @deprecated Please migrate to the App Flows APIs: {@link APM.startFlow}, {@link APM.endFlow}, and {@link APM.setFlowAttribute}. */ + end() { NativeAPM.endExecutionTrace(this.id); } diff --git a/src/modules/APM.ts b/src/modules/APM.ts index 44c5b4552..664f4473c 100644 --- a/src/modules/APM.ts +++ b/src/modules/APM.ts @@ -46,9 +46,14 @@ export const setAutoUITraceEnabled = (isEnabled: boolean) => { }; /** - * Starts a custom trace - * Returns a promise, the promise delivers the trace reference if APM is enabled, otherwise it gets rejected - * @param name + * Starts a custom execution trace. + * + * Returns a promise which resolves with the trace reference if APM is enabled; otherwise, the promise is rejected. + * + * @param name - The name of the trace to start. + * @returns A promise that resolves with a Trace object. + * + * @deprecated Please migrate to the App Flows APIs: {@link startFlow}, {@link endFlow}, and {@link setFlowAttribute}. */ export const startExecutionTrace = async (name: string): Promise => { const TRACE_NOT_STARTED_APM_NOT_ENABLED = `Execution trace "${name}" wasn't created. Please make sure to enable APM first by following the instructions at this link: https://docs.instabug.com/reference#enable-or-disable-apm`; @@ -63,6 +68,51 @@ export const startExecutionTrace = async (name: string): Promise => { return new Trace(id, name); }; +/** + * Starts an AppFlow with the specified name. + * + * On starting two flows with the same name, the older flow will end with a force abandon end reason. + * The AppFlow name cannot exceed 150 characters; otherwise, it's truncated, + * leading and trailing whitespaces are also ignored. + * + * @param name - The name of the AppFlow. It cannot be an empty string or null. + * A new AppFlow is started if APM is enabled, the feature is enabled, + * and the Instabug SDK is initialized. + */ +export const startFlow = (name: string) => { + NativeAPM.startFlow(name); +}; + +/** + * Ends an AppFlow with the given name. + * + * @param name - The name of the AppFlow to end. It cannot be an empty string or null. + */ +export const endFlow = (name: string) => { + NativeAPM.endFlow(name); +}; + +/** + * Sets custom attributes for an AppFlow with a given name. + * + * Setting an attribute value to null will remove the corresponding key if it already exists. + * Attribute keys cannot exceed 30 characters and leading/trailing whitespaces are ignored. + * Empty strings or null for attribute keys are not accepted. + * + * Attribute values cannot exceed 60 characters and leading/trailing whitespaces are ignored. + * Empty strings for attribute values are not accepted, but null can be used to remove an attribute. + * + * If an AppFlow is ended, attributes will not be added and existing ones will not be updated. + * + * @param name - The name of the AppFlow. It cannot be an empty string or null. + * @param key - The key of the attribute. It cannot be an empty string or null. + * @param [value] - The value of the attribute. It cannot be an empty string. Use null to remove the attribute. + */ + +export const setFlowAttribute = (name: string, key: string, value?: string | null) => { + NativeAPM.setFlowAttribute(name, key, value); +}; + /** * Starts a custom trace * @param name diff --git a/src/native/NativeAPM.ts b/src/native/NativeAPM.ts index 26ba21e03..2c2121587 100644 --- a/src/native/NativeAPM.ts +++ b/src/native/NativeAPM.ts @@ -18,6 +18,11 @@ export interface ApmNativeModule extends NativeModule { setExecutionTraceAttribute(id: string, key: string, value: string): void; endExecutionTrace(id: string): void; + // App Flows APIs // + startFlow(name: string): void; + endFlow(name: string): void; + setFlowAttribute(name: string, key: string, value?: string | null): void; + // UI Traces APIs // setAutoUITraceEnabled(isEnabled: boolean): void; startUITrace(name: string): void; diff --git a/test/mocks/mockAPM.ts b/test/mocks/mockAPM.ts index 77997be86..ca9dd297d 100644 --- a/test/mocks/mockAPM.ts +++ b/test/mocks/mockAPM.ts @@ -9,6 +9,9 @@ const mockAPM: ApmNativeModule = { startExecutionTrace: jest.fn(), setExecutionTraceAttribute: jest.fn(), endExecutionTrace: jest.fn(), + startFlow: jest.fn(), + setFlowAttribute: jest.fn(), + endFlow: jest.fn(), startUITrace: jest.fn(), endUITrace: jest.fn(), endAppLaunch: jest.fn(), diff --git a/test/modules/APM.spec.ts b/test/modules/APM.spec.ts index d416bcf93..d11cadf32 100644 --- a/test/modules/APM.spec.ts +++ b/test/modules/APM.spec.ts @@ -103,6 +103,39 @@ describe('APM Module', () => { }); }); + it('should call the native method startFlow', () => { + const appFlowName = 'flowName'; + + APM.startFlow(appFlowName); + + expect(NativeAPM.startFlow).toBeCalledTimes(1); + expect(NativeAPM.startFlow).toBeCalledWith(appFlowName); + }); + + it('should call the native method setFlowAttributes', () => { + const appFlowName = 'flowName'; + const flowAttributeKey = 'attributeKey'; + const flowAttributeValue = 'attributeValue'; + + APM.setFlowAttribute(appFlowName, flowAttributeKey, flowAttributeValue); + + expect(NativeAPM.setFlowAttribute).toBeCalledTimes(1); + expect(NativeAPM.setFlowAttribute).toBeCalledWith( + appFlowName, + flowAttributeKey, + flowAttributeValue, + ); + }); + + it('should call the native method endFlow', () => { + const appFlowName = 'flowName'; + + APM.endFlow(appFlowName); + + expect(NativeAPM.endFlow).toBeCalledTimes(1); + expect(NativeAPM.endFlow).toBeCalledWith(appFlowName); + }); + it('should call the native method startUITrace', () => { APM.startUITrace('uiTrace'); diff --git a/yarn.lock b/yarn.lock index 0d64f1d6e..a7cc47ffa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -814,6 +814,15 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@es-joy/jsdoccomment@~0.42.0": + version "0.42.0" + resolved "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.42.0.tgz#59e878708336aaee88c2b34c894f73dbf77ae2b0" + integrity sha512-R1w57YlVA6+YE01wch3GPYn6bCsrOV3YW/5oGGE2tmX6JcL9Nr+b5IikrjMPF+v9CV3ay+obImEdsDhovhJrzw== + dependencies: + comment-parser "1.4.1" + esquery "^1.5.0" + jsdoc-type-pratt-parser "~4.0.0" + "@eslint-community/eslint-utils@^4.2.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -2128,6 +2137,11 @@ appdirsjs@^1.2.4: resolved "https://registry.yarnpkg.com/appdirsjs/-/appdirsjs-1.2.7.tgz#50b4b7948a26ba6090d4aede2ae2dc2b051be3b3" integrity sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw== +are-docs-informative@^0.0.2: + version "0.0.2" + resolved "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz#387f0e93f5d45280373d387a59d34c96db321963" + integrity sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig== + argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -2740,6 +2754,11 @@ commander@~2.13.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" integrity sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA== +comment-parser@1.4.1: + version "1.4.1" + resolved "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz#bdafead37961ac079be11eb7ec65c4d021eaf9cc" + integrity sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg== + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -3222,6 +3241,21 @@ eslint-plugin-jest@^26.5.3: dependencies: "@typescript-eslint/utils" "^5.10.0" +eslint-plugin-jsdoc@^48.1.0: + version "48.1.0" + resolved "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.1.0.tgz#565363770b433485bfc70dc862b50b7f780529ec" + integrity sha512-g9S8ukmTd1DVcV/xeBYPPXOZ6rc8WJ4yi0+MVxJ1jBOrz5kmxV9gJJQ64ltCqIWFnBChLIhLVx3tbTSarqVyFA== + dependencies: + "@es-joy/jsdoccomment" "~0.42.0" + are-docs-informative "^0.0.2" + comment-parser "1.4.1" + debug "^4.3.4" + escape-string-regexp "^4.0.0" + esquery "^1.5.0" + is-builtin-module "^3.2.1" + semver "^7.6.0" + spdx-expression-parse "^4.0.0" + eslint-plugin-prettier@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b" @@ -3359,7 +3393,7 @@ esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.2: +esquery@^1.4.2, esquery@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== @@ -4861,6 +4895,11 @@ jscodeshift@^0.14.0: temp "^0.8.4" write-file-atomic "^2.3.0" +jsdoc-type-pratt-parser@~4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz#136f0571a99c184d84ec84662c45c29ceff71114" + integrity sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ== + jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" @@ -6593,6 +6632,13 @@ semver@^7.3.7, semver@^7.3.8, semver@^7.5.3: dependencies: lru-cache "^6.0.0" +semver@^7.6.0: + version "7.6.0" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" + integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== + dependencies: + lru-cache "^6.0.0" + send@0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" @@ -6735,6 +6781,24 @@ sourcemap-codec@^1.4.8: resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== +spdx-exceptions@^2.1.0: + version "2.5.0" + resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" + integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w== + +spdx-expression-parse@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz#a23af9f3132115465dac215c099303e4ceac5794" + integrity sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.17" + resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz#887da8aa73218e51a1d917502d79863161a93f9c" + integrity sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg== + split-on-first@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f"