From 405d33aa2f7284f0a33bd81df19f019c4b1317e1 Mon Sep 17 00:00:00 2001 From: nick-delirium Date: Wed, 10 Jan 2024 14:54:16 +0100 Subject: [PATCH] fix(tracker): fix react-native network tracking issues --- tracker/tracker-reactnative/example/README.md | 80 +------------------ .../tracker-reactnative/src/Network/index.ts | 19 ++--- tracker/tracker-reactnative/src/index.tsx | 18 +++-- tracker/tracker-reactnative/src/network.ts | 60 ++++++++------ 4 files changed, 59 insertions(+), 118 deletions(-) diff --git a/tracker/tracker-reactnative/example/README.md b/tracker/tracker-reactnative/example/README.md index 12470c30e..5efa84d65 100644 --- a/tracker/tracker-reactnative/example/README.md +++ b/tracker/tracker-reactnative/example/README.md @@ -1,79 +1,3 @@ -This is a new [**React Native**](https://reactnative.dev) project, bootstrapped using [`@react-native-community/cli`](https://github.com/react-native-community/cli). +> [SDK Docs](https://docs.openreplay.com/en/rn-sdk/) -# Getting Started - ->**Note**: Make sure you have completed the [React Native - Environment Setup](https://reactnative.dev/docs/environment-setup) instructions till "Creating a new application" step, before proceeding. - -## Step 1: Start the Metro Server - -First, you will need to start **Metro**, the JavaScript _bundler_ that ships _with_ React Native. - -To start Metro, run the following command from the _root_ of your React Native project: - -```bash -# using npm -npm start - -# OR using Yarn -yarn start -``` - -## Step 2: Start your Application - -Let Metro Bundler run in its _own_ terminal. Open a _new_ terminal from the _root_ of your React Native project. Run the following command to start your _Android_ or _iOS_ app: - -### For Android - -```bash -# using npm -npm run android - -# OR using Yarn -yarn android -``` - -### For iOS - -```bash -# using npm -npm run ios - -# OR using Yarn -yarn ios -``` - -If everything is set up _correctly_, you should see your new app running in your _Android Emulator_ or _iOS Simulator_ shortly provided you have set up your emulator/simulator correctly. - -This is one way to run your app — you can also run it directly from within Android Studio and Xcode respectively. - -## Step 3: Modifying your App - -Now that you have successfully run the app, let's modify it. - -1. Open `App.tsx` in your text editor of choice and edit some lines. -2. For **Android**: Press the R key twice or select **"Reload"** from the **Developer Menu** (Ctrl + M (on Window and Linux) or Cmd ⌘ + M (on macOS)) to see your changes! - - For **iOS**: Hit Cmd ⌘ + R in your iOS Simulator to reload the app and see your changes! - -## Congratulations! :tada: - -You've successfully run and modified your React Native App. :partying_face: - -### Now what? - -- If you want to add this new React Native code to an existing application, check out the [Integration guide](https://reactnative.dev/docs/integration-with-existing-apps). -- If you're curious to learn more about React Native, check out the [Introduction to React Native](https://reactnative.dev/docs/getting-started). - -# Troubleshooting - -If you can't get this to work, see the [Troubleshooting](https://reactnative.dev/docs/troubleshooting) page. - -# Learn More - -To learn more about React Native, take a look at the following resources: - -- [React Native Website](https://reactnative.dev) - learn more about React Native. -- [Getting Started](https://reactnative.dev/docs/environment-setup) - an **overview** of React Native and how setup your environment. -- [Learn the Basics](https://reactnative.dev/docs/getting-started) - a **guided tour** of the React Native **basics**. -- [Blog](https://reactnative.dev/blog) - read the latest official React Native **Blog** posts. -- [`@facebook/react-native`](https://github.com/facebook/react-native) - the Open Source; GitHub **repository** for React Native. +React-native library for OpenReplay. Read [main README](../../README.md) for more information. diff --git a/tracker/tracker-reactnative/src/Network/index.ts b/tracker/tracker-reactnative/src/Network/index.ts index 3299de096..7f5f13ffd 100644 --- a/tracker/tracker-reactnative/src/Network/index.ts +++ b/tracker/tracker-reactnative/src/Network/index.ts @@ -1,6 +1,6 @@ -import FetchProxy from './fetchProxy' -import XHRProxy from './xhrProxy' -import type { RequestResponseData } from './types' +import FetchProxy from './fetchProxy'; +import XHRProxy from './xhrProxy'; +import type { RequestResponseData } from './types'; export default function setProxy( context: typeof globalThis, @@ -9,23 +9,24 @@ export default function setProxy( sendMessage: (message: any) => void, isServiceUrl: (url: string) => boolean, tokenUrlMatcher?: (url: string) => boolean, + mode: 'fetch' | 'xhr' | 'all' = 'fetch' ) { - if (context.XMLHttpRequest) { + if (context.XMLHttpRequest && mode !== 'fetch') { context.XMLHttpRequest = XHRProxy.create( ignoredHeaders, sanitize, sendMessage, isServiceUrl, - tokenUrlMatcher, - ) + tokenUrlMatcher + ); } - if (context.fetch) { + if (context.fetch && mode !== 'xhr') { context.fetch = FetchProxy.create( ignoredHeaders, sanitize, sendMessage, isServiceUrl, - tokenUrlMatcher, - ) + tokenUrlMatcher + ); } } diff --git a/tracker/tracker-reactnative/src/index.tsx b/tracker/tracker-reactnative/src/index.tsx index 7b7f4bdff..8856a09c5 100644 --- a/tracker/tracker-reactnative/src/index.tsx +++ b/tracker/tracker-reactnative/src/index.tsx @@ -7,8 +7,8 @@ import { TextInput, } from 'react-native'; import type { ViewProps, TextInputProps } from 'react-native'; -import network from './network' -import type { Options as NetworkOptions } from './network' +import network from './network'; +import type { Options as NetworkOptions } from './network'; const { ORTrackerConnector } = NativeModules; @@ -90,9 +90,17 @@ const emptyShell = { networkRequest: () => null, }; -const patchNetwork = (ctx = global, isServiceUrl = () => false, opts: Partial) => { - network(ctx, ORTrackerConnector.networkRequest, isServiceUrl, opts) -} +let patched = false; +const patchNetwork = ( + ctx = global, + isServiceUrl = () => false, + opts: Partial +) => { + if (!patched) { + network(ctx, ORTrackerConnector.networkRequest, isServiceUrl, opts); + patched = true; + } +}; export default { tracker: diff --git a/tracker/tracker-reactnative/src/network.ts b/tracker/tracker-reactnative/src/network.ts index 92b9f17a4..9e7ae414d 100644 --- a/tracker/tracker-reactnative/src/network.ts +++ b/tracker/tracker-reactnative/src/network.ts @@ -1,34 +1,40 @@ -import setProxy from './Network/index' +import setProxy from './Network/index'; interface RequestData { - body: string | null - headers: Record + body: string | null; + headers: Record; } interface ResponseData { - body: any - headers: Record + body: any; + headers: Record; } export interface RequestResponseData { - readonly status: number - readonly method: string - url: string - request: RequestData - response: ResponseData + readonly status: number; + readonly method: string; + url: string; + request: RequestData; + response: ResponseData; } -type Sanitizer = (data: RequestResponseData) => RequestResponseData +type Sanitizer = (data: RequestResponseData) => RequestResponseData; export interface Options { - ignoreHeaders: Array | boolean - capturePayload: boolean - captureInIframes: boolean - sanitizer?: Sanitizer - tokenUrlMatcher?: (url: string) => boolean + ignoreHeaders: Array | boolean; + capturePayload: boolean; + captureInIframes: boolean; + sanitizer?: Sanitizer; + tokenUrlMatcher?: (url: string) => boolean; + mode: 'fetch' | 'xhr' | 'all'; } -export default function (context = global, sendMessage: (args: any[]) => void, isServiceUrl: (url: string) => boolean, opts: Partial = {}) { +export default function ( + context = global, + sendMessage: (args: any[]) => void, + isServiceUrl: (url: string) => boolean, + opts: Partial = {} +) { const options: Options = Object.assign( { failuresOnly: false, @@ -37,27 +43,28 @@ export default function (context = global, sendMessage: (args: any[]) => void, i captureInIframes: true, axiosInstances: undefined, useProxy: true, + mode: 'fetch', }, - opts, - ) + opts + ); function sanitize(reqResInfo: RequestResponseData) { if (!options.capturePayload) { // @ts-ignore - delete reqResInfo.request.body - delete reqResInfo.response.body + delete reqResInfo.request.body; + delete reqResInfo.response.body; } if (options.sanitizer) { - const resBody = reqResInfo.response.body + const resBody = reqResInfo.response.body; if (typeof resBody === 'string') { // Parse response in order to have handy view in sanitization function try { - reqResInfo.response.body = JSON.parse(resBody) + reqResInfo.response.body = JSON.parse(resBody); } catch {} } - return options.sanitizer(reqResInfo) + return options.sanitizer(reqResInfo); } - return reqResInfo + return reqResInfo; } return setProxy( @@ -67,5 +74,6 @@ export default function (context = global, sendMessage: (args: any[]) => void, i sendMessage, (url) => isServiceUrl(url), options.tokenUrlMatcher, - ) + options.mode + ); }