master bd3435a456a2 cached
144 files
364.4 KB
98.3k tokens
96 symbols
1 requests
Download .txt
Showing preview only (397K chars total). Download the full file or copy to clipboard to get everything.
Repository: jhen0409/react-native-debugger
Branch: master
Commit: bd3435a456a2
Files: 144
Total size: 364.4 KB

Directory structure:
gitextract_p_y_i4jj/

├── .eslintignore
├── .eslintrc
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE.md
│   ├── settings.yml
│   └── workflows/
│       ├── main.yml
│       └── release.yml
├── .gitignore
├── .prettierrc
├── LICENSE.md
├── README.md
├── __e2e__/
│   ├── app.spec.js
│   ├── buildTestBundle.js
│   ├── fixture/
│   │   ├── apollo.js
│   │   ├── app.js
│   │   ├── mobx.js
│   │   ├── redux.js
│   │   ├── remotedev.js
│   │   ├── setup.js
│   │   └── xhr-test.js
│   └── mockRNServer.js
├── app/
│   ├── actions/
│   │   ├── debugger.js
│   │   └── setting.js
│   ├── components/
│   │   ├── Draggable.js
│   │   └── FormInput.js
│   ├── containers/
│   │   ├── App.js
│   │   ├── ReactInspector.js
│   │   └── redux/
│   │       ├── DevTools.js
│   │       ├── Header.js
│   │       └── Settings.js
│   ├── globalStyles.js
│   ├── index.js
│   ├── middlewares/
│   │   ├── debuggerAPI.js
│   │   └── reduxAPI.js
│   ├── reducers/
│   │   ├── debugger.js
│   │   ├── index.js
│   │   └── setting.js
│   ├── setup.js
│   ├── store/
│   │   └── configureStore.js
│   ├── utils/
│   │   ├── adb.js
│   │   ├── config.js
│   │   ├── devMenu.js
│   │   └── devtools.js
│   └── worker/
│       ├── .eslintrc
│       ├── apollo.js
│       ├── asyncStorage.js
│       ├── devMenu.js
│       ├── index.js
│       ├── networkInspect.js
│       ├── polyfills/
│       │   └── fetch.js
│       ├── reactDevTools.js
│       ├── reduxAPI.js
│       ├── remotedev.js
│       ├── setup.js
│       └── utils.js
├── auto_update.json
├── auto_updater.json
├── babel.config.js
├── dist/
│   ├── app.html
│   ├── css/
│   │   └── style.css
│   ├── devtools-helper/
│   │   ├── main.html
│   │   ├── main.js
│   │   └── manifest.json
│   ├── package.json
│   └── patches/
│       └── apollo-client-devtools+4.1.4.patch
├── docs/
│   ├── README.md
│   ├── apollo-client-devtools-integration.md
│   ├── config-file-in-home-directory.md
│   ├── contributing.md
│   ├── debugger-integration.md
│   ├── enable-open-in-editor-in-console.md
│   ├── getting-started.md
│   ├── network-inspect-of-chrome-devtools.md
│   ├── react-devtools-integration.md
│   ├── redux-devtools-integration.md
│   ├── shortcut-references.md
│   └── troubleshooting.md
├── electron/
│   ├── app.html
│   ├── config/
│   │   ├── __tests__/
│   │   │   ├── __snapshots__/
│   │   │   │   └── index.test.js.snap
│   │   │   └── index.test.js
│   │   ├── index.js
│   │   └── template.js
│   ├── context-menu.js
│   ├── debug.js
│   ├── devtools.js
│   ├── extensions.js
│   ├── logo.icns
│   ├── main.js
│   ├── menu/
│   │   ├── common.js
│   │   ├── darwin.js
│   │   ├── dialog.js
│   │   ├── index.js
│   │   └── linux+win.js
│   ├── sync-state.js
│   ├── update.js
│   ├── url-handle/
│   │   ├── handleURL.js
│   │   ├── index.js
│   │   └── port.js
│   └── window.js
├── examples/
│   ├── .eslintrc
│   └── test-old-bridge/
│       ├── .gitignore
│       ├── App.js
│       ├── README.md
│       ├── app.json
│       ├── babel.config.js
│       ├── examples/
│       │   ├── apollo/
│       │   │   ├── App.js
│       │   │   └── SimpleQuery.js
│       │   └── redux/
│       │       ├── App.js
│       │       ├── app/
│       │       │   └── store.js
│       │       └── features/
│       │           └── counter/
│       │               ├── Counter.js
│       │               ├── counterAPI.js
│       │               └── counterSlice.js
│       └── package.json
├── npm-package/
│   ├── .eslintrc
│   ├── .gitignore
│   ├── README.md
│   ├── babel.config.js
│   ├── bin/
│   │   └── rndebugger-open.js
│   ├── package.json
│   └── src/
│       ├── __tests__/
│       │   ├── __snapshots__/
│       │   │   └── injectDevToolsMiddleware.test.js.snap
│       │   └── injectDevToolsMiddleware.test.js
│       ├── injectDevToolsMiddleware.js
│       ├── main.js
│       └── open.js
├── package.json
├── patches/
│   ├── @redux-devtools+inspector-monitor-trace-tab+1.0.0.patch
│   ├── @redux-devtools+ui+1.3.0.patch
│   ├── apollo-client-devtools+4.1.4.patch
│   ├── electron-gh-releases+2.0.4.patch
│   └── react-dev-utils+4.2.3.patch
├── scripts/
│   ├── config.json
│   ├── mac/
│   │   ├── createDMG.js
│   │   ├── createUniversalApp.js
│   │   └── entitlements.plist
│   ├── package-linux.sh
│   ├── package-macos.sh
│   ├── package-windows.sh
│   ├── patch-modules.js
│   └── postinstall.js
└── webpack/
    ├── .eslintrc
    ├── base.js
    ├── main.prod.js
    ├── renderer.dev.js
    └── renderer.prod.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .eslintignore
================================================
npm-package/lib/
*.tmpl.js
*.bundle.js
dist/
release/
node_modules/


================================================
FILE: .eslintrc
================================================
{
  "parser": "@babel/eslint-parser",
  "extends": ["airbnb", "prettier"],
  "env": {
    "browser": true,
    "node": true,
    "jest": true
  },
  "settings": {
    "import/core-modules": ["electron"]
  },
  "rules": {
    "linebreak-style": 0,
    "react/prefer-stateless-function": 0,
    "consistent-return": 0,
    "strict": 0,
    "no-console": 0,
    "no-param-reassign": ["error", { "props": false }],
    "no-underscore-dangle": [
      "error",
      {
        "allow": [
          "__IS_REDUX_NATIVE_MESSAGE__",
          "__AVAILABLE_METHODS_CAN_CALL_BY_RNDEBUGGER__",
          "__PLATFORM__",
          "__REPORT_REACT_DEVTOOLS_PORT__",
          "__FETCH_SUPPORT__",
          "__NETWORK_INSPECT__",
          "__FROM_DEBUGGER_WORKER__"
        ]
      }
    ],
    "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
    "import/prefer-default-export": 0,
    "import/no-extraneous-dependencies": ["error", { "optionalDependencies": true }],
    "semi": ["error", "never"]
  }
}


================================================
FILE: .github/FUNDING.yml
================================================
github: jhen0409
open_collective: react-native-debugger


================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
<!--
Before submitting the issue:

- You're using the latest version of react-native-debugger
- You have read the documentation
- For the feature requests / issues of devtools integration like React / Redux / Apollo, you should submit an issue to that repo
  - https://github.com/facebook/react-devtools/issues
  - https://github.com/reduxjs/redux-devtools/issues
  - https://github.com/apollographql/apollo-client-devtools/issues
-->

<!--
Please provide the following information for bug report or question, if you can provide a minimal example project or screenshot or even video would be helpful for reproduce the problem. You can just removed these if you want to submit a feature request:
-->

React Native Debugger app version: [FILL THIS OUT]
React Native version: [FILL THIS OUT]
Platform: [FILL THIS OUT: iOS, Android, ...]
Is real device of platform: [Yes or No]
Operating System: [FILL THIS OUT: macOS, Linux, Windows]

<!-- Love react-native-debugger? Please consider supporting our collective:
👉  https://opencollective.com/react-native-debugger/donate -->


================================================
FILE: .github/settings.yml
================================================
repository:
  name: react-native-debugger
  has_issues: true
  has_wiki: true
  has_downloads: true
  default_branch: master
  allow_squash_merge: true
  allow_merge_commit: true
  allow_rebase_merge: true

labels:
  - name: bug
    color: CC0000
  - name: help wanted
    color: 33aa3f
  - name: duplicate
    color: cfd3d7
  - name: enhancement
    color: a2eeef
  - name: question
    color: d876e3
  - name: invalid
    color: e4e669
  - name: wontfix
    color: ffffff
  - name: feature
    color: 336699
  - name: trivial
    oldname: good first issue
    color: afffb2
  - name: has PR
    color: 3100ad
  - name: documentation
    color: a1ed95
  - name: RFC
    color: 3100ad
  - name: WIP
    color: e4e669
  - name: don't merge
    color: CC0000
  - name: stale
    color: ffffff
  - name: cannot-reproduce
    color: bfdadc
  - name: more-information-needed
    color: c2e0c6
  - name: upstream
    color: 5319e7
  - name: waiting-for-response
    color: 3100ad

  # Integrations
  - name: integration/react-devtools
    color: 1b307c
  - name: integration/redux-devtools
    color: 7c2d9e
  - name: integration/apollo-client-devtools
    color: 7066e8

  # Features
  - name: feature/network-inspect
    color: fce885

  # Packages
  - name: package/react-native-debugger-open
    color: f7e78f


================================================
FILE: .github/workflows/main.yml
================================================
name: CI

on: [push, pull_request]

concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

jobs:
  build-test-linux:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3.7.0
        with:
          node-version: 18.x
          cache: 'yarn'
      - name: Setup
        run: sudo apt-get install -y libgbm-dev
      - name: Test
        id: test
        run: |
          yarn
          cd npm-package && yarn && cd ..
          yarn test
          yarn build
          xvfb-run --auto-servernum yarn test-e2e
      - name: Upload artifacts on failure
        if: ${{ failure() && steps.test.conclusion == 'failure' }}
        uses: actions/upload-artifact@v3
        with:
          name: artifacts
          path: artifacts
          retention-days: 1
  build-test-macos:
    runs-on: macOS-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3.7.0
        with:
          node-version: 18.x
          cache: 'yarn'
      - name: Test
        id: test
        run: |
          yarn
          cd npm-package && yarn && cd ..
          yarn test
          yarn build
          yarn test-e2e
      - name: Upload artifacts on failure
        if: ${{ failure() && steps.test.conclusion == 'failure' }}
        uses: actions/upload-artifact@v3
        with:
          name: artifacts
          path: artifacts
          retention-days: 1
  build-test-windows:
    runs-on: windows-2022
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3.7.0
        with:
          node-version: 18.x
          cache: 'yarn'
      - name: Test
        id: test
        shell: bash
        run: |
          yarn config set network-timeout 500000 -g
          yarn
          cd npm-package && yarn && cd ..
          yarn build
          yarn test
          yarn test-e2e
      - name: Upload artifacts on failure
        if: ${{ failure() && steps.test.conclusion == 'failure' }}
        uses: actions/upload-artifact@v3
        with:
          name: artifacts
          path: artifacts
          retention-days: 1

================================================
FILE: .github/workflows/release.yml
================================================
name: Release

on:
  release:
    types: [published]

jobs:
  release-linux:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3.7.0
        with:
          node-version: 18.x
          cache: 'yarn'
      - name: Package
        run: |
          yarn
          yarn build
          yarn pack-linux
      - name: Upload assets to release
        uses: jhen0409/release-asset-action@master
        with:
          file: release/rn-debugger-linux-x64.zip
          pattern: release/react-native-debugger*
          github-token: ${{ secrets.GITHUB_TOKEN }}
  release-windows:
    runs-on: windows-2022
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3.7.0
        with:
          node-version: 18.x
          cache: 'yarn'
      - name: Package
        shell: bash
        run: |
          yarn config set network-timeout 500000 -g
          yarn
          yarn build
          yarn pack-windows
      - name: Upload assets to release
        uses: jhen0409/release-asset-action@master
        with:
          file: release/rn-debugger-windows-x64.zip
          pattern: release/react_native_debugger*.exe
          github-token: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .gitignore
================================================
node_modules
npm-debug.log
yarn-error.log
.DS_Store
dist/js
dist/main.js*
release/
*.bundle.js
tmp/
config_test
.idea/
artifacts/


================================================
FILE: .prettierrc
================================================
{
  "trailingComma": "all",
  "tabWidth": 2,
  "semi": false,
  "singleQuote": true,
  "printWidth": 80
}


================================================
FILE: LICENSE.md
================================================

The MIT License (MIT)

Copyright (c) 2016 Jhen-Jie Hong

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# React Native Debugger

[![Backers on Open Collective](https://opencollective.com/react-native-debugger/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/react-native-debugger/sponsors/badge.svg)](#sponsors) [![CI Status](https://github.com/jhen0409/react-native-debugger/workflows/CI/badge.svg)](https://github.com/jhen0409/react-native-debugger)

⚠️ This app is currently only supported old [Remote Debugger](https://reactnative.dev/docs/debugging#chrome-developer-tools), if you're looking for new debugger support (e.g. Hermes / JSI / New Architecture) of React Native Debugger, please follow [discussion#774](https://github.com/jhen0409/react-native-debugger/discussions/774).

![React Native Debugger](https://user-images.githubusercontent.com/3001525/29451479-6621bf1a-83c8-11e7-8ebb-b4e98b1af91c.png)

> Run the redux example of [react-navigation](https://github.com/react-navigation/react-navigation/tree/master/example) with Redux DevTools setup

This is a standalone app for debugging React Native apps:

- Based on official [Remote Debugger](https://reactnative.dev/docs/debugging#chrome-developer-tools) and provide more functionality.
- Includes [React Inspector](docs/react-devtools-integration.md) from [`react-devtools-core`](https://github.com/facebook/react/tree/master/packages/react-devtools-core).
- Includes Redux DevTools, made [the same API](docs/redux-devtools-integration.md) with [`redux-devtools-extension`](https://github.com/reduxjs/redux-devtools/tree/main/extension).
- Includes [Apollo Client DevTools](docs/apollo-client-devtools-integration.md) ([`apollographql/apollo-client-devtools`](https://github.com/apollographql/apollo-client-devtools)) as devtools extension.

## Installation

To install the app, you can download a prebuilt binary from the [release page](https://github.com/jhen0409/react-native-debugger/releases).

For **macOS**, you can use [Homebrew Cask](https://caskroom.github.io) to install:

### < Homebrew 2.6.0

```bash
brew update && brew install --cask react-native-debugger
```

### >= Homebrew 2.6.0

```bash
brew install --cask react-native-debugger
```

This puts `React Native Debugger.app` in your `/applications/` folder.

### NOTICE: React Native Compatibility

To use this app you need to ensure you are using the correct version of React Native Debugger and react-native:

| React Native Debugger | react-native |
| --------------------- | ------------ |
| >= 0.11               | >= 0.62      |
| <= 0.10               | <= 0.61      |

We used different auto-update feed for `v0.10` and `v0.11`, so you won't see update tips of `v0.11` from `v0.10`.

Install last release of v0.10 (0.10.7)

### < Homebrew 2.6.0

`brew update && brew cask install https://raw.githubusercontent.com/Homebrew/homebrew-cask/b6ac3795c1df9f97242481c0817b1165e3e6306a/Casks/react-native-debugger.rb`

### >= Homebrew 2.6.0

`brew install --cask https://raw.githubusercontent.com/Homebrew/homebrew-cask/b6ac3795c1df9f97242481c0817b1165e3e6306a/Casks/react-native-debugger.rb`

### Arch-based distributions

You can install [react-native-debugger-bin][1] from Arch User Repository:

```shell
git clone https://aur.archlinux.org/react-native-debugger-bin.git
cd react-native-debugger-bin
makepkg -si

# or using AUR helper
paru -S react-native-debugger-bin
```

## Build from source

Please read [Development section](docs/contributing.md#development) in docs/contributing.md for how to build the app from source.

## Documentation

- [Getting Started](docs/getting-started.md)
- [Debugger Integration](docs/debugger-integration.md)
- [React DevTools Integration](docs/react-devtools-integration.md)
- [Redux DevTools Integration](docs/redux-devtools-integration.md)
- [Apollo Client DevTools Integration](docs/apollo-client-devtools-integration.md)
- [Shortcut references](docs/shortcut-references.md)
- [Network inspect of Chrome Developer Tools](docs/network-inspect-of-chrome-devtools.md)
- [Enable open in editor in console](docs/enable-open-in-editor-in-console.md)
- [Config file in home directory](docs/config-file-in-home-directory.md)
- [Troubleshooting](docs/troubleshooting.md)
- [Contributing](docs/contributing.md)

## Documentation (v0.10)

Please visit [`v0.10 branch`](https://github.com/jhen0409/react-native-debugger/tree/v0.10).

## Credits

- Great work of [React DevTools](https://github.com/facebook/react/tree/master/packages/react-devtools)
- Great work of [Redux DevTools](https://github.com/gaearon/redux-devtools) / [Remote Redux DevTools](https://github.com/zalmoxisus/remote-redux-devtools) and all third-party monitors.
- Great work of [Apollo Client DevTools](https://github.com/apollographql/apollo-client-devtools)). (Special thanks to [@Gongreg](https://github.com/Gongreg) for integrating this!)

## Backers

Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/react-native-debugger#backer)]

<a href="https://opencollective.com/react-native-debugger#backers" target="_blank"><img src="https://opencollective.com/react-native-debugger/backers.svg?width=890"></a>

## Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/react-native-debugger#sponsor)]

<a href="https://opencollective.com/react-native-debugger#backers" target="_blank"><img src="https://opencollective.com/react-native-debugger/sponsors.svg?width=890"></a>

## LICENSE

[MIT](LICENSE.md)

[1]: https://aur.archlinux.org/packages/react-native-debugger-bin


================================================
FILE: __e2e__/app.spec.js
================================================
import fs from 'fs'
import path from 'path'
import net from 'net'
import http from 'http'
import executablePath from 'electron'
import { _electron as electron } from 'playwright-core'
import waitForExpect from 'wait-for-expect'
import buildTestBundle, { bundlePath } from './buildTestBundle'
import createMockRNServer from './mockRNServer'

const delay = (time) =>
  new Promise((resolve) => {
    setTimeout(resolve, time)
  })

jest.setTimeout(6e4)

describe('Application launch', () => {
  let electronApp
  let mainWindow
  const logs = []

  beforeAll(async () => {
    await buildTestBundle()
    process.env.PACKAGE = 'no'
    electronApp = await electron.launch({
      executablePath,
      args: ['--user-dir=__e2e__/tmp', './main.js'],
      cwd: path.join(__dirname, '../dist'),
    })
    mainWindow = await electronApp.firstWindow()
    mainWindow.on('console', (msg) => logs.push(msg))
    await mainWindow.waitForLoadState()
  })

  afterEach(async () => {
    const state = expect.getState()
    await mainWindow.screenshot({
      path: `./artifacts/${state.currentTestName}.png`,
    })
    const devtoolsWindow = electronApp.windows()[2]
    if (devtoolsWindow) {
      try {
        await delay(100)
        await devtoolsWindow.screenshot({
          path: `./artifacts/devtools:${state.currentTestName}.png`,
        })
      } catch (e) {
        console.error(e)
      }
    }
  })

  afterAll(async () => {
    await electronApp.close()
  })

  it('should show an initial window', async () => {
    expect(await mainWindow.title()).toBe(
      'React Native Debugger - Attempting reconnection (port 8081)',
    )
  })

  it('should portfile (for debugger-open usage) always exists in home dir', async () => {
    const portFile = path.join(
      process.env.USERPROFILE || process.env.HOME,
      '.rndebugger_port',
    )

    expect(fs.existsSync(portFile)).toBe(true)
    fs.unlinkSync(portFile)

    await waitForExpect(async () => {
      expect(fs.existsSync(portFile)).toBeTruthy()
    })
  })

  it("should contain Inspector monitor's component on Redux DevTools", async () => {
    const val = await mainWindow.textContent(
      '//div[contains(@class, "inspector-")]',
    )
    expect(val).not.toBeNull()
  })

  it('should contain an empty actions list on Redux DevTools', async () => {
    const val = await mainWindow.textContent(
      '//div[contains(@class, "actionListRows-")]',
    )
    expect(val).toBe('')
  })

  it('should show waiting message on React DevTools', async () => {
    const el = await mainWindow.locator(
      '//h2[text()="Waiting for React to connect…"]',
    )
    expect(await el.isVisible()).toBe(true)
  })

  const customRNServerPort = 8098
  const getURLFromConnection = (server) =>
    new Promise((resolve) => {
      server.on('connection', (socket, req) => {
        resolve(req.url)
      })
    })

  it('should connect to fake RN server', async () => {
    const { wss, server } = createMockRNServer()

    const url = await getURLFromConnection(wss)
    expect(url).toBe('/debugger-proxy?role=debugger&name=Chrome')

    await waitForExpect(async () => {
      expect(await mainWindow.title()).toBe(
        'React Native Debugger - Waiting for client connection (port 8081)',
      )
    })
    server.close()
    wss.close()
  })

  it('should connect to fake RN server (port 8088) with send set-debugger-loc after', async () => {
    const { wss, server } = createMockRNServer(customRNServerPort)

    const rndPath = `rndebugger://set-debugger-loc?host=localhost&port=${customRNServerPort}`
    const homeEnv = process.platform === 'win32' ? 'USERPROFILE' : 'HOME'
    const portFile = path.join(process.env[homeEnv], '.rndebugger_port')
    const rndPort = fs.readFileSync(portFile, 'utf-8')

    const sendSuccess = await new Promise((resolve) => {
      const socket = net.createConnection(
        { host: '127.0.0.1', port: rndPort },
        () => {
          let pass
          socket.setEncoding('utf-8')
          socket.write(JSON.stringify({ path: rndPath }))
          socket.on('data', (data) => {
            pass = data === 'success'
            socket.end()
          })
          socket.on('end', () => resolve(pass))
          setTimeout(() => socket.end(), 1000)
        },
      )
    })
    expect(sendSuccess).toBe(true)

    const url = await getURLFromConnection(wss)
    expect(url).toBe('/debugger-proxy?role=debugger&name=Chrome')

    await waitForExpect(async () => {
      expect(await mainWindow.title()).toBe(
        `React Native Debugger - Waiting for client connection (port ${customRNServerPort})`,
      )
    })
    server.close()
    wss.close()
  })

  describe('Import fake script after', () => {
    const getOneRequestHeaders = (port) =>
      new Promise((resolve) => {
        const server = http.createServer((req, res) => {
          res.writeHead(200, { 'Content-Type': 'text/plain' })
          res.end('')
          resolve(req.headers)
          server.close()
        })
        server.listen(port)
      })

    let headersPromise
    let server
    let wss
    beforeAll(async () => {
      const info = createMockRNServer(customRNServerPort)
      server = info.server
      wss = info.wss

      headersPromise = getOneRequestHeaders(8099)

      await new Promise((resolve) => {
        wss.on('connection', (socket) => {
          socket.on('message', (message) => {
            const data = JSON.parse(message)
            switch (data.replyID) {
              case 'createJSRuntime':
                socket.send(
                  JSON.stringify({
                    id: 'sendFakeScript',
                    method: 'executeApplicationScript',
                    inject: [],
                    url: `../../${bundlePath}`,
                  }),
                )
                break
              case 'sendFakeScript':
                return resolve()
              default:
                console.error(`Unexperted id ${data.replyID}, data:`, data)
            }
          })
          socket.send(
            JSON.stringify({
              id: 'createJSRuntime',
              method: 'prepareJSRuntime',
            }),
          )
        })
      })
      expect(await mainWindow.title()).toBe(
        `React Native Debugger - Connected (port ${customRNServerPort})`,
      )
    })

    afterAll(() => {
      server.close()
      wss.close()
    })

    it('should received forbidden header names from xhr-test', async () => {
      const headers = await headersPromise

      expect(headers.origin).toBe('custom_origin_here')
      expect(headers['user-agent']).toBe('react-native')
    })

    it('should have @@INIT action on Redux DevTools', async () => {
      const el = await mainWindow
        .locator('div')
        .filter({ hasText: '@@redux/INIT' })
        .first()
      expect(await el.isVisible()).toBeTruthy() // Last store is `RemoteDev store instance 1`
    })

    let currentInstance = 'Autoselect instances' // Default instance
    const wait = () => delay(750)
    const selectInstance = async (instance) => {
      let el = mainWindow.locator(`//div[text()="${currentInstance}"]`)
      expect(await el.isVisible()).toBeTruthy()
      await el.click({ force: true })
      await wait()
      currentInstance = instance
      el = mainWindow.locator(`//div[text()="${instance}"]`)
      expect(await el.isVisible()).toBeTruthy()
      await el.click({ force: true })
      await wait()
    }
    const commit = async () => {
      await mainWindow.click('//button[text()="Commit"]', { force: true })
      await wait()
    }

    const expectActions = {
      'Redux store instance 1': {
        expt: [
          '@@INIT',
          'TEST_PASS_FOR_REDUX_STORE_1',
          'SHOW_FOR_REDUX_STORE_1',
        ],
        notExpt: ['NOT_SHOW_FOR_REDUX_STORE_1', 'TEST_PASS_FOR_REDUX_STORE_2'],
      },
      'Redux store instance 2': {
        expt: ['@@INIT', 'TEST_PASS_FOR_REDUX_STORE_2'],
        notExpt: [
          'TEST_PASS_FOR_REDUX_STORE_1',
          'NOT_SHOW_1_FOR_REDUX_STORE_2',
          'NOT_SHOW_2_FOR_REDUX_STORE_2',
          'NOT_SHOW_3_FOR_REDUX_STORE_2',
        ],
      },
      'MobX store instance 1': {
        expt: ['@@INIT', 'testPassForMobXStore1'],
        notExpt: ['TEST_PASS_FOR_REDUX_STORE_2'],
      },
      'MobX store instance 2': {
        expt: ['@@INIT', 'testPassForMobXStore2'],
        notExpt: ['testPassForMobXStore1'],
      },
      'RemoteDev store instance 1': {
        expt: ['@@redux/INIT', 'TEST_PASS_FOR_REMOTEDEV_STORE_1'],
        notExpt: ['testPassForMobXStore2'],
      },
    }

    const eachAsync = (entries, fn) =>
      entries.reduce(
        (promise, entry, index) => promise.then(() => fn(entry, index)),
        Promise.resolve(),
      )

    const runExpectActions = async (name) => {
      const { expt, notExpt } = expectActions[name]

      await eachAsync(expt, async (action) => {
        const el = await mainWindow
          .locator('div')
          .filter({ hasText: action })
          .first()
        expect(await el.isVisible()).toBeTruthy()
      })

      await eachAsync(notExpt, async (action) => {
        const el = await mainWindow
          .locator('div')
          .filter({ hasText: action })
          .first()
        expect(await el.isVisible()).toBeFalsy()
      })
    }

    const checkInstance = async (name) => {
      await selectInstance(name)
      await runExpectActions(name)
      await commit()
    }

    it('should have two Redux store instances on Redux DevTools', async () => {
      await checkInstance('Redux store instance 1')
      await checkInstance('Redux store instance 2')
    })

    it('should have two MobX store instances on Redux DevTools', async () => {
      await checkInstance('MobX store instance 1')
      await checkInstance('MobX store instance 2')
    })

    it('should have one RemoteDev store instances on Redux DevTools', async () => {
      await checkInstance('RemoteDev store instance 1')
    })

    it('should have only specific logs in console of main window', async () => {
      // Print renderer process logs
      logs.forEach((log) =>
        console.log(`Message: ${log.text()}\nType: ${log.type()}`),
      )
      expect(logs.length).toEqual(3) // clear + clear + warning
      const [, , formDataWarning] = logs
      expect(formDataWarning.type()).toBe('warning')
      expect(
        formDataWarning
          .text()
          .indexOf("Detected you're enabled Network Inspect") > 0,
      ).toBeTruthy()
    })

    it('should show apollo devtools panel', async () => {
      const devtoolsWindow = electronApp.windows()[2]
      expect(
        await devtoolsWindow.evaluate(() =>
          // eslint-disable-next-line no-undef
          Object.keys(UI.panels).some(
            (key) =>
              key.startsWith('chrome-extension://') && key.endsWith('Apollo'),
          ),
        ),
      ).toBeTruthy()
    })
  })
})


================================================
FILE: __e2e__/buildTestBundle.js
================================================
import path from 'path'
import webpack from 'webpack'

const outputPath = '__e2e__/fixture'
const filename = 'app.bundle.js'

export const bundlePath = path.join(outputPath, filename)

// Build a bundle for simulate RNDebugger worker run react-native bundle,
// it included redux, mobx, remotedev tests
export default function buildTestBundle() {
  return new Promise((resolve) => {
    webpack({
      mode: 'development',
      entry: './__e2e__/fixture/app',
      output: {
        path: path.resolve(__dirname, '..', outputPath),
        filename,
      },
      resolve: {
        mainFields: ['react-native', 'main', 'browser'],
      },
    }).run(resolve)
  })
}


================================================
FILE: __e2e__/fixture/apollo.js
================================================
/* eslint-disable import/no-extraneous-dependencies */
/*
 * Create an Apollo Client to test the bridge messages sent
 * wouldn't break the debugger proxy.
 */

import { ApolloClient, InMemoryCache } from '@apollo/client'
import gql from 'graphql-tag'

const client = new ApolloClient({
  uri: 'https://spacex-production.up.railway.app/',
  cache: new InMemoryCache(),
})

export default async function run() {
  return client.query({
    query: gql`
      query ExampleQuery {
        company {
          name
          ceo
          employees
        }
      }
    `,
  })
}


================================================
FILE: __e2e__/fixture/app.js
================================================
import './setup'

import runXHRTest from './xhr-test' // Install fetch polyfill before initial apollo-client
import runApolloTest from './apollo'
import runReduxTest from './redux'
import runMobXTest from './mobx'
import runRemoteDevTest from './remotedev'

runReduxTest()
runMobXTest()
runRemoteDevTest()
runApolloTest().catch((e) => console.error(e))
runXHRTest().catch((e) => console.error(e))


================================================
FILE: __e2e__/fixture/mobx.js
================================================
/* eslint prefer-arrow-callback: 0 */
import { observable, action, useStrict } from 'mobx'
import remotedev from 'mobx-remotedev/lib/dev'

useStrict(true)

export default function run() {
  const store = observable({ value: 0 })
  store.testPassForMobXStore1 = action(function testPassForMobXStore1() {})

  remotedev(store, { name: 'MobX store instance 1' }).testPassForMobXStore1()

  const store2 = observable({ value: 1 })
  store2.testPassForMobXStore2 = action(function testPassForMobXStore2() {})

  remotedev(store2, { name: 'MobX store instance 2' }).testPassForMobXStore2()
}


================================================
FILE: __e2e__/fixture/redux.js
================================================
/* eslint no-underscore-dangle: 0 */

import { createStore } from 'redux'

export default function run() {
  // Enhancer
  const store1 = createStore(
    (state) => state,
    { value: 0 },
    window.__REDUX_DEVTOOLS_EXTENSION__({
      name: 'Redux store instance 1',
      actionsWhitelist: ['@@INIT', 'TEST_PASS_FOR_REDUX_STORE_1', '^SHOW_FOR_REDUX_STORE_1$'],
    }),
  )

  // Compose enhancers
  const store2 = createStore(
    (state) => state,
    { value: 1 },
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
      name: 'Redux store instance 2',
      actionsBlacklist: ['NOT_SHOW_1_FOR_REDUX_STORE_2', 'NOT_SHOW_2_FOR_REDUX_STORE_2'],
      predicate: (state, action) => action.type !== 'NOT_SHOW_3_FOR_REDUX_STORE_2',
    })(/* No enhancers */),
  )

  store1.dispatch({ type: 'TEST_PASS_FOR_REDUX_STORE_1' })
  store1.dispatch({ type: 'SHOW_FOR_REDUX_STORE_1' })
  store1.dispatch({ type: 'NOT_SHOW_FOR_REDUX_STORE_1' })

  store2.dispatch({ type: 'TEST_PASS_FOR_REDUX_STORE_2' })
  store2.dispatch({ type: 'NOT_SHOW_1_FOR_REDUX_STORE_2' })
  store2.dispatch({ type: 'NOT_SHOW_2_FOR_REDUX_STORE_2' })
  store2.dispatch({ type: 'NOT_SHOW_3_FOR_REDUX_STORE_2' })
}


================================================
FILE: __e2e__/fixture/remotedev.js
================================================
import { createStore } from 'redux'

const connectViaExtension = window.devToolsExtension.connect

const logReducer = (reducer) => {
  const remotedev = connectViaExtension({
    name: 'RemoteDev store instance 1',
    actionCreators: {
      test: () => {},
    },
  })
  return (state, action) => {
    const reducedState = reducer(state, action)
    remotedev.send(action, reducedState)
    return reducedState
  }
}

const logRemotely = (next) => (reducer, initialState) => next(logReducer(reducer), initialState)

export default function run() {
  const store = logRemotely(createStore)((state) => state, { value: 0 })

  store.dispatch({ type: 'TEST_PASS_FOR_REMOTEDEV_STORE_1' })
}


================================================
FILE: __e2e__/fixture/setup.js
================================================
/* eslint-disable no-restricted-globals */
/* eslint no-underscore-dangle: 0 */

self.window = global

// Remove native fetch as react-native use whatwg-fetch polyfill
self.fetch = undefined

const MessageQueue = function MessageQueue() {}
MessageQueue.spy = () => {}
MessageQueue.prototype.__spy = null

const requiredModules = {
  NativeModules: {},
  Platform: {},
  setupDevtools: undefined,
  AsyncStorage: {},
  MessageQueue,
}
// Simulate React Native's window.require polyfill
window.require = (moduleName) => {
  if (typeof moduleName !== 'number') {
    // From https://github.com/facebook/react-native/blob/5403946f098cc72c3d33ea5cee263fb3dd03891d/packager/src/Resolver/polyfills/require.js#L97
    console.warn(
      `Requiring module '${moduleName}' by name is only supported for `
        + 'debugging purposes and will BREAK IN PRODUCTION!',
    )
  }
  return requiredModules[moduleName]
}
window.__DEV__ = true
window.__fbBatchedBridge = new MessageQueue()


================================================
FILE: __e2e__/fixture/xhr-test.js
================================================
import 'whatwg-fetch'

export default async function run() {
  // Fetch with forbidden header names
  await fetch('http://localhost:8099', {
    headers: {
      Origin: 'custom_origin_here',
      'User-Agent': 'react-native',
    },
  })

  // It will log warning
  // because we can't use worker's FormData for upload file
  const data = { uri: 'uri' }
  const form = new FormData()
  form.append('file', data)
}


================================================
FILE: __e2e__/mockRNServer.js
================================================
import http from 'http'
import WebSocket from 'ws'

export default function createMockRNServer(port = 8081) {
  const server = http.createServer((req, res) => {
    if (req.method === 'GET' && req.url === '/debugger-ui') {
      res.writeHead(200, { 'Content-Type': 'text/html' })
      res.end('<html></html>')
    }
  })
  const wss = new WebSocket.Server({ server })
  server.listen(port)
  return { server, wss }
}


================================================
FILE: app/actions/debugger.js
================================================
export const SET_DEBUGGER_LOCATION = 'SET_DEBUGGER_LOCATION'
export const SET_DEBUGGER_STATUS = 'SET_DEBUGGER_STATUS'
export const SET_DEBUGGER_WORKER = 'SET_DEBUGGER_WORKER'
export const SYNC_STATE = 'SYNC_STATE'
export const BEFORE_WINDOW_CLOSE = 'BEFORE_WINDOW_CLOSE'

export const setDebuggerLocation = (loc) => ({
  type: SET_DEBUGGER_LOCATION,
  loc,
})

export const setDebuggerStatus = (status) => ({
  type: SET_DEBUGGER_STATUS,
  status,
})

export const setDebuggerWorker = (worker, status) => ({
  type: SET_DEBUGGER_WORKER,
  worker,
  status,
})

export const syncState = (payload) => ({
  type: SYNC_STATE,
  payload,
})

export const beforeWindowClose = () => ({
  type: BEFORE_WINDOW_CLOSE,
})


================================================
FILE: app/actions/setting.js
================================================
export const TOGGLE_DEVTOOLS = 'TOGGLE_DEVTOOLS'
export const RESIZE_DEVTOOLS = 'RESIZE_DEVTOOLS'
export const CHANGE_DEFAULT_THEME = 'CHANGE_DEFAULT_THEME'

export const toggleDevTools = (name) => ({
  type: TOGGLE_DEVTOOLS,
  name,
})

export const resizeDevTools = (size) => ({
  type: RESIZE_DEVTOOLS,
  size,
})

export const changeDefaultTheme = (themeName) => ({
  type: CHANGE_DEFAULT_THEME,
  themeName,
})


================================================
FILE: app/components/Draggable.js
================================================
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'

const styles = {
  draggable: {
    position: 'relative',
    zIndex: 1,
    cursor: 'ns-resize',
    padding: '3px 0',
    margin: '-3px 0',
    width: '100%',
  },
}

export default class Draggable extends PureComponent {
  onMove = (evt) => {
    evt.preventDefault()
    const { onMove } = this.props
    onMove?.(evt.pageX, evt.pageY)
  }

  onUp = (evt) => {
    evt.preventDefault()
    document.removeEventListener('mousemove', this.onMove)
    document.removeEventListener('mouseup', this.onUp)
    const { onStop } = this.props
    onStop?.()
  }

  startDragging = (evt) => {
    evt.preventDefault()
    document.addEventListener('mousemove', this.onMove)
    document.addEventListener('mouseup', this.onUp)
    const { onStart } = this.props
    onStart?.()
  }

  render() {
    return (
      <div
        role="button"
        tabIndex="0"
        aria-label="Draggable"
        style={styles.draggable}
        onMouseDown={this.startDragging}
      />
    )
  }
}

Draggable.propTypes = {
  onStart: PropTypes.func,
  onMove: PropTypes.func.isRequired,
  onStop: PropTypes.func,
}

Draggable.defaultProps = {
  onStart: undefined,
  onStop: undefined,
}


================================================
FILE: app/components/FormInput.js
================================================
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'

const styles = {
  title: { textAlign: 'center' },
  form: {
    display: 'flex',
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    margin: 8,
  },
  input: {
    appearance: 'none',
    fontSize: '16px',
    margin: 2,
    padding: '8px',
    border: 0,
    borderRadius: 2,
  },
  button: {
    fontSize: '16px',
    margin: 2,
    padding: '8px',
    border: 0,
    borderRadius: 2,
  },
}

export default class FormInput extends PureComponent {
  constructor(props) {
    super(props)
    this.state = { value: undefined }
  }

  handleOnChange = (evt) => {
    const { onInputChange } = this.props
    let { value } = evt.target
    if (onInputChange) {
      value = onInputChange(value)
    }
    this.setState({ value })
  }

  handleClick = (evt) => {
    const { inputProps, onSubmit } = this.props
    const { value } = this.state
    onSubmit(evt, value || inputProps.value)
  }

  render() {
    const { title, inputProps, button } = this.props
    const { value } = this.state
    const val = typeof value !== 'undefined' ? value : inputProps.value
    return (
      <div>
        <div style={styles.title}>{title}</div>
        <div style={styles.form}>
          <input
            onKeyDown={(e) => {
              // Enter/Return key pressed
              if (e.key === 'Enter') this.handleClick()
            }}
            type={inputProps.type}
            value={val}
            style={styles.input}
            onChange={this.handleOnChange}
          />
          <button type="button" style={styles.button} onClick={this.handleClick}>
            {button}
          </button>
        </div>
      </div>
    )
  }
}

FormInput.propTypes = {
  title: PropTypes.string.isRequired,
  inputProps: PropTypes.shape({
    type: PropTypes.string,
    value: PropTypes.string,
  }),
  button: PropTypes.string,
  onInputChange: PropTypes.func,
  onSubmit: PropTypes.func.isRequired,
}

FormInput.defaultProps = {
  inputProps: { type: 'input' },
  button: 'Confirm',
  onInputChange: null,
}


================================================
FILE: app/containers/App.js
================================================
import { ipcRenderer } from 'electron'
import { getCurrentWindow } from '@electron/remote'
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import * as debuggerActionCreators from '../actions/debugger'
import * as settingActionCreators from '../actions/setting'
import ReduxDevTools from './redux/DevTools'
import ReactInspector from './ReactInspector'
import FormInput from '../components/FormInput'
import Draggable from '../components/Draggable'
import { catchConsoleLogLink } from '../../electron/devtools'

const currentWindow = getCurrentWindow()

const styles = {
  container: {
    height: '100%',
  },
  wrapBackground: {
    display: 'flex',
    height: '100%',
    flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'center',
    color: '#ccc',
    fontSize: '25px',
    WebkitUserSelect: 'none',
  },
  text: {
    textAlign: 'center',
    margin: '7px',
  },
  shortcut: {
    fontFamily: 'Monaco, monospace',
    color: '#ddd',
    backgroundColor: '#555',
    padding: '4px',
    borderRadius: '4px',
    letterSpacing: '3px',
  },
}

const shortcutPrefix = process.platform === 'darwin' ? '⌥⌘' : 'Ctrl+Alt+'

const background = (
  <div style={styles.wrapBackground}>
    <div style={styles.text}>
      <kbd style={styles.shortcut}>{`${shortcutPrefix}K`}</kbd>
      {' to toggle Redux DevTools'}
    </div>
    <div style={styles.text}>
      <kbd style={styles.shortcut}>{`${shortcutPrefix}J`}</kbd>
      {' to toggle React DevTools'}
    </div>
  </div>
)

const removeAllIPCListeners = () => {
  ipcRenderer.removeAllListeners('toggle-devtools')
  ipcRenderer.removeAllListeners('set-debugger-loc')
  ipcRenderer.removeAllListeners('sync-state')
}

class App extends Component {
  componentDidMount() {
    const { settingActions, debuggerActions } = this.props
    ipcRenderer.on('toggle-devtools', (e, name) => settingActions.toggleDevTools(name))
    ipcRenderer.on('sync-state', (event, arg) => debuggerActions.syncState(arg))
    ipcRenderer.on('set-debugger-loc', (e, payload) => {
      const location = JSON.parse(payload)
      this.setDebuggerLocation(location)
      catchConsoleLogLink(currentWindow, location.host || 'localhost', location.port)
    })
    const { debuggerState } = this.props
    if (!debuggerState.isPortSettingRequired) {
      this.setDebuggerLocation(JSON.parse(process.env.DEBUGGER_SETTING || '{}'))
    }
    window.onbeforeunload = removeAllIPCListeners
    window.notifyDevToolsThemeChange = settingActions.changeDefaultTheme
  }

  componentWillUnmount() {
    removeAllIPCListeners()
    window.notifyDevToolsThemeChange = null
  }

  onResize = (x, y) => {
    const { settingActions } = this.props
    settingActions.resizeDevTools(y / window.innerHeight)
  }

  setDebuggerLocation({ projectRoots, ...location }) {
    const { debuggerActions } = this.props
    debuggerActions.setDebuggerLocation(location)
    if (projectRoots) {
      ReactInspector.setProjectRoots(projectRoots)
    }
  }

  getReactBackgroundColor = () => {
    const { settingState } = this.props
    const { themeName } = settingState
    switch (themeName) {
      case 'dark':
        return '#242424'
      case 'default':
        return 'white'
      default:
        return 'transparent'
    }
  }

  getLayoutStyle = (size) => ({
    width: '100%',
    height: `${size * 100}%`,
    display: size ? 'inline-block' : 'none',
    backgroundColor: this.getReactBackgroundColor(),
  })

  getDevToolsSize() {
    const { settingState } = this.props
    const { redux, react, size } = settingState
    if (!redux || !react) {
      return {
        redux: redux ? 1 : 0,
        react: react ? 1 : 0,
      }
    }
    return { redux: size, react: 1 - size }
  }

  handlePortOnSubmit = (evt, port) => {
    ipcRenderer.once('check-port-available-reply', (event, available) => {
      if (!available) {
        window.alert(`The port ${port} is already used by another window.`)
        return
      }
      const { debuggerActions } = this.props
      debuggerActions.setDebuggerLocation({
        ...JSON.parse(process.env.DEBUGGER_SETTING || '{}'),
        port,
      })
      currentWindow.openDevTools()
    })
    ipcRenderer.send('check-port-available', port)
  }

  renderPortSetting() {
    return (
      <div style={styles.wrapBackground}>
        <FormInput
          title="Type in another React Native packager port"
          button="Confirm"
          inputProps={{
            type: 'input',
            value: 19000,
          }}
          onInputChange={(value) => Number(value.replace(/\D/g, '').substr(0, 5)) || ''}
          onSubmit={this.handlePortOnSubmit}
        />
      </div>
    )
  }

  renderReduxDevTools(size) {
    return (
      <div style={this.getLayoutStyle(size)}>
        <ReduxDevTools />
        <Draggable onMove={this.onResize} />
      </div>
    )
  }

  renderReactInspector(size) {
    return (
      <div style={this.getLayoutStyle(size)}>
        <ReactInspector />
      </div>
    )
  }

  render() {
    const { debuggerState } = this.props
    const { isPortSettingRequired } = debuggerState
    if (isPortSettingRequired) {
      return this.renderPortSetting()
    }
    const { redux, react } = this.getDevToolsSize()
    return (
      <div style={styles.container}>
        {this.renderReduxDevTools(redux)}
        {this.renderReactInspector(react)}
        {!react && !redux && background}
      </div>
    )
  }
}

App.propTypes = {
  settingState: PropTypes.shape({
    redux: PropTypes.bool.isRequired,
    react: PropTypes.bool.isRequired,
    size: PropTypes.number.isRequired,
    themeName: PropTypes.string.isRequired,
  }).isRequired,
  settingActions: PropTypes.shape({
    toggleDevTools: PropTypes.func.isRequired,
    resizeDevTools: PropTypes.func.isRequired,
    changeDefaultTheme: PropTypes.func.isRequired,
  }).isRequired,
  debuggerState: PropTypes.shape({
    isPortSettingRequired: PropTypes.bool.isRequired,
  }).isRequired,
  debuggerActions: PropTypes.shape({
    setDebuggerLocation: PropTypes.func.isRequired,
    syncState: PropTypes.func.isRequired,
  }).isRequired,
}

export default connect(
  (state) => ({
    debuggerState: state.debugger,
    settingState: state.setting,
  }),
  (dispatch) => ({
    debuggerActions: bindActionCreators(debuggerActionCreators, dispatch),
    settingActions: bindActionCreators(settingActionCreators, dispatch),
  }),
)(App)


================================================
FILE: app/containers/ReactInspector.js
================================================
import { connect } from 'react-redux'
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { tryADBReverse } from '../utils/adb'

let ReactServer
const getReactInspector = () => {
  if (ReactServer) return ReactServer
  // eslint-disable-next-line
  ReactServer = ReactServer || require('react-devtools-core/standalone').default;

  return ReactServer
}
const containerId = 'react-devtools-container'

const styles = {
  container: {
    display: 'flex',
    height: '100%',
    justifyContent: 'center',
    position: 'relative',
  },
  waiting: {
    height: '100%',
    display: 'flex',
    WebkitUserSelect: 'none',
    textAlign: 'center',
    color: '#aaa',
    justifyContent: 'center',
    alignItems: 'center',
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
  },
}

const isReactPanelOpen = (props) => props.settingState.react

class ReactInspector extends Component {
  static setProjectRoots(projectRoots) {
    getReactInspector().setProjectRoots(projectRoots)
  }

  listeningPort = window.reactDevToolsPort

  componentDidMount() {
    const { debuggerState } = this.props
    const { worker } = debuggerState
    if (worker) {
      this.server = this.startServer()
      worker.addEventListener('message', this.workerOnMessage)
    }
  }

  UNSAFE_componentWillReceiveProps(nextProps) {
    const { debuggerState } = this.props
    const { worker } = debuggerState
    const { worker: nextWorker } = nextProps.debuggerState
    if (nextWorker && nextWorker !== worker) {
      this.closeServerIfExists()
      if (isReactPanelOpen(this.props)) {
        this.server = this.startServer()
      }
      nextWorker.addEventListener('message', this.workerOnMessage)
    } else if (!nextWorker) {
      this.closeServerIfExists()
    }
    // Open / Close server when react panel opened / hidden
    if (!worker && !nextWorker) return
    if (isReactPanelOpen(this.props) && !isReactPanelOpen(nextProps)) {
      this.closeServerIfExists()
    } else if (!isReactPanelOpen(this.props) && isReactPanelOpen(nextProps)) {
      this.closeServerIfExists()
      this.server = this.startServer()
    }
  }

  shouldComponentUpdate() {
    return false
  }

  componentWillUnmount() {
    this.closeServerIfExists()
  }

  workerOnMessage = (message) => {
    const { data } = message
    if (!data || !data.__REPORT_REACT_DEVTOOLS_PORT__) return

    const port = Number(data.__REPORT_REACT_DEVTOOLS_PORT__)
    const { platform } = data
    if (port && port !== this.listeningPort) {
      this.listeningPort = port
      this.closeServerIfExists()
      if (isReactPanelOpen(this.props)) {
        this.server = this.startServer(port)
      }
      if (platform === 'android') tryADBReverse(port).catch(() => {})
    }
  }

  closeServerIfExists = () => {
    if (this.server) {
      this.server.close()
      this.server = null
    }
  }

  startServer(port = this.listeningPort) {
    let loggedWarn = false

    return getReactInspector()
      .setStatusListener((status) => {
        if (!loggedWarn && status === 'Failed to start the server.') {
          const message = port !== 8097
            ? 're-open the debugger window might be helpful.'
            : 'we recommended to upgrade React Native version to 0.39+ for random port support.'
          console.error(
            '[RNDebugger]',
            `Failed to start React DevTools server with port \`${port}\`,`,
            'because another server is listening,',
            message,
          )
          loggedWarn = true
        }
      })
      .setContentDOMNode(document.getElementById(containerId))
      .startServer(port)
  }

  render() {
    return (
      <div id={containerId} style={styles.container}>
        <div id="waiting" style={styles.waiting}>
          <h2>Waiting for React to connect…</h2>
        </div>
      </div>
    )
  }
}

ReactInspector.propTypes = {
  debuggerState: PropTypes.shape({
    worker: PropTypes.shape({
      addEventListener: PropTypes.func.isRequired,
    }),
  }).isRequired,
}

export default connect(
  (state) => ({
    settingState: state.setting,
    debuggerState: state.debugger,
  }),
  (dispatch) => ({ dispatch }),
)(ReactInspector)


================================================
FILE: app/containers/redux/DevTools.js
================================================
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import styled from 'styled-components'
import { Container, Notification } from '@redux-devtools/ui'
import { clearNotification } from '@redux-devtools/app/lib/esm/actions'
import Actions from '@redux-devtools/app/lib/esm/containers/Actions'
import Settings from './Settings'
import Header from './Header'

const StyledContainer = styled(Container)`overflow: hidden;`

function App() {
  const section = useSelector((state) => state.section)
  const theme = useSelector((state) => state.theme)
  const notification = useSelector((state) => state.notification)

  const dispatch = useDispatch()

  let body
  switch (section) {
    case 'Settings':
      body = <Settings />
      break
    default:
      body = <Actions />
  }

  return (
    <StyledContainer themeData={theme}>
      <Header section={section} />
      {body}
      {notification && (
        <Notification
          type={notification.type}
          onClose={() => dispatch(clearNotification())}
        >
          {notification.message}
        </Notification>
      )}
    </StyledContainer>
  )
}

export default App


================================================
FILE: app/containers/redux/Header.js
================================================
import React, { useCallback } from 'react'
import PropTypes from 'prop-types'
import { useDispatch } from 'react-redux'
import {
  Tabs, Toolbar, Button, Divider,
} from '@redux-devtools/ui'
import { GoBook } from 'react-icons/go'
import styled from 'styled-components'
import { changeSection } from '@redux-devtools/app/lib/esm/actions'
import { shell } from 'electron'

const WindowDraggable = styled.div`
  display: flex;
  flex: 1;
  height: 100%;
  -webkit-app-region: drag;
  -webkit-user-select: none;
`

const tabs = [{ name: 'Actions' }, { name: 'Settings' }]

function Header(props) {
  const { section } = props

  const dispatch = useDispatch()

  const handleChangeSection = useCallback(
    (sec) => dispatch(changeSection(sec)),
    [dispatch, changeSection],
  )

  const openHelp = useCallback(() => shell.openExternal('https://goo.gl/SHU4yL'), [])

  return (
    <Toolbar compact noBorder borderPosition="bottom">
      <Tabs
        main
        collapsible
        tabs={tabs}
        onClick={handleChangeSection}
        selected={section || 'Actions'}
        style={{ flex: 'unset' }}
      />
      <WindowDraggable />
      <Divider />
      <Button
        title="Documentation"
        tooltipPosition="bottom"
        onClick={openHelp}
      >
        <GoBook />
      </Button>
    </Toolbar>
  )
}

Header.propTypes = {
  section: PropTypes.string.isRequired,
}

export default Header


================================================
FILE: app/containers/redux/Settings.js
================================================
/* eslint-disable import/no-named-as-default */
import React, { Component } from 'react'
import Tabs from '@redux-devtools/ui/lib/esm/Tabs/Tabs'
import Themes from '@redux-devtools/app/lib/esm/components/Settings/Themes'

export default class Settings extends Component {
  tabs = [
    { name: 'Themes', component: Themes },
  ]

  constructor(props) {
    super(props)
    this.state = { selected: 'Themes' }
  }

  handleSelect = (selected) => {
    this.setState({ selected })
  }

  render() {
    const { selected } = this.state
    return (
      <Tabs
        tabs={this.tabs}
        selected={selected}
        onClick={this.handleSelect}
      />
    )
  }
}


================================================
FILE: app/globalStyles.js
================================================
import { css, createGlobalStyle } from 'styled-components'

const commonStyles = css``

export const GlobalStyle =
  process.platform !== 'darwin'
    ? createGlobalStyle`
        ${commonStyles}
        ::-webkit-scrollbar {
          width: 8px;
          height: 8px;
          background-color: #95959588;
        }
        ::-webkit-scrollbar-thumb {
          background-color: #33333366;
        }
      `
    : createGlobalStyle`${commonStyles}`


================================================
FILE: app/index.js
================================================
import { findAPortNotInUse } from 'portscanner'
import { webFrame } from 'electron'
import { getCurrentWindow } from '@electron/remote'
import React from 'react'
import { createRoot } from 'react-dom/client'
import { Provider } from 'react-redux'
import launchEditor from 'react-dev-utils/launchEditor'
import { PersistGate } from 'redux-persist/integration/react'
import './setup'
import App from './containers/App'
import configureStore from './store/configureStore'
import { beforeWindowClose } from './actions/debugger'
import { invokeDevMethod } from './utils/devMenu'
import { client, tryADBReverse } from './utils/adb'
import config from './utils/config'
import { toggleOpenInEditor, isOpenInEditorEnabled } from './utils/devtools'
import { GlobalStyle } from './globalStyles'

const currentWindow = getCurrentWindow()

webFrame.setZoomFactor(1)
webFrame.setVisualZoomLevelLimits(1, 1)

// Prevent dropped file
document.addEventListener('drop', (e) => {
  e.preventDefault()
  e.stopPropagation()
})
document.addEventListener('dragover', (e) => {
  e.preventDefault()
  e.stopPropagation()
})

let store
let persistor
const handleReady = () => {
  const { defaultReactDevToolsPort = 19567 } = config
  findAPortNotInUse(Number(defaultReactDevToolsPort)).then((port) => {
    window.reactDevToolsPort = port
    const root = createRoot(document.getElementById('root'))
    root.render(
      <>
        <GlobalStyle />
        <Provider store={store}>
          <PersistGate loading={null} persistor={persistor}>
            <App />
          </PersistGate>
        </Provider>
      </>,
    )
  })
}

;({ store, persistor } = configureStore(handleReady))

// Provide for user
window.adb = client
window.adb.reverseAll = tryADBReverse
window.adb.reversePackager = () =>
  tryADBReverse(store.getState().debugger.location.port)

window.checkWindowInfo = () => {
  const debuggerState = store.getState().debugger
  return {
    isWorkerRunning: !!debuggerState.worker,
    location: debuggerState.location,
    isPortSettingRequired: debuggerState.isPortSettingRequired,
  }
}

window.beforeWindowClose = () =>
  new Promise((resolve) => {
    if (store.dispatch(beforeWindowClose())) {
      setTimeout(resolve, 200)
    } else {
      resolve()
    }
  })

// For security, we should disable nodeIntegration when user use this open a website
const originWindowOpen = window.open
window.open = (url, frameName, features = '') => {
  const featureList = features.split(',')
  featureList.push('nodeIntegration=0')
  return originWindowOpen.call(window, url, frameName, featureList.join(','))
}

window.openInEditor = (file, lineNumber) => launchEditor(file, lineNumber)
window.toggleOpenInEditor = () => {
  const { port } = store.getState().debugger.location
  return toggleOpenInEditor(currentWindow, port)
}
window.isOpenInEditorEnabled = () => isOpenInEditorEnabled(currentWindow)

window.invokeDevMethod = (name) => invokeDevMethod(name)()

// Package will missing /usr/local/bin,
// we need fix it for ensure child process work
// (like launchEditor of react-devtools)
if (
  process.env.NODE_ENV === 'production' &&
  process.platform === 'darwin' &&
  process.env.PATH.indexOf('/usr/local/bin') === -1
) {
  process.env.PATH = `${process.env.PATH}:/usr/local/bin`
}


================================================
FILE: app/middlewares/debuggerAPI.js
================================================
/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

// Take from https://github.com/facebook/react-native/blob/master/local-cli/server/util/debugger.html

import { getCurrentWindow } from '@electron/remote'
import { bindActionCreators } from 'redux'
import { checkPortStatus } from 'portscanner'
import * as debuggerActions from '../actions/debugger'
import { setDevMenuMethods, networkInspect } from '../utils/devMenu'
import { tryADBReverse } from '../utils/adb'
import { clearNetworkLogs, selectRNDebuggerWorkerContext } from '../utils/devtools'
import config from '../utils/config'

const currentWindow = getCurrentWindow()
const { SET_DEBUGGER_LOCATION, BEFORE_WINDOW_CLOSE } = debuggerActions

let worker
let queuedMessages = []
let scriptExecuted = false
let actions
let host
let port
let socket

const APOLLO_MESSAGE_PREFIX = 'ac-devtools:'

const workerOnMessage = (message) => {
  const { data } = message

  if (data && data.message?.startsWith(APOLLO_MESSAGE_PREFIX)) {
    data.__FROM_DEBUGGER_WORKER__ = true
    postMessage(data, '*')
    return false
  }

  if (data && (data.__IS_REDUX_NATIVE_MESSAGE__ || data.__REPORT_REACT_DEVTOOLS_PORT__)) {
    return true
  }
  const list = data && data.__AVAILABLE_METHODS_CAN_CALL_BY_RNDEBUGGER__
  if (list) {
    setDevMenuMethods(list, worker)
    return false
  }
  socket.send(JSON.stringify(data))
}

const onWindowMessage = (e) => {
  const { data } = e
  if (
    !data?.__FROM_DEBUGGER_WORKER__ &&
    data?.message?.startsWith(APOLLO_MESSAGE_PREFIX)
  ) {
    worker.postMessage({
      method: 'emitApolloMessage',
      ...data,
    })
    return false
  }
}

const createJSRuntime = () => {
  // This worker will run the application javascript code,
  // making sure that it's run in an environment without a global
  // document, to make it consistent with the JSC executor environment.
  // eslint-disable-next-line
  worker = new Worker(`${__webpack_public_path__}RNDebuggerWorker.js`);
  worker.addEventListener('message', workerOnMessage)
  window.addEventListener('message', onWindowMessage)
  actions.setDebuggerWorker(worker, 'connected')
}

const shutdownJSRuntime = () => {
  const { setDebuggerWorker } = actions
  scriptExecuted = false
  if (worker) {
    worker.terminate()
    window.removeEventListener('message', onWindowMessage)
    setDevMenuMethods([])
  }
  worker = null
  setDebuggerWorker(null, 'disconnected')
}

const isScriptBuildForAndroid = (url) => url && (url.indexOf('.android.bundle') > -1 || url.indexOf('platform=android') > -1)

let preconnectTimeout
const preconnect = async (fn, firstTimeout) => {
  if (firstTimeout || (await checkPortStatus(port, host)) !== 'open') {
    preconnectTimeout = setTimeout(() => preconnect(fn), 500)
    return
  }
  socket = await fn()
}

const clearLogs = () => {
  if (process.env.NODE_ENV !== 'development') {
    console.clear()
    clearNetworkLogs(currentWindow)
  }
}

const flushQueuedMessages = () => {
  if (!worker) return
  // Flush any messages queued up and clear them
  queuedMessages.forEach((message) => worker.postMessage(message))
  queuedMessages = []
}

let loadCount = 0
const checkJSLoadCount = () => {
  loadCount += 1
  if (
    currentWindow.webContents.isDevToolsOpened()
    && config.timesJSLoadToRefreshDevTools >= 0
    && loadCount > 0
    && loadCount % config.timesJSLoadToRefreshDevTools === 0
  ) {
    currentWindow.webContents.closeDevTools()
    currentWindow.webContents.openDevTools()
    console.warn(
      '[RNDebugger]',
      `Refreshed the devtools panel as React Native app was reloaded ${loadCount} times.`,
      'If you want to update or disable this,',
      'Open `Debugger` -> `Open Config File` to change `timesJSLoadToRefreshDevTools` field.',
    )
    loadCount = 0
  }
}

const connectToDebuggerProxy = async () => {
  const ws = new WebSocket(`ws://${host}:${port}/debugger-proxy?role=debugger&name=Chrome`)

  const { setDebuggerStatus } = actions
  ws.onopen = () => setDebuggerStatus('waiting')
  ws.onmessage = async (message) => {
    if (!message.data) return

    const object = JSON.parse(message.data)
    if (object.$event === 'client-disconnected') {
      shutdownJSRuntime()
      return
    }
    if (!object.method) return

    // Special message that asks for a new JS runtime
    if (object.method === 'prepareJSRuntime') {
      shutdownJSRuntime()
      createJSRuntime()
      clearLogs()
      selectRNDebuggerWorkerContext(currentWindow)
      ws.send(JSON.stringify({ replyID: object.id }))
    } else if (object.method === '$disconnected') {
      shutdownJSRuntime()
    } else {
      if (!worker) return
      if (object.method === 'executeApplicationScript') {
        object.networkInspect = networkInspect.isEnabled()
        object.reactDevToolsPort = window.reactDevToolsPort
        if (isScriptBuildForAndroid(object.url)) {
          // Reserve React Inspector port for debug via USB on Android real device
          tryADBReverse(window.reactDevToolsPort).catch(() => {})
        }
        // Clear logs even if no error catched
        clearLogs()
        scriptExecuted = true
        checkJSLoadCount()
      }
      if (scriptExecuted) {
        // Otherwise, pass through to the worker provided the
        // application script has been executed. If not add
        // it to a queue until it has been executed.
        worker.postMessage(object)
        flushQueuedMessages()
      } else {
        queuedMessages.push(object)
      }
    }
  }

  ws.onerror = () => {}
  ws.onclose = (e) => {
    shutdownJSRuntime()
    if (e.reason) {
      console.warn(e.reason)
    }
    preconnect(connectToDebuggerProxy, true)
  }
  return ws
}

const setDebuggerLoc = ({ host: packagerHost, port: packagerPort }) => {
  if (host === packagerHost && port === Number(packagerPort)) return

  host = packagerHost || 'localhost'
  port = packagerPort || config.port || 8081
  if (socket) {
    shutdownJSRuntime()
    socket.close()
  } else {
    // Should ensure cleared timeout if called preconnect twice
    clearTimeout(preconnectTimeout)
    preconnect(connectToDebuggerProxy)
  }
}

export default ({ dispatch }) => {
  actions = bindActionCreators(debuggerActions, dispatch)

  return (next) => (action) => {
    if (action.type === SET_DEBUGGER_LOCATION) {
      setDebuggerLoc(action.loc)
    }
    if (action.type === BEFORE_WINDOW_CLOSE) {
      // Return boolean instead of handle reducer
      if (!worker) return false
      worker.postMessage({ method: 'beforeTerminate' })
      return true
    }
    return next(action)
  }
}


================================================
FILE: app/middlewares/reduxAPI.js
================================================
import { bindActionCreators } from 'redux'
import { ipcRenderer } from 'electron'
import { getGlobal } from '@electron/remote'

import { UPDATE_STATE, LIFTED_ACTION } from '@redux-devtools/app/lib/esm/constants/actionTypes'
import { DISCONNECTED } from '@redux-devtools/app/lib/esm/constants/socketActionTypes'
import { nonReduxDispatch } from '@redux-devtools/app/lib/esm/utils/monitorActions'
import { showNotification, liftedDispatch } from '@redux-devtools/app/lib/esm/actions'
import { getActiveInstance } from '@redux-devtools/app/lib/esm/reducers/instances'

import { SET_DEBUGGER_WORKER, SYNC_STATE } from '../actions/debugger'
import { setReduxDevToolsMethods, updateSliderContent } from '../utils/devMenu'

const unboundActions = {
  showNotification,
  updateState: (request) => ({
    type: UPDATE_STATE,
    request: request.data ? { ...request.data, id: request.id } : request,
  }),
  liftedDispatch,
}
let actions
let worker
let store

const toWorker = ({
  message, action, state, toAll,
}) => {
  if (!worker) return

  const { instances } = store.getState()
  const instanceId = getActiveInstance(instances)
  const id = instances.options[instanceId].connectionId
  worker.postMessage({
    method: 'emitReduxMessage',
    content: {
      type: message,
      action,
      state: nonReduxDispatch(store, message, instanceId, action, state, instances),
      instanceId,
      id,
      toAll,
    },
  })
}

const postImportMessage = (state) => {
  if (!worker) return

  const { instances } = store.getState()
  const instanceId = getActiveInstance(instances)
  const id = instances.options[instanceId].connectionId
  worker.postMessage({
    method: 'emitReduxMessage',
    content: {
      type: 'IMPORT',
      state,
      instanceId,
      id,
    },
  })
}

// Receive messages from worker
const messaging = (message) => {
  const { data } = message
  if (!data || !data.__IS_REDUX_NATIVE_MESSAGE__) return

  const { content: request } = data
  if (request.type === 'ERROR') {
    actions.showNotification(request.payload)
    return
  }
  actions.updateState(request)
}

const initWorker = (wkr) => {
  wkr.addEventListener('message', messaging)
  worker = wkr
}

const removeWorker = () => {
  worker = null
}

const syncLiftedState = (liftedState) => {
  if (!getGlobal('isSyncState')()) return

  const { actionsById } = liftedState
  const payload = []
  liftedState.stagedActionIds.slice(1).forEach((id) => {
    payload.push(actionsById[id].action)
  })
  const serialized = JSON.stringify({ payload: JSON.stringify(payload) })
  ipcRenderer.send('sync-state', serialized)
}

export default (inStore) => {
  store = inStore
  actions = bindActionCreators(unboundActions, store.dispatch)
  return (next) => (action) => {
    if (action.type === SET_DEBUGGER_WORKER) {
      if (action.worker) {
        initWorker(action.worker)
      } else {
        removeWorker(action.worker)
        setReduxDevToolsMethods(false)
        next({ type: DISCONNECTED })
      }
    }
    if (action.type === LIFTED_ACTION) {
      toWorker(action)
    }
    if (
      action.type === UPDATE_STATE
      || action.type === LIFTED_ACTION
      || action.type === SYNC_STATE
    ) {
      next(action)
      const state = store.getState()
      const { instances } = state
      const id = getActiveInstance(instances)
      const liftedState = instances.states[id]
      if (liftedState && liftedState.computedStates.length > 1) {
        setReduxDevToolsMethods(true, actions.liftedDispatch)
      } else if (liftedState && liftedState.computedStates.length <= 1) {
        setReduxDevToolsMethods(false)
      }
      updateSliderContent(liftedState, action.action && action.action.dontUpdateTouchBarSlider)
      if (action.request && action.request.type === 'ACTION') {
        syncLiftedState(liftedState)
      }
      if (action.type === SYNC_STATE) {
        postImportMessage(action.payload)
      }
      return
    }
    return next(action)
  }
}


================================================
FILE: app/reducers/debugger.js
================================================
import {
  SET_DEBUGGER_STATUS,
  SET_DEBUGGER_WORKER,
  SET_DEBUGGER_LOCATION,
} from '../actions/debugger'
import config from '../utils/config'

function getStatusMessage(status, port) {
  let message
  switch (status) {
    case 'new':
      message = 'New Window'
      break
    case 'waiting':
      message = 'Waiting for client connection'
      break
    case 'connected':
      message = 'Connected'
      break
    case 'disconnected':
    default:
      message = 'Attempting reconnection'
  }
  if (status !== 'new') {
    message += ` (port ${port})`
  }
  const title = `React Native Debugger - ${message}`
  if (title !== document.title) {
    document.title = title
  }
  return message
}

const initialState = {
  worker: null,
  status: 'disconnected',
  statusMessage: getStatusMessage(config.isPortSettingRequired ? 'new' : 'disconnected', 8081),
  location: {
    host: 'localhost',
    port: config.port || 8081,
  },
  isPortSettingRequired: config.isPortSettingRequired,
}

const actionsMap = {
  [SET_DEBUGGER_STATUS]: (state, action) => {
    const status = action.status || initialState.status
    const newState = {
      ...state,
      status,
      statusMessage: getStatusMessage(status, state.location.port),
    }
    return newState
  },
  [SET_DEBUGGER_WORKER]: (state, action) => {
    const status = action.status || initialState.status
    const newState = {
      ...state,
      worker: action.worker,
      status,
      statusMessage: getStatusMessage(status, state.location.port),
    }
    return newState
  },
  [SET_DEBUGGER_LOCATION]: (state, action) => {
    const location = { ...state.location, ...action.loc }
    const newState = {
      ...state,
      location,
      statusMessage: getStatusMessage(state.status, location.port),
      isPortSettingRequired: false,
    }
    return newState
  },
}

export default (state = initialState, action = {}) => {
  const reduceFn = actionsMap[action.type]
  if (!reduceFn) return state
  return reduceFn(state, action)
}


================================================
FILE: app/reducers/index.js
================================================
import { combineReducers } from 'redux'
import { section } from '@redux-devtools/app/lib/esm/reducers/section'
// import { connection } from '@redux-devtools/app/lib/esm/reducers/connection';
// import { socket } from '@redux-devtools/app/lib/esm/reducers/socket';
import { monitor } from '@redux-devtools/app/lib/esm/reducers/monitor'
import { notification } from '@redux-devtools/app/lib/esm/reducers/notification'
import { instances } from '@redux-devtools/app/lib/esm/reducers/instances'
import { reports } from '@redux-devtools/app/lib/esm/reducers/reports'
import { theme } from '@redux-devtools/app/lib/esm/reducers/theme'

import setting from './setting'
import debuggerReducer from './debugger'

export default combineReducers({
  section,
  instances,
  reports,
  theme,
  monitor,
  notification,

  setting,
  debugger: debuggerReducer,
})


================================================
FILE: app/reducers/setting.js
================================================
import { TOGGLE_DEVTOOLS, RESIZE_DEVTOOLS, CHANGE_DEFAULT_THEME } from '../actions/setting'

const initialState = {
  react: true,
  redux: true,
  size: 0.6,
  themeName: null,
}

const actionsMap = {
  [TOGGLE_DEVTOOLS]: (state, action) => ({
    ...state,
    [action.name]: !state[action.name],
  }),
  [RESIZE_DEVTOOLS]: (state, action) => {
    if (!state.redux || !state.react) {
      return state
    }
    const { size } = action
    if (size < 0.2) return { ...state, size: 0.2 }
    if (size > 0.8) return { ...state, size: 0.8 }
    return { ...state, size }
  },
  [CHANGE_DEFAULT_THEME]: (state, action) => ({
    ...state,
    themeName: action.themeName,
  }),
}

export default (state = initialState, action = {}) => {
  const reduceFn = actionsMap[action.type]
  if (!reduceFn) return state
  return reduceFn(state, action)
}


================================================
FILE: app/setup.js
================================================
import config from './utils/config'

if (config.editor) {
  process.env.EDITOR = config.editor
}

if (config.fontFamily) {
  const styleEl = document.createElement('style')
  document.head.appendChild(styleEl)
  styleEl.sheet.insertRule(
    `div *, span * { font-family: ${config.fontFamily} !important; }`,
    0,
  )
}


================================================
FILE: app/store/configureStore.js
================================================
import { createStore, applyMiddleware, compose } from 'redux'
import { persistReducer, persistStore } from 'redux-persist'
import localForage from 'localforage'
import { exportStateMiddleware } from '@redux-devtools/app/lib/cjs/middlewares/exportState'
import { instancesInitialState } from '@redux-devtools/app/lib/esm/reducers/instances'
import debuggerAPI from '../middlewares/debuggerAPI'
import reduxAPI from '../middlewares/reduxAPI'
import rootReducer from '../reducers'

const persistConfig = {
  key: 'redux-devtools',
  blacklist: ['instances', 'debugger'],
  storage: localForage,
}

const persistedReducer = persistReducer(persistConfig, rootReducer)

const middlewares = applyMiddleware(
  debuggerAPI,
  exportStateMiddleware,
  reduxAPI,
)

// If Redux DevTools Extension is installed use it, otherwise use Redux compose
/* eslint-disable no-underscore-dangle */
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
/* eslint-enable no-underscore-dangle */
const enhancer = composeEnhancers(middlewares)

const initialState = {
  instances: {
    ...instancesInitialState,
    selected: '',
  },
}

export default (callback) => {
  const store = createStore(persistedReducer, initialState, enhancer)
  const persistor = persistStore(store, null, () => callback?.(store))
  return { store, persistor }
}


================================================
FILE: app/utils/adb.js
================================================
import adb from 'adbkit'

export const client = adb.createClient({ host: '127.0.0.1' })

const reverse = (device, port) => client.reverse(device, `tcp:${port}`, `tcp:${port}`)

export const tryADBReverse = async (port) => {
  const devices = await client.listDevices().filter((device) => device.type === 'device')
  return Promise.all(devices.map((device) => reverse(device.id, port)))
}


================================================
FILE: app/utils/config.js
================================================
import { getCurrentWindow } from '@electron/remote'

export default getCurrentWindow().debuggerConfig || {}


================================================
FILE: app/utils/devMenu.js
================================================
import { TouchBar, nativeImage, getCurrentWindow } from '@electron/remote'

import { ipcRenderer } from 'electron'
import config from './config'

const { TouchBarButton, TouchBarSlider } = TouchBar || {}
const currentWindow = getCurrentWindow()

let worker
let availableMethods = []

/* reload, toggleElementInspector, networkInspect */
let leftBar = {}

let isSliderEnabled
let storeLiftedState
/* slider, prev, next */
let rightBar = {}

const getBarItems = (bar) => Object.keys(bar)
  .map((key) => bar[key])
  .filter((barItem) => !!barItem)
const setTouchBar = () => currentWindow.setTouchBar(
  new TouchBar({
    items: [
      ...getBarItems(leftBar),
      ...(isSliderEnabled ? getBarItems(rightBar) : []),
    ],
  }),
)

const invokeDevMenuMethod = ({ name, args }) => worker && worker.postMessage({ method: 'invokeDevMenuMethod', name, args })

let networkInspectEnabled = !!config.networkInspect
const sendContextMenuUpdate = () => {
  ipcRenderer.send(`context-menu-available-methods-update-${currentWindow.id}`, {
    availableMethods,
    networkInspectEnabled,
  })
}

export const networkInspect = {
  isEnabled: () => !!networkInspectEnabled,
  getHighlightColor: () => (networkInspectEnabled ? '#7A7A7A' : '#363636'),
  toggle() {
    networkInspectEnabled = !networkInspectEnabled
    sendContextMenuUpdate()
  },
}

const devMenuMethods = {
  reload: () => invokeDevMenuMethod({ name: 'reload' }),
  toggleElementInspector: () => invokeDevMenuMethod({ name: 'toggleElementInspector' }),
  show: () => invokeDevMenuMethod({ name: 'show' }),
  networkInspect: () => {
    networkInspect.toggle()
    if (leftBar.networkInspect) {
      leftBar.networkInspect.backgroundColor = networkInspect.getHighlightColor()
    }
    invokeDevMenuMethod({
      name: 'networkInspect',
      args: [networkInspectEnabled],
    })
  },
  showAsyncStorage: () => {
    invokeDevMenuMethod({ name: 'showAsyncStorage' })
  },
  clearAsyncStorage: () => {
    if (
      window.confirm(
        'Call `AsyncStorage.clear()` in current React Native debug session?',
      )
    ) {
      invokeDevMenuMethod({ name: 'clearAsyncStorage' })
    }
  },
}

export const invokeDevMethod = (name) => () => {
  if (availableMethods.includes(name)) {
    return devMenuMethods[name]()
  }
}

const hslShift = [0.5, 0.2, 0.8]
const icon = (name, resizeOpts) => {
  const image = nativeImage.createFromNamedImage(name, hslShift)
  return image.resize(resizeOpts)
}

let namedImages
const initNamedImages = () => {
  if (process.platform !== 'darwin' || namedImages) return
  namedImages = {
    reload: icon('NSTouchBarRefreshTemplate', { height: 20 }),
    toggleElementInspector: icon('NSTouchBarQuickLookTemplate', { height: 18 }),
    networkInspect: icon('NSTouchBarRecordStartTemplate', { height: 20 }),
    prev: icon('NSTouchBarGoBackTemplate', { height: 20 }),
    next: icon('NSTouchBarGoForwardTemplate', { height: 20 }),
  }
}

const setDevMenuMethodsForTouchBar = () => {
  if (process.platform !== 'darwin') return
  initNamedImages()

  leftBar = {
    // Default items
    networkInspect: new TouchBarButton({
      icon: namedImages.networkInspect,
      click: devMenuMethods.networkInspect,
      backgroundColor: networkInspect.getHighlightColor(),
    }),
  }
  if (availableMethods.includes('reload')) {
    leftBar.reload = new TouchBarButton({
      icon: namedImages.reload,
      click: devMenuMethods.reload,
    })
  }
  if (availableMethods.includes('toggleElementInspector')) {
    leftBar.toggleElementInspector = new TouchBarButton({
      icon: namedImages.toggleElementInspector,
      click: devMenuMethods.toggleElementInspector,
    })
  }
  setTouchBar()
}

// Reset TouchBar when reload the app
setDevMenuMethodsForTouchBar([])

export const setDevMenuMethods = (list, wkr) => {
  worker = wkr
  availableMethods = list
  sendContextMenuUpdate()
  setDevMenuMethodsForTouchBar()
}

export const setReduxDevToolsMethods = (enabled, dispatch) => {
  if (process.platform !== 'darwin') return
  initNamedImages()

  // Already setup
  if (enabled && isSliderEnabled) return

  const handleSliderChange = (nextIndex, dontUpdateTouchBarSlider = false) => dispatch({
    type: 'JUMP_TO_STATE',
    actionId: storeLiftedState.stagedActionIds[nextIndex],
    index: nextIndex,
    dontUpdateTouchBarSlider,
  })

  rightBar = {
    slider: new TouchBarSlider({
      value: 0,
      minValue: 0,
      maxValue: 0,
      change(nextIndex) {
        if (nextIndex !== storeLiftedState.currentStateIndex) {
          // Set `dontUpdateTouchBarSlider` true for keep slide experience
          handleSliderChange(nextIndex, true)
        }
      },
    }),
    prev: new TouchBarButton({
      icon: namedImages.prev,
      click() {
        const nextIndex = storeLiftedState.currentStateIndex - 1
        if (nextIndex >= 0) {
          handleSliderChange(nextIndex)
        }
      },
    }),
    next: new TouchBarButton({
      icon: namedImages.next,
      click() {
        const nextIndex = storeLiftedState.currentStateIndex + 1
        if (nextIndex < storeLiftedState.computedStates.length) {
          handleSliderChange(nextIndex)
        }
      },
    }),
  }
  isSliderEnabled = enabled
  setTouchBar()
}

export const updateSliderContent = (liftedState, dontUpdateTouchBarSlider) => {
  if (process.platform !== 'darwin') return

  storeLiftedState = liftedState
  if (isSliderEnabled && !dontUpdateTouchBarSlider) {
    const { currentStateIndex, computedStates } = liftedState
    rightBar.slider.maxValue = computedStates.length - 1
    rightBar.slider.value = currentStateIndex
  }
}


================================================
FILE: app/utils/devtools.js
================================================
import { getCatchConsoleLogScript } from '../../electron/devtools'

let enabled = false
export const toggleOpenInEditor = (win, port) => {
  if (win.devToolsWebContents) {
    enabled = !enabled
    return win.devToolsWebContents.executeJavaScript(`(() => {
      ${getCatchConsoleLogScript(port)}
      window.__IS_OPEN_IN_EDITOR_ENABLED__ = ${enabled};
    })()`)
  }
}

export const isOpenInEditorEnabled = () => enabled

export const clearNetworkLogs = (win) => {
  if (win.devToolsWebContents) {
    return win.devToolsWebContents.executeJavaScript(`setTimeout(() => {
      const { network } = UI.panels;
      if (network && network.networkLogView && network.networkLogView.reset) {
        network.networkLogView.reset()
      }
    }, 100)`)
  }
}

export const selectRNDebuggerWorkerContext = (win) => {
  if (win.devToolsWebContents) {
    return win.devToolsWebContents.executeJavaScript(`setTimeout(() => {
      const { console } = UI.panels;
      if (console && console.view && console.view.consoleContextSelector) {
        const selector = console.view.consoleContextSelector;
        const item = selector.items.items.find(
          item => item.label() === 'RNDebuggerWorker.js'
        );
        if (item) {
          selector.itemSelected(item);
        }
      }
    }, 100)`)
  }
}


================================================
FILE: app/worker/.eslintrc
================================================
{
  "rules": {
    "no-restricted-globals": "off"
  }
}

================================================
FILE: app/worker/apollo.js
================================================

export function handleApolloClient() {
  // eslint-disable-next-line global-require
  require('apollo-client-devtools/build/hook')
}


================================================
FILE: app/worker/asyncStorage.js
================================================
export const getClearAsyncStorageFn = (AsyncStorage) => {
  if (!AsyncStorage.clear) return
  return () => AsyncStorage.clear().catch((f) => f)
}

function convertError(error) {
  if (!error) {
    return null
  }
  const out = new Error(error.message)
  out.key = error.key
  return out
}

function convertErrors(errs) {
  if (!errs) {
    return null
  }
  return (Array.isArray(errs) ? errs : [errs]).map((e) => convertError(e))
}

export const getSafeAsyncStorage = (NativeModules) => {
  const RCTAsyncStorage = NativeModules
    && (NativeModules.RNC_AsyncSQLiteDBStorage
      || NativeModules.RNCAsyncStorage
      || NativeModules.PlatformLocalStorage
      || NativeModules.AsyncRocksDBStorage
      || NativeModules.AsyncSQLiteDBStorage
      || NativeModules.AsyncLocalStorage)

  return {
    getItem(key) {
      if (!RCTAsyncStorage) return Promise.resolve(null)
      return new Promise((resolve, reject) => {
        RCTAsyncStorage.multiGet([key], (errors, result) => {
          // Unpack result to get value from [[key,value]]
          const value = result && result[0] && result[0][1] ? result[0][1] : null
          const errs = convertErrors(errors)
          if (errs) {
            reject(errs[0])
          } else {
            resolve(value)
          }
        })
      })
    },
    async setItem(key, value) {
      if (!RCTAsyncStorage) return Promise.resolve(null)
      return new Promise((resolve, reject) => {
        RCTAsyncStorage.multiSet([[key, value]], (errors) => {
          const errs = convertErrors(errors)
          if (errs) {
            reject(errs[0])
          } else {
            resolve(null)
          }
        })
      })
    },
    clear() {
      if (!RCTAsyncStorage) return Promise.resolve(null)
      return new Promise((resolve, reject) => {
        RCTAsyncStorage.clear((error) => {
          if (error && convertError(error)) {
            reject(convertError(error))
          } else {
            resolve(null)
          }
        })
      })
    },
    getAllKeys() {
      if (!RCTAsyncStorage) return Promise.resolve(null)
      return new Promise((resolve, reject) => {
        RCTAsyncStorage.getAllKeys((error, keys) => {
          if (error) {
            reject(convertError(error))
          } else {
            resolve(keys)
          }
        })
      })
    },
  }
}

export const getShowAsyncStorageFn = (AsyncStorage) => {
  if (!AsyncStorage.getAllKeys || !AsyncStorage.getItem) return
  return async () => {
    const keys = await AsyncStorage.getAllKeys()
    if (keys && keys.length) {
      const items = await Promise.all(
        keys.map((key) => AsyncStorage.getItem(key)),
      )
      const table = {}
      keys.forEach((key, index) => {
        table[key] = { content: items[index] }
      })
      console.table(table)
    } else {
      console.log('[RNDebugger] No AsyncStorage content.')
    }
  }
}


================================================
FILE: app/worker/devMenu.js
================================================
/* eslint-disable no-underscore-dangle */

import { toggleNetworkInspect } from './networkInspect'
import { getClearAsyncStorageFn, getShowAsyncStorageFn, getSafeAsyncStorage } from './asyncStorage'

let availableDevMenuMethods = {}

export const checkAvailableDevMenuMethods = ({ NativeModules }) => {
  // RN 0.43 use DevSettings, DevMenu will be deprecated
  const DevSettings = NativeModules.DevSettings || NativeModules.DevMenu
  // Currently `show dev menu` is only on DevMenu
  const showDevMenu = (DevSettings && DevSettings.show)
    || (NativeModules.DevMenu && NativeModules.DevMenu.show)
    || undefined

  const AsyncStorage = getSafeAsyncStorage(NativeModules)
  const methods = {
    ...DevSettings,
    show: showDevMenu,
    networkInspect: toggleNetworkInspect,
    showAsyncStorage: getShowAsyncStorageFn(AsyncStorage),
    clearAsyncStorage: getClearAsyncStorageFn(AsyncStorage),
  }
  if (methods.showAsyncStorage) {
    window.showAsyncStorageContentInDev = methods.showAsyncStorage
  }
  const result = Object.keys(methods).filter((key) => !!methods[key])
  availableDevMenuMethods = methods

  postMessage({ __AVAILABLE_METHODS_CAN_CALL_BY_RNDEBUGGER__: result })
}

export const invokeDevMenuMethodIfAvailable = (name, args = []) => {
  const method = availableDevMenuMethods[name]
  if (method) method(...args)
}


================================================
FILE: app/worker/index.js
================================================
/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
/* global __fbBatchedBridge, importScripts: true */

// Edit from https://github.com/facebook/react-native/blob/master/local-cli/server/util/debuggerWorker.js

import './setup'
import { checkAvailableDevMenuMethods, invokeDevMenuMethodIfAvailable } from './devMenu'
import { reportDefaultReactDevToolsPort } from './reactDevTools'
import devToolsEnhancer, { composeWithDevTools } from './reduxAPI'
import * as RemoteDev from './remotedev'
import { getRequiredModules } from './utils'
import { toggleNetworkInspect } from './networkInspect'
import { handleApolloClient } from './apollo'

/* eslint-disable no-underscore-dangle */
self.__REMOTEDEV__ = RemoteDev

devToolsEnhancer.send = RemoteDev.send
devToolsEnhancer.connect = RemoteDev.connect
devToolsEnhancer.disconnect = RemoteDev.disconnect

// Deprecated API, these may removed when redux-devtools-extension 3.0 release
self.devToolsExtension = devToolsEnhancer
self.reduxNativeDevTools = devToolsEnhancer
self.reduxNativeDevToolsCompose = composeWithDevTools

self.__REDUX_DEVTOOLS_EXTENSION__ = devToolsEnhancer
self.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ = composeWithDevTools

const setupRNDebuggerBeforeImportScript = (message) => {
  self.__REACT_DEVTOOLS_PORT__ = message.reactDevToolsPort
  if (message.networkInspect) {
    self.__NETWORK_INSPECT__ = toggleNetworkInspect
  }
}

const noop = (f) => f
const setupRNDebugger = async (message) => {
  // We need to regularly update JS runtime
  // because the changes of worker message (Redux DevTools, DevMenu)
  // doesn't notify to the remote JS runtime
  self.__RND_INTERVAL__ = setInterval(noop, 100); // eslint-disable-line

  handleApolloClient()
  toggleNetworkInspect(message.networkInspect)
  const modules = await getRequiredModules(message.moduleSize)
  if (modules) {
    checkAvailableDevMenuMethods(modules)
    reportDefaultReactDevToolsPort(modules)
  }
}

const messageHandlers = {
  executeApplicationScript(message, sendReply) {
    setupRNDebuggerBeforeImportScript(message)

    Object.keys(message.inject).forEach((key) => {
      self[key] = JSON.parse(message.inject[key])
    })
    let error
    try {
      importScripts(message.url)
    } catch (err) {
      error = err.message
    }

    if (!error) {
      setupRNDebugger(message)
    }

    sendReply(null /* result */, error)

    return false
  },
  emitReduxMessage() {
    // pass to other listeners
    return true
  },
  emitApolloMessage() {
    // pass to other listeners
    return true
  },
  invokeDevMenuMethod({ name, args }) {
    invokeDevMenuMethodIfAvailable(name, args)
    return false
  },
  beforeTerminate() {
    // Clean for notify native bridge
    if (window.__RND_INTERVAL__) {
      clearInterval(window.__RND_INTERVAL__)
      window.__RND_INTERVAL__ = null
    }
    return false
  },
}

addEventListener('message', (message) => {
  const object = message.data

  const sendReply = (result, error) => {
    postMessage({ replyID: object.id, result, error })
  }

  const handler = messageHandlers[object.method]
  if (handler) {
    // Special cased handlers
    return handler(object, sendReply)
  }
  // Other methods get called on the bridge
  let returnValue = [[], [], [], 0]
  let error
  try {
    if (typeof __fbBatchedBridge === 'object') {
      returnValue = __fbBatchedBridge[object.method].apply(null, object.arguments)
    } else {
      error = 'Failed to call function, __fbBatchedBridge is undefined'
    }
  } catch (err) {
    error = err.message
  } finally {
    sendReply(JSON.stringify(returnValue), error)
  }
  return false
})


================================================
FILE: app/worker/networkInspect.js
================================================
import getRNDebuggerFetchPolyfills from './polyfills/fetch'

const isWorkerMethod = (fn) => String(fn).indexOf('[native code]') > -1

/* eslint-disable no-underscore-dangle */
let networkInspect

export const toggleNetworkInspect = (enabled) => {
  if (!enabled && networkInspect) {
    self.fetch = networkInspect.fetch
    self.XMLHttpRequest = networkInspect.XMLHttpRequest
    self.FormData = networkInspect.FormData
    self.Headers = networkInspect.Headers
    self.Request = networkInspect.Request
    self.Response = networkInspect.Response
    networkInspect = null
    return
  }
  if (!enabled) return
  if (enabled && networkInspect) return
  if (isWorkerMethod(self.XMLHttpRequest) || isWorkerMethod(self.FormData)) {
    console.warn(
      '[RNDebugger] '
        + 'I tried to enable Network Inspect but XHR '
        + "have been replaced by worker's XHR. "
        + 'You can disable Network Inspect (documentation: https://goo.gl/BVvEkJ) '
        + 'or tracking your app code if you have called '
        + '`global.XMLHttpRequest = global.originalXMLHttpRequest`.',
    )
    return
  }
  networkInspect = {
    fetch: self.fetch,
    XMLHttpRequest: self.XMLHttpRequest,
    FormData: self.FormData,
    Headers: self.Headers,
    Request: self.Request,
    Response: self.Response,
  }

  self.XMLHttpRequest = self.originalXMLHttpRequest
    ? self.originalXMLHttpRequest
    : self.XMLHttpRequest
  self.FormData = self.originalFormData ? self.originalFormData : self.FormData
  const {
    fetch, Headers, Request, Response,
  } = getRNDebuggerFetchPolyfills()
  self.fetch = fetch
  self.Headers = Headers
  self.Request = Request
  self.Response = Response

  console.log(
    '[RNDebugger]',
    'Network Inspect is enabled,',
    'see the documentation (https://goo.gl/yEcRrU) for more information.',
  )
}

/*
 * `originalXMLHttpRequest` haven't permission to set forbidden header name
 * (https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name)
 * We have to use Electron session to solve this problem (See electron/main.js)
 */
const forbiddenHeaderNames = [
  'Accept-Charset',
  'Accept-Encoding',
  'Access-Control-Request-Headers',
  'Access-Control-Request-Method',
  'Connection',
  'Content-Length',
  'Cookie',
  'Cookie2',
  'Date',
  'DNT',
  'Expect',
  'Host',
  'Keep-Alive',
  'Origin',
  'Referer',
  'TE',
  'Trailer',
  'Transfer-Encoding',
  'Upgrade',
  'Via',
  // Actually it still blocked on Chrome
  'User-Agent',
]
forbiddenHeaderNames.forEach((name) => forbiddenHeaderNames.push(name.toLowerCase()))

const isForbiddenHeaderName = (header) => forbiddenHeaderNames.includes(header)
  || header.startsWith('Proxy-')
  || header.startsWith('proxy-')
  || header.startsWith('Sec-')
  || header.startsWith('sec-')

export const replaceForbiddenHeadersForWorkerXHR = () => {
  if (!isWorkerMethod(self.XMLHttpRequest)) return
  const originalSetRequestHeader = self.XMLHttpRequest.prototype.setRequestHeader
  self.XMLHttpRequest.prototype.setRequestHeader = function setRequestHeader(header, value) {
    let replacedHeader = header
    if (isForbiddenHeaderName(header)) {
      replacedHeader = `__RN_DEBUGGER_SET_HEADER_REQUEST_${header}`
    }
    return originalSetRequestHeader.call(this, replacedHeader, value)
  }
}

export const addURIWarningForWorkerFormData = () => {
  if (!isWorkerMethod(self.FormData)) return
  const originAppend = FormData.prototype.append
  self.FormData.prototype.append = function append(key, value) {
    if (value && value.uri) {
      console.warn(
        '[RNDebugger] '
          + "Detected you're enabled Network Inspect and using `uri` in FormData, "
          + 'it will be a problem if you use it for upload, '
          + 'please see the documentation (https://goo.gl/yEcRrU) for more information.',
      )
    }
    return originAppend.call(this, key, value)
  }
}


================================================
FILE: app/worker/polyfills/fetch.js
================================================
/* eslint-disable no-underscore-dangle */
/* eslint-disable no-param-reassign */
/* eslint-disable no-prototype-builtins */
/* eslint-disable no-new */
/* eslint-disable no-restricted-syntax */
/* eslint-disable func-names */

export default function getRNDebuggerFetchPolyfills() {
  const support = {
    searchParams: 'URLSearchParams' in self,
    iterable: 'Symbol' in self && 'iterator' in Symbol,
    blob: false, // NOTE: Default for RNDebugger
    formData: 'FormData' in self,
    arrayBuffer: 'ArrayBuffer' in self,
  }

  function isDataView(obj) {
    return obj && DataView.prototype.isPrototypeOf(obj)
  }

  let isArrayBufferView
  if (support.arrayBuffer) {
    const viewClasses = [
      '[object Int8Array]',
      '[object Uint8Array]',
      '[object Uint8ClampedArray]',
      '[object Int16Array]',
      '[object Uint16Array]',
      '[object Int32Array]',
      '[object Uint32Array]',
      '[object Float32Array]',
      '[object Float64Array]',
    ]

    isArrayBufferView = ArrayBuffer.isView
      || function (obj) {
        return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1
      }
  }

  function normalizeName(name) {
    if (typeof name !== 'string') {
      name = String(name)
    }
    if (/[^a-z0-9\-#$%&'*+.^_`|~]/i.test(name) || name === '') {
      throw new TypeError('Invalid character in header field name')
    }
    return name.toLowerCase()
  }

  function normalizeValue(value) {
    if (typeof value !== 'string') {
      value = String(value)
    }
    return value
  }

  // Build a destructive iterator for the value list
  function iteratorFor(items) {
    const iterator = {
      next() {
        const value = items.shift()
        return { done: value === undefined, value }
      },
    }

    if (support.iterable) {
      iterator[Symbol.iterator] = function () {
        return iterator
      }
    }

    return iterator
  }

  function Headers(headers) {
    this.map = {}

    if (headers instanceof Headers) {
      headers.forEach(function (value, name) {
        this.append(name, value)
      }, this)
    } else if (Array.isArray(headers)) {
      headers.forEach(function (header) {
        this.append(header[0], header[1])
      }, this)
    } else if (headers) {
      Object.getOwnPropertyNames(headers).forEach(function (name) {
        this.append(name, headers[name])
      }, this)
    }
  }

  Headers.prototype.append = function (name, value) {
    name = normalizeName(name)
    value = normalizeValue(value)
    const oldValue = this.map[name]
    this.map[name] = oldValue ? `${oldValue}, ${value}` : value
  }

  Headers.prototype.delete = function (name) {
    delete this.map[normalizeName(name)]
  }

  Headers.prototype.get = function (name) {
    name = normalizeName(name)
    return this.has(name) ? this.map[name] : null
  }

  Headers.prototype.has = function (name) {
    return this.map.hasOwnProperty(normalizeName(name))
  }

  Headers.prototype.set = function (name, value) {
    this.map[normalizeName(name)] = normalizeValue(value)
  }

  Headers.prototype.forEach = function (callback, thisArg) {
    for (const name in this.map) {
      if (this.map.hasOwnProperty(name)) {
        callback.call(thisArg, this.map[name], name, this)
      }
    }
  }

  Headers.prototype.keys = function () {
    const items = []
    this.forEach((value, name) => {
      items.push(name)
    })
    return iteratorFor(items)
  }

  Headers.prototype.values = function () {
    const items = []
    this.forEach((value) => {
      items.push(value)
    })
    return iteratorFor(items)
  }

  Headers.prototype.entries = function () {
    const items = []
    this.forEach((value, name) => {
      items.push([name, value])
    })
    return iteratorFor(items)
  }

  if (support.iterable) {
    Headers.prototype[Symbol.iterator] = Headers.prototype.entries
  }

  function consumed(body) {
    if (body.bodyUsed) {
      return Promise.reject(new TypeError('Already read'))
    }
    body.bodyUsed = true
  }

  function fileReaderReady(reader) {
    return new Promise((resolve, reject) => {
      reader.onload = function () {
        resolve(reader.result)
      }
      reader.onerror = function () {
        reject(reader.error)
      }
    })
  }

  function readBlobAsArrayBuffer(blob) {
    const reader = new FileReader()
    const promise = fileReaderReady(reader)
    reader.readAsArrayBuffer(blob)
    return promise
  }

  function readBlobAsText(blob) {
    const reader = new FileReader()
    const promise = fileReaderReady(reader)
    reader.readAsText(blob)
    return promise
  }

  function readArrayBufferAsText(buf) {
    const view = new Uint8Array(buf)
    const chars = new Array(view.length)

    for (let i = 0; i < view.length; i += 1) {
      chars[i] = String.fromCharCode(view[i])
    }
    return chars.join('')
  }

  function bufferClone(buf) {
    if (buf.slice) {
      return buf.slice(0)
    }
    const view = new Uint8Array(buf.byteLength)
    view.set(new Uint8Array(buf))
    return view.buffer
  }

  function decode(body) {
    const form = new FormData()
    body
      .trim()
      .split('&')
      .forEach((bytes) => {
        if (bytes) {
          const split = bytes.split('=')
          const name = split.shift().replace(/\+/g, ' ')
          const value = split.join('=').replace(/\+/g, ' ')
          form.append(decodeURIComponent(name), decodeURIComponent(value))
        }
      })
    return form
  }

  function Body() {
    this.bodyUsed = false

    this._initBody = function (body) {
      this._bodyInit = body
      if (!body) {
        this._bodyText = ''
      } else if (typeof body === 'string') {
        this._bodyText = body
      } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
        this._bodyBlob = body
      } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
        this._bodyFormData = body
      } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
        this._bodyText = body.toString()
      } else if (support.arrayBuffer && support.blob && isDataView(body)) {
        this._bodyArrayBuffer = bufferClone(body.buffer)
        // IE 10-11 can't handle a DataView body.
        this._bodyInit = new Blob([this._bodyArrayBuffer])
      } else if (
        support.arrayBuffer
        && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))
      ) {
        this._bodyArrayBuffer = bufferClone(body)
      } else {
        const bodyText = Object.prototype.toString.call(body)
        body = bodyText
        this._bodyText = bodyText
      }

      if (!this.headers.get('content-type')) {
        if (typeof body === 'string') {
          this.headers.set('content-type', 'text/plain;charset=UTF-8')
        } else if (this._bodyBlob && this._bodyBlob.type) {
          this.headers.set('content-type', this._bodyBlob.type)
        } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
          this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8')
        }
      }
    }

    if (support.blob) {
      this.blob = function () {
        const rejected = consumed(this)
        if (rejected) {
          return rejected
        }

        if (this._bodyBlob) {
          return Promise.resolve(this._bodyBlob)
        } if (this._bodyArrayBuffer) {
          return Promise.resolve(new Blob([this._bodyArrayBuffer]))
        } if (this._bodyFormData) {
          throw new Error('could not read FormData body as blob')
        } else {
          return Promise.resolve(new Blob([this._bodyText]))
        }
      }

      this.arrayBuffer = function () {
        if (this._bodyArrayBuffer) {
          return consumed(this) || Promise.resolve(this._bodyArrayBuffer)
        }
        return this.blob().then(readBlobAsArrayBuffer)
      }
    }

    this.text = function () {
      const rejected = consumed(this)
      if (rejected) {
        return rejected
      }

      if (this._bodyBlob) {
        return readBlobAsText(this._bodyBlob)
      } if (this._bodyArrayBuffer) {
        return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer))
      } if (this._bodyFormData) {
        throw new Error('could not read FormData body as text')
      } else {
        return Promise.resolve(this._bodyText)
      }
    }

    if (support.formData) {
      this.formData = function () {
        return this.text().then(decode)
      }
    }

    this.json = function () {
      return this.text().then(JSON.parse)
    }

    return this
  }

  // HTTP methods whose capitalization should be normalized
  const methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']

  function normalizeMethod(method) {
    const upcased = method.toUpperCase()
    return methods.indexOf(upcased) > -1 ? upcased : method
  }

  function Request(input, options) {
    options = options || {}
    let { body } = options

    if (input instanceof Request) {
      if (input.bodyUsed) {
        throw new TypeError('Already read')
      }
      this.url = input.url
      this.credentials = input.credentials
      if (!options.headers) {
        this.headers = new Headers(input.headers)
      }
      this.method = input.method
      this.mode = input.mode
      this.signal = input.signal
      if (!body && input._bodyInit != null) {
        body = input._bodyInit
        input.bodyUsed = true
      }
    } else {
      this.url = String(input)
    }

    this.credentials = options.credentials || this.credentials || 'same-origin'
    if (options.headers || !this.headers) {
      this.headers = new Headers(options.headers)
    }
    this.method = normalizeMethod(options.method || this.method || 'GET')
    this.mode = options.mode || this.mode || null
    this.signal = options.signal || this.signal
    this.referrer = null

    if ((this.method === 'GET' || this.method === 'HEAD') && body) {
      throw new TypeError('Body not allowed for GET or HEAD requests')
    }
    this._initBody(body)
  }

  Request.prototype.clone = function () {
    return new Request(this, { body: this._bodyInit })
  }

  function parseHeaders(rawHeaders) {
    const headers = new Headers()
    // Replace instances of \r\n and \n followed by
    // at least one space or horizontal tab with a space
    // https://tools.ietf.org/html/rfc7230#section-3.2
    const preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' ')
    preProcessedHeaders.split(/\r?\n/).forEach((line) => {
      const parts = line.split(':')
      const key = parts.shift().trim()
      if (key) {
        const value = parts.join(':').trim()
        headers.append(key, value)
      }
    })
    return headers
  }

  Body.call(Request.prototype)

  function Response(bodyInit, options) {
    if (!options) {
      options = {}
    }

    this.type = 'default'
    this.status = options.status === undefined ? 200 : options.status
    this.ok = this.status >= 200 && this.status < 300
    this.statusText = 'statusText' in options ? options.statusText : 'OK'
    this.headers = new Headers(options.headers)
    this.url = options.url || ''
    this._initBody(bodyInit)
  }

  Body.call(Response.prototype)

  Response.prototype.clone = function () {
    return new Response(this._bodyInit, {
      status: this.status,
      statusText: this.statusText,
      headers: new Headers(this.headers),
      url: this.url,
    })
  }

  Response.error = function () {
    const response = new Response(null, { status: 0, statusText: '' })
    response.type = 'error'
    return response
  }

  const redirectStatuses = [301, 302, 303, 307, 308]

  Response.redirect = function (url, status) {
    if (redirectStatuses.indexOf(status) === -1) {
      throw new RangeError('Invalid status code')
    }

    return new Response(null, { status, headers: { location: url } })
  }

  let { DOMException } = self
  try {
    new DOMException()
  } catch (err) {
    DOMException = function (message, name) {
      this.message = message
      this.name = name
      const error = Error(message)
      this.stack = error.stack
    }
    DOMException.prototype = Object.create(Error.prototype)
    DOMException.prototype.constructor = DOMException
  }

  function fetch(input, init) {
    return new Promise((resolve, reject) => {
      const request = new Request(input, init)

      if (request.signal && request.signal.aborted) {
        reject(new DOMException('Aborted', 'AbortError'))
        return
      }

      const xhr = new XMLHttpRequest()

      function abortXhr() {
        xhr.abort()
      }

      xhr.onload = function () {
        const options = {
          status: xhr.status,
          statusText: xhr.statusText,
          headers: parseHeaders(xhr.getAllResponseHeaders() || ''),
        }
        options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL')
        const body = 'response' in xhr ? xhr.response : xhr.responseText
        resolve(new Response(body, options))
      }

      xhr.onerror = function () {
        reject(new TypeError('Network request failed'))
      }

      xhr.ontimeout = function () {
        reject(new TypeError('Network request failed'))
      }

      xhr.onabort = function () {
        reject(new DOMException('Aborted', 'AbortError'))
      }

      xhr.open(request.method, request.url, true)

      if (request.credentials === 'include') {
        xhr.withCredentials = true
      } else if (request.credentials === 'omit') {
        xhr.withCredentials = false
      }

      if ('responseType' in xhr && support.blob) {
        xhr.responseType = 'blob'
      }

      request.headers.forEach((value, name) => {
        xhr.setRequestHeader(name, value)
      })

      if (request.signal) {
        request.signal.addEventListener('abort', abortXhr)

        xhr.onreadystatechange = function () {
          // DONE (success or failure)
          if (xhr.readyState === 4) {
            request.signal.removeEventListener('abort', abortXhr)
          }
        }
      }

      xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit)
    })
  }

  fetch.polyfill = true

  return {
    fetch,
    Headers,
    Request,
    Response,
  }
}


================================================
FILE: app/worker/reactDevTools.js
================================================
/* eslint-disable no-underscore-dangle */

const methodGlobalName = '__REPORT_REACT_DEVTOOLS_PORT__'

const reportReactDevToolsPort = (port, platform) => postMessage({
  [methodGlobalName]: port,
  platform,
})

export const reportDefaultReactDevToolsPort = async ({ setupDevtools, Platform }) => {
  if (Platform.__empty) return
  /*
   * [Fallback] React Native version under 0.39 can't specified the port
   */
  if (
    typeof setupDevtools === 'function'
    && setupDevtools.toString().indexOf('window.__REACT_DEVTOOLS_PORT__') === -1
  ) {
    reportReactDevToolsPort(8097, Platform.OS)
  } else {
    // React Inspector will keep the last reported port even if reload JS,
    // because we don't want to icrease the user waiting time for reload JS.
    // We need back to use the random port if we don't need fallback
    reportReactDevToolsPort(window.__REACT_DEVTOOLS_PORT__, Platform.OS)
  }
}


================================================
FILE: app/worker/reduxAPI.js
================================================
import { instrument } from '@redux-devtools/instrument'
import {
  evalAction,
  getActionsArray,
  generateId,
  stringify,
  getSeralizeParameter,
  importState,
  getLocalFilter,
  isFiltered,
  filterStagedActions,
  filterState,
} from '@redux-devtools/utils'
import { updateStackWithSourceMap } from './utils'

function configureStore(next, subscriber, options) {
  return instrument(subscriber, options)(next)
}

const instances = {
  /* [id]: { name, store, ... } */
}

let lastAction
let isExcess
let listenerAdded
let locked
let paused

function getStackTrace(config, toExcludeFromTrace) {
  if (!config.trace) return undefined
  if (typeof config.trace === 'function') return config.trace()

  let stack
  let extraFrames = 0
  let prevStackTraceLimit
  const { traceLimit } = config
  const error = Error()
  if (Error.captureStackTrace) {
    if (Error.stackTraceLimit < traceLimit) {
      prevStackTraceLimit = Error.stackTraceLimit
      Error.stackTraceLimit = traceLimit
    }
    Error.captureStackTrace(error, toExcludeFromTrace)
  } else {
    extraFrames = 3
  }
  stack = error.stack
  if (prevStackTraceLimit) Error.stackTraceLimit = prevStackTraceLimit
  if (
    extraFrames
    || typeof Error.stackTraceLimit !== 'number'
    || Error.stackTraceLimit > traceLimit
  ) {
    const frames = stack.split('\n')
    if (frames.length > traceLimit) {
      stack = frames
        .slice(0, traceLimit + extraFrames + (frames[0] === 'Error' ? 1 : 0))
        .join('\n')
    }
  }
  return updateStackWithSourceMap(stack)
}

function getLiftedState(store, filters) {
  return filterStagedActions(store.liftedStore.getState(), filters)
}

function relay(type, state, instance, action, nextActionId) {
  const {
    filters,
    predicate,
    stateSanitizer,
    actionSanitizer,
    serializeState,
    serializeAction,
  } = instance

  const message = {
    type,
    id: instance.id,
    name: instance.name,
  }
  if (state) {
    message.payload = type === 'ERROR'
      ? state
      : stringify(
        filterState(
          state,
          type,
          filters,
          stateSanitizer,
          actionSanitizer,
          nextActionId,
          predicate,
        ),
        serializeState,
      )
  }
  if (type === 'ACTION') {
    action.stack = getStackTrace(instance, true)
    message.action = stringify(
      !actionSanitizer ? action : actionSanitizer(action.action, nextActionId - 1),
      serializeAction,
    )
    message.isExcess = isExcess
    message.nextActionId = nextActionId
  } else if (instance) {
    message.libConfig = {
      type: 'redux',
      actionCreators: stringify(instance.actionCreators),
      serialize: !!instance.serialize,
    }
  }
  postMessage({ __IS_REDUX_NATIVE_MESSAGE__: true, content: message })
}

function dispatchRemotely(action, instance) {
  try {
    const { store, actionCreators } = instance
    const result = evalAction(action, actionCreators)
    store.dispatch(result)
  } catch (e) {
    relay('ERROR', e.message, instance)
  }
}

function importPayloadFrom(store, state, instance) {
  try {
    const nextLiftedState = importState(state, instance)
    if (!nextLiftedState) return
    store.liftedStore.dispatch({ type: 'IMPORT_STATE', ...nextLiftedState })
    relay('STATE', getLiftedState(store, instance.filters), instance)
  } catch (e) {
    relay('ERROR', e.message, instance)
  }
}

function exportState({ id: instanceId, store, serializeState }) {
  const liftedState = store.liftedStore.getState()
  const { actionsById } = liftedState
  const payload = []
  liftedState.stagedActionIds.slice(1).forEach((id) => {
    payload.push(actionsById[id].action)
  })
  postMessage({
    __IS_REDUX_NATIVE_MESSAGE__: true,
    content: {
      type: 'EXPORT',
      payload: stringify(payload, serializeState),
      committedState:
        typeof liftedState.committedState !== 'undefined'
          ? stringify(liftedState.committedState, serializeState)
          : undefined,
      instanceId,
    },
  })
}

function handleMessages(message) {
  const {
    id, instanceId, type, action, state, toAll,
  } = message
  if (toAll) {
    Object.keys(instances).forEach((key) => {
      handleMessages({ ...message, id: key, toAll: false })
    })
    return false
  }

  const instance = instances[id || instanceId]
  if (!instance) return true
  const { store, filters } = instance
  if (!store) return false

  switch (type) {
    case 'DISPATCH':
      store.liftedStore.dispatch(action)
      break
    case 'ACTION':
      dispatchRemotely(action, instance)
      break
    case 'IMPORT':
      importPayloadFrom(store, state, instance)
      break
    case 'EXPORT':
      exportState(instance)
      break
    case 'UPDATE':
      relay('STATE', getLiftedState(store, filters), instance)
      break
    default:
      break
  }
  return false
}

function start(instance) {
  if (!listenerAdded) {
    self.addEventListener('message', (message) => {
      const { method, content } = message.data
      if (method === 'emitReduxMessage') {
        handleMessages(content)
      }
    })
    listenerAdded = true
  }
  const { store, actionCreators, filters } = instance
  if (typeof actionCreators === 'function') {
    instance.actionCreators = actionCreators()
  }
  relay('STATE', getLiftedState(store, filters), instance)
}

function checkForReducerErrors(liftedState, instance) {
  if (liftedState.computedStates[liftedState.currentStateIndex].error) {
    relay('STATE', filterStagedActions(liftedState, instance.filters), instance)
    return true
  }
  return false
}

function monitorReducer(state = {}, action = {}) {
  lastAction = action.type
  return state
}

function handleChange(state, liftedState, maxAge, instance) {
  if (checkForReducerErrors(liftedState, instance)) return

  const { filters, predicate } = instance
  if (lastAction === 'PERFORM_ACTION') {
    const { nextActionId } = liftedState
    const liftedAction = liftedState.actionsById[nextActionId - 1]
    if (isFiltered(liftedAction.action, filters)) return
    if (predicate && !predicate(state, liftedAction.action)) return
    relay('ACTION', state, instance, liftedAction, nextActionId)
    if (!isExcess && maxAge) isExcess = liftedState.stagedActionIds.length >= maxAge
  } else {
    if (lastAction === 'JUMP_TO_STATE') return
    if (lastAction === 'PAUSE_RECORDING') {
      paused = liftedState.isPaused
    } else if (lastAction === 'LOCK_CHANGES') {
      locked = liftedState.isLocked
    }
    if (paused || locked) {
      if (lastAction) lastAction = undefined
      else return
    }
    relay('STATE', filterStagedActions(liftedState, filters), instance)
  }
}

export default function devToolsEnhancer(options = {}) {
  const {
    name,
    maxAge = 30,
    shouldCatchErrors = !!global.shouldCatchErrors,
    shouldHotReload,
    shouldRecordChanges,
    shouldStartLocked,
    pauseActionType = '@@PAUSED',
    actionCreators,
    filters,
    actionsBlacklist,
    actionsWhitelist,
    actionSanitizer,
    stateSanitizer,
    deserializeState,
    deserializeAction,
    serialize,
    predicate,
    trace,
    traceLimit,
  } = options
  const id = generateId(options.instanceId)

  const serializeState = getSeralizeParameter(options, 'serializeState')
  const serializeAction = getSeralizeParameter(options, 'serializeAction')

  return (next) => (reducer, initialState) => {
    const store = configureStore(next, monitorReducer, {
      maxAge,
      shouldCatchErrors,
      shouldHotReload,
      shouldRecordChanges,
      shouldStartLocked,
      pauseActionType,
    })(reducer, initialState)

    instances[id] = {
      name: name || id,
      id,
      store,
      filters: getLocalFilter({
        actionsWhitelist: (filters && filters.whitelist) || actionsWhitelist,
        actionsBlacklist: (filters && filters.blacklist) || actionsBlacklist,
      }),
      actionCreators: actionCreators && (() => getActionsArray(actionCreators)),
      stateSanitizer,
      actionSanitizer,
      deserializeState,
      deserializeAction,
      serializeState,
      serializeAction,
      serialize,
      predicate,
      trace,
      traceLimit,
    }

    start(instances[id])
    store.subscribe(() => {
      handleChange(store.getState(), store.liftedStore.getState(), maxAge, instances[id])
    })
    return store
  }
}

const preEnhancer = (instanceId) => (next) => (reducer, initialState, enhancer) => {
  const store = next(reducer, initialState, enhancer)

  if (instances[instanceId]) {
    instances[instanceId].store = store
  }
  return {
    ...store,
    dispatch: (action) => (locked ? action : store.dispatch(action)),
  }
}

devToolsEnhancer.updateStore = (newStore, instanceId) => {
  console.warn(
    '[RNDebugger]',
    '`updateStore` is deprecated use `window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__` instead:',
    'https://github.com/jhen0409/react-native-debugger/blob/master/docs/redux-devtools-integration.md',
  )

  const keys = Object.keys(instances)
  if (!keys.length) return

  if (keys.length > 1 && !instanceId) {
    console.warn(
      'You have multiple stores,',
      'please provide `instanceId` argument (`updateStore(store, instanceId)`)',
    )
  }
  if (instanceId) {
    const instance = instances[instanceId]
    if (!instance) return
    instance.store = newStore
  } else {
    instances[keys[0]].store = newStore
  }
}

const compose = (options) => (...funcs) => (...args) => {
  const instanceId = generateId(options.instanceId)
  return [preEnhancer(instanceId), ...funcs].reduceRight(
    (composed, f) => f(composed),
    devToolsEnhancer({ ...options, instanceId })(...args),
  )
}

export function composeWithDevTools(...funcs) {
  if (funcs.length === 0) {
    return devToolsEnhancer()
  }
  if (funcs.length === 1 && typeof funcs[0] === 'object') {
    return compose(funcs[0])
  }
  return compose({})(...funcs)
}


================================================
FILE: app/worker/remotedev.js
================================================
// Edit from https://github.com/zalmoxisus/remotedev/blob/master/src/devTools.js

import { stringify, parse } from 'jsan'
import { generateId, getActionsArray } from '@redux-devtools/utils'

let listenerAdded
const listeners = {}

export function extractState(message) {
  if (!message || !message.state) return undefined
  if (typeof message.state === 'string') return parse(message.state)
  return message.state
}

function handleMessages(message) {
  if (!message.payload) {
    message.payload = message.action
  }
  const fn = listeners[message.instanceId]
  if (!fn) return true

  if (typeof fn === 'function') {
    fn(message)
  } else {
    fn.forEach((func) => func(message))
  }
  return false
}

export function start() {
  if (!listenerAdded) {
    self.addEventListener('message', (message) => {
      const { method, content } = message.data
      if (method === 'emitReduxMessage') {
        return handleMessages(content)
      }
    })
    listenerAdded = true
  }
}

function transformAction(action, config) {
  if (action.action) return action
  const liftedAction = { timestamp: Date.now() }
  if (action) {
    if (config.getActionType) {
      liftedAction.action = config.getActionType(action)
    } else if (typeof action === 'string') {
      liftedAction.action = { type: action }
    } else if (!action.type) {
      liftedAction.action = { type: 'update' }
    } else {
      liftedAction.action = action
    }
  } else {
    liftedAction.action = { type: action }
  }
  return liftedAction
}

export function send(action, state, type, options) {
  start()
  setTimeout(() => {
    const message = {
      payload: state ? stringify(state) : '',
      action: type === 'ACTION' ? stringify(transformAction(action, options)) : action,
      type: type || 'ACTION',
      id: options.instanceId,
      instanceId: options.instanceId,
      name: options.name,
    }
    message.libConfig = {
      type: options.type,
      name: options.name,
      serialize: !!options.serialize,
      actionCreators: options.actionCreators,
    }
    postMessage({ __IS_REDUX_NATIVE_MESSAGE__: true, content: message })
  }, 0)
}

export function connect(options = {}) {
  const id = generateId(options.instanceId)
  const opts = {
    ...options,
    instanceId: id,
    name: options.name || id,
    actionCreators: JSON.stringify(getActionsArray(options.actionCreators || {})),
  }
  start()
  return {
    init(state, action) {
      send(action || {}, state, 'INIT', opts)
    },
    subscribe(listener) {
      if (!listener) return undefined
      if (!listeners[id]) listeners[id] = []
      listeners[id].push(listener)

      return function unsubscribe() {
        const index = listeners[id].indexOf(listener)
        listeners[id].splice(index, 1)
      }
    },
    unsubscribe() {
      delete listeners[id]
    },
    send(action, payload) {
      if (action) {
        send(action, payload, 'ACTION', opts)
      } else {
        send(undefined, payload, 'STATE', opts)
      }
    },
    error(payload) {
      send(undefined, payload, 'Error', opts)
    },
  }
}

// Not implemented
export function disconnect() {}


================================================
FILE: app/worker/setup.js
================================================
import {
  replaceForbiddenHeadersForWorkerXHR,
  addURIWarningForWorkerFormData,
} from './networkInspect'

// Add the missing `global` for WebWorker
self.global = self

/*
 * Blob is not supported for RN < 0.54,
 * we should remove it in WebWorker because
 * it will used for `whatwg-fetch` on older RN versions
 */
if (self.Blob && self.Blob.toString() === 'function Blob() { [native code] }') {
  /*
   * RN > 0.54 will polyfill Blob.
   * If it is deleted before the RN setup, RN will not add a reference to the original.
   * We will need to be able to restore the original when running RN > 0.54 for networking tools,
   * so add the reference here as react-native will not do it if the original is deleted
   */
  self.originalBlob = self.Blob
  delete self.Blob
}

if (
  self.XMLHttpRequest
  && self.XMLHttpRequest.toString() === 'function XMLHttpRequest() { [native code] }'
) {
  self.originalXMLHttpRequest = self.XMLHttpRequest
}

if (self.FormData && self.FormData.toString() === 'function FormData() { [native code] }') {
  self.originalFormData = self.FormData
}

// Catch native fetch
if (self.fetch && self.fetch.toString() === 'function fetch() { [native code] }') {
  /* eslint-disable-next-line no-underscore-dangle */
  self.__ORIGINAL_FETCH__ = self.fetch
}

replaceForbiddenHeadersForWorkerXHR()
addURIWarningForWorkerFormData()


================================================
FILE: app/worker/utils.js
================================================
/* eslint-disable no-underscore-dangle */

// Avoid warning of use metro require on dev mode
// it actually unnecessary for RN >= 0.56, so it is backward compatibility
const avoidWarnForRequire = (moduleNames) => {
  if (!moduleNames.length) moduleNames.push('NativeModules')
  return new Promise((resolve) => {
    setTimeout(() => {
      // It's replaced console.warn of react-native
      const originalWarn = console.warn
      console.warn = (...args) => {
        if (
          args[0]
            && moduleNames.some(
              (name) => args[0].indexOf(`Requiring module '${name}' by name`) > -1,
            )
        ) {
          return
        }
        return originalWarn(...args)
      }
      resolve(() => {
        console.warn = originalWarn
      })
    })
  })
}

let reactNative

const getRequireMethod = () => {
  // RN >= 0.57
  if (typeof window.__r === 'function') return window.__r
  // RN < 0.57
  if (typeof window.require === 'function') return window.require
}

const lookupForRNModules = (size = 999) => {
  const metroRequire = getRequireMethod()
  let actualSize = size
  let getModule = metroRequire
  if (metroRequire.getModules) {
    const mods = metroRequire.getModules()
    actualSize = Object.keys(mods).length
    getModule = (moduleId) => {
      const mod = mods && mods[moduleId]
      return (mod && mod.publicModule && mod.publicModule.exports) || null
    }
  } else {
    getModule = (moduleId) => metroRequire(moduleId)
  }
  for (let moduleId = 0; moduleId <= actualSize - 1; moduleId += 1) {
    const rn = getModule(moduleId)
    if (rn && rn.requireNativeComponent && rn.NativeModules) {
      return rn
    }
  }
  return null
}

const getModule = (name, size) => {
  let result
  try {
    const metroRequire = getRequireMethod()
    // RN >= 0.56
    if (metroRequire.name === 'metroRequire') {
      const rn = reactNative || lookupForRNModules(size)
      reactNative = rn
      global.$reactNative = rn
      result = reactNative && reactNative[name]
    } else if (metroRequire.name === '_require') {
      result = metroRequire(name)
    }
  } catch (e) {} // eslint-disable-line
  return result || { __empty: true }
}

const requiredModules = {
  MessageQueue: (size) => (self.__fbBatchedBridge
      && Object.getPrototypeOf(self.__fbBatchedBridge).constructor)
    || getModule('MessageQueue', size),
  NativeModules: (size) => getModule('NativeModules', size),
  Platform: (size) => getModule('Platform', size),
  setupDevtools: (size) => getModule('setupDevtools', size),
}

export const getRequiredModules = async (size) => {
  if (!window.__DEV__ || !getRequireMethod()) return
  const done = await avoidWarnForRequire(Object.keys(requiredModules))
  const modules = {}
  Object.keys(requiredModules).forEach((name) => {
    modules[name] = requiredModules[name](size)
  })
  done()
  return modules
}

const RN_DEBUGGER_URL_PART = 'RNDebuggerWorker.js'
const BUNDLE_URL_REGEXP = /(http[\S]*?index\.bundle\?[\S]*?)(:\d+:?\d?)/

const addInlineSourceMap = (_, urlGroup1, urlGroup2) => `${urlGroup1}&inlineSourceMap=true${urlGroup2}`
const mapStackLines = (line) => line.replace(BUNDLE_URL_REGEXP, addInlineSourceMap)
const filterRnDebuggerLines = (line) => !line.includes(RN_DEBUGGER_URL_PART)

export function updateStackWithSourceMap(stack) {
  const lines = stack.split('\n')
  const linesWithoutRNDebugger = lines.filter(filterRnDebuggerLines)
  const lineWithSourceMap = linesWithoutRNDebugger.map(mapStackLines)
  return lineWithSourceMap.join('\n')
}


================================================
FILE: auto_update.json
================================================
{
  "url": "https://github.com/jhen0409/react-native-debugger/releases/download/v0.14.0/rn-debugger-macos-universal.zip",
  "name": "v0.14.0",
  "notes": "- Upgrade react-devtools-core to v4.28.0\n- Upgrade redux-devtools to latest version\n- Upgrade apollo-client-devtools to v4- More: https://github.com/jhen0409/react-native-debugger/releases/tag/v0.14.0"
}


================================================
FILE: auto_updater.json
================================================
{
  "url": "https://github.com/jhen0409/react-native-debugger/releases/download/v0.10.13/rn-debugger-macos-x64.zip",
  "name": "v0.10.13",
  "notes": "Update apollo-client-devtools to v2.3.5"
}


================================================
FILE: babel.config.js
================================================
module.exports = (api) => {
  api.cache(true)
  return {
    presets: [['@babel/preset-env', { targets: { node: '18.5' } }], '@babel/preset-react'],
    plugins: [],
    env: {
      production: {
        plugins: [
          '@babel/plugin-transform-react-inline-elements',
          '@babel/plugin-transform-react-constant-elements',
          'transform-react-remove-prop-types',
        ],
      },
    },
  }
}


================================================
FILE: dist/app.html
================================================
<!doctype html>
<html>
  <head>
    <meta charset=utf-8>
    <title>React Native Debugger</title>
    <link href='css/style.css' rel="stylesheet" />
  </head>
  <body>
    <div id="root">
      <div id="loading">Loading...</div>
    </div>
    <script src="js/bundle.js"></script>
  </body>
</html>


================================================
FILE: dist/css/style.css
================================================
html,
body {
  font-family: monaco, Consolas, Lucida Console, monospace;
  overflow: hidden;
  font-size: 100%;
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  background-color: rgb(53, 59, 70);
}

#root {
  width: 100%;
  height: 100%;
}
#logs {
  position: fixed;
  top: 0;
  left: 0;
  white-space: pre;
}
#loading {
  color: #aaa;
  font-size: 30px;
  display: flex;
  height: 100%;
  justify-content: center;
  align-items: center;
}

::-webkit-scrollbar {
  width: 8px;
  height: 8px;
  background-color: #555;
}
::-webkit-scrollbar-thumb {
  background-color: #333;
}
::-webkit-scrollbar-corner {
  background-color: #333;
}

@media print {
  @page {
    size: auto;
    margin: 0;
  }
  body {
    position: static;
  }
}
.CodeMirror {
  font-family: monaco, Consolas, Lucida Console, monospace !important;
}


================================================
FILE: dist/devtools-helper/main.html
================================================
<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <script src="./main.js"></script>
  </head>
  <body>
  </body>
</html>


================================================
FILE: dist/devtools-helper/main.js
================================================
const detectChromeDevToolsTheme = () => chrome.devtools.panels.themeName || 'default';

const themeName = detectChromeDevToolsTheme();

chrome.devtools.inspectedWindow.eval(`
  window.chromeDevToolsTheme = '${themeName}';
  if (window.notifyDevToolsThemeChange) {
    window.notifyDevToolsThemeChange(window.chromeDevToolsTheme);
  }
`);

window.addEventListener('message', ({ data }) => {
  if (data.type !== 'open-in-editor') {
    return;
  }
  const arr = data.source.split(':');
  const lineNumber = arr.pop(-1);
  const file = arr.join(':');
  chrome.devtools.inspectedWindow.eval(`
    if (window.openInEditor) {
      window.openInEditor('${file}', ${Number(lineNumber)});
    }
  `);
});


================================================
FILE: dist/devtools-helper/manifest.json
================================================
{
  "manifest_version": 2,
  "name": "RNDebugger devtools helper",
  "version": "0.0.1",
  "devtools_page": "main.html"
}


================================================
FILE: dist/package.json
================================================
{
  "name": "react-native-debugger",
  "version": "0.14.0",
  "productName": "React Native Debugger",
  "description": "The standalone app for React Native Debugger, with React DevTools / Redux DevTools",
  "main": "main.js",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/jhen0409/react-native-debugger.git"
  },
  "author": "Jhen <developer@jhen.me>",
  "license": "MIT",
  "scripts": {
    "postinstall": "patch-package"
  },
  "dependencies": {
    "adbkit": "^2.11.0",
    "electron-store": "^1.2.0",
    "react-devtools-core": "^4.28.0"
  },
  "devDependencies": {
    "apollo-client-devtools": "^4.1.4",
    "patch-package": "^6.2.2"
  }
}


================================================
FILE: dist/patches/apollo-client-devtools+4.1.4.patch
================================================
diff --git a/node_modules/apollo-client-devtools/build/background.js b/node_modules/apollo-client-devtools/build/background.js
index 1b46d15..5767881 100644
--- a/node_modules/apollo-client-devtools/build/background.js
+++ b/node_modules/apollo-client-devtools/build/background.js
@@ -171,21 +171,21 @@ chrome.runtime.onConnect.addListener(port => {
 
 Object.defineProperty(exports, "__esModule", ({ value: true }));
 exports.RELOAD_TAB_COMPLETE = exports.RELOADING_TAB = exports.EXPLORER_RESPONSE = exports.EXPLORER_REQUEST = exports.PANEL_CLOSED = exports.PANEL_OPEN = exports.UPDATE = exports.REQUEST_DATA = exports.ACTION_HOOK_FIRED = exports.CREATE_DEVTOOLS_PANEL = exports.APOLLO_CLIENT_FOUND = exports.FIND_APOLLO_CLIENT = exports.DEVTOOLS_INITIALIZED = exports.REQUEST_TAB_ID = exports.CLIENT_FOUND = void 0;
-exports.CLIENT_FOUND = "client-found";
-exports.REQUEST_TAB_ID = "request-tab-id";
-exports.DEVTOOLS_INITIALIZED = "devtools-initialized";
-exports.FIND_APOLLO_CLIENT = "find-apollo-client";
-exports.APOLLO_CLIENT_FOUND = "apollo-client-found";
-exports.CREATE_DEVTOOLS_PANEL = "create-devtools-panel";
-exports.ACTION_HOOK_FIRED = "action-hook-fired";
-exports.REQUEST_DATA = "request-data";
-exports.UPDATE = "update";
-exports.PANEL_OPEN = "panel-open";
-exports.PANEL_CLOSED = "panel-closed";
-exports.EXPLORER_REQUEST = "explorer-request";
-exports.EXPLORER_RESPONSE = "explorer-response";
-exports.RELOADING_TAB = "reloading-tab";
-exports.RELOAD_TAB_COMPLETE = "reload-tab-complete";
+exports.CLIENT_FOUND = "ac-devtools:client-found";
+exports.REQUEST_TAB_ID = "ac-devtools:request-tab-id";
+exports.DEVTOOLS_INITIALIZED = "ac-devtools:devtools-initialized";
+exports.FIND_APOLLO_CLIENT = "ac-devtools:find-apollo-client";
+exports.APOLLO_CLIENT_FOUND = "ac-devtools:apollo-client-found";
+exports.CREATE_DEVTOOLS_PANEL = "ac-devtools:create-devtools-panel";
+exports.ACTION_HOOK_FIRED = "ac-devtools:action-hook-fired";
+exports.REQUEST_DATA = "ac-devtools:request-data";
+exports.UPDATE = "ac-devtools:update";
+exports.PANEL_OPEN = "ac-devtools:panel-open";
+exports.PANEL_CLOSED = "ac-devtools:panel-closed";
+exports.EXPLORER_REQUEST = "ac-devtools:explorer-request";
+exports.EXPLORER_RESPONSE = "ac-devtools:explorer-response";
+exports.RELOADING_TAB = "ac-devtools:reloading-tab";
+exports.RELOAD_TAB_COMPLETE = "ac-devtools:reload-tab-complete";
 
 
 /***/ })
diff --git a/node_modules/apollo-client-devtools/build/devtools.js b/node_modules/apollo-client-devtools/build/devtools.js
index 165495f..8290715 100644
--- a/node_modules/apollo-client-devtools/build/devtools.js
+++ b/node_modules/apollo-client-devtools/build/devtools.js
@@ -165,22 +165,21 @@ exports["default"] = EventTarget;
 
 Object.defineProperty(exports, "__esModule", ({ value: true }));
 exports.RELOAD_TAB_COMPLETE = exports.RELOADING_TAB = exports.EXPLORER_RESPONSE = exports.EXPLORER_REQUEST = exports.PANEL_CLOSED = exports.PANEL_OPEN = exports.UPDATE = exports.REQUEST_DATA = exports.ACTION_HOOK_FIRED = exports.CREATE_DEVTOOLS_PANEL = exports.APOLLO_CLIENT_FOUND = exports.FIND_APOLLO_CLIENT = exports.DEVTOOLS_INITIALIZED = exports.REQUEST_TAB_ID = exports.CLIENT_FOUND = void 0;
-exports.CLIENT_FOUND = "client-found";
-exports.REQUEST_TAB_ID = "request-tab-id";
-exports.DEVTOOLS_INITIALIZED = "devtools-initialized";
-exports.FIND_APOLLO_CLIENT = "find-apollo-client";
-exports.APOLLO_CLIENT_FOUND = "apollo-client-found";
-exports.CREATE_DEVTOOLS_PANEL = "create-devtools-panel";
-exports.ACTION_HOOK_FIRED = "action-hook-fired";
-exports.REQUEST_DATA = "request-data";
-exports.UPDATE = "update";
-exports.PANEL_OPEN = "panel-open";
-exports.PANEL_CLOSED = "panel-closed";
-exports.EXPLORER_REQUEST = "explorer-request";
-exports.EXPLORER_RESPONSE = "explorer-response";
-exports.RELOADING_TAB = "reloading-tab";
-exports.RELOAD_TAB_COMPLETE = "reload-tab-complete";
-
+exports.CLIENT_FOUND = "ac-devtools:client-found";
+exports.REQUEST_TAB_ID = "ac-devtools:request-tab-id";
+exports.DEVTOOLS_INITIALIZED = "ac-devtools:devtools-initialized";
+exports.FIND_APOLLO_CLIENT = "ac-devtools:find-apollo-client";
+exports.APOLLO_CLIENT_FOUND = "ac-devtools:apollo-client-found";
+exports.CREATE_DEVTOOLS_PANEL = "ac-devtools:create-devtools-panel";
+exports.ACTION_HOOK_FIRED = "ac-devtools:action-hook-fired";
+exports.REQUEST_DATA = "ac-devtools:request-data";
+exports.UPDATE = "ac-devtools:update";
+exports.PANEL_OPEN = "ac-devtools:panel-open";
+exports.PANEL_CLOSED = "ac-devtools:panel-closed";
+exports.EXPLORER_REQUEST = "ac-devtools:explorer-request";
+exports.EXPLORER_RESPONSE = "ac-devtools:explorer-response";
+exports.RELOADING_TAB = "ac-devtools:reloading-tab";
+exports.RELOAD_TAB_COMPLETE = "ac-devtools:reload-tab-complete";
 
 /***/ }),
 
diff --git a/node_modules/apollo-client-devtools/build/hook.js b/node_modules/apollo-client-devtools/build/hook.js
index 63aa181..d6539a7 100644
--- a/node_modules/apollo-client-devtools/build/hook.js
+++ b/node_modules/apollo-client-devtools/build/hook.js
@@ -4712,21 +4712,21 @@ exports["default"] = EventTarget;
 
 Object.defineProperty(exports, "__esModule", ({ value: true }));
 exports.RELOAD_TAB_COMPLETE = exports.RELOADING_TAB = exports.EXPLORER_RESPONSE = exports.EXPLORER_REQUEST = exports.PANEL_CLOSED = exports.PANEL_OPEN = exports.UPDATE = exports.REQUEST_DATA = exports.ACTION_HOOK_FIRED = exports.CREATE_DEVTOOLS_PANEL = exports.APOLLO_CLIENT_FOUND = exports.FIND_APOLLO_CLIENT = exports.DEVTOOLS_INITIALIZED = exports.REQUEST_TAB_ID = exports.CLIENT_FOUND = void 0;
-exports.CLIENT_FOUND = "client-found";
-exports.REQUEST_TAB_ID = "request-tab-id";
-exports.DEVTOOLS_INITIALIZED = "devtools-initialized";
-exports.FIND_APOLLO_CLIENT = "find-apollo-client";
-exports.APOLLO_CLIENT_FOUND = "apollo-client-found";
-exports.CREATE_DEVTOOLS_PANEL = "create-devtools-panel";
-exports.ACTION_HOOK_FIRED = "action-hook-fired";
-exports.REQUEST_DATA = "request-data";
-exports.UPDATE = "update";
-exports.PANEL_OPEN = "panel-open";
-exports.PANEL_CLOSED = "panel-closed";
-exports.EXPLORER_REQUEST = "explorer-request";
-exports.EXPLORER_RESPONSE = "explorer-response";
-exports.RELOADING_TAB = "reloading-tab";
-exports.RELOAD_TAB_COMPLETE = "reload-tab-complete";
+exports.CLIENT_FOUND = "ac-devtools:client-found";
+exports.REQUEST_TAB_ID = "ac-devtools:request-tab-id";
+exports.DEVTOOLS_INITIALIZED = "ac-devtools:devtools-initialized";
+exports.FIND_APOLLO_CLIENT = "ac-devtools:find-apollo-client";
+exports.APOLLO_CLIENT_FOUND = "ac-devtools:apollo-client-found";
+exports.CREATE_DEVTOOLS_PANEL = "ac-devtools:create-devtools-panel";
+exports.ACTION_HOOK_FIRED = "ac-devtools:action-hook-fired";
+exports.REQUEST_DATA = "ac-devtools:request-data";
+exports.UPDATE = "ac-devtools:update";
+exports.PANEL_OPEN = "ac-devtools:panel-open";
+exports.PANEL_CLOSED = "ac-devtools:panel-closed";
+exports.EXPLORER_REQUEST = "ac-devtools:explorer-request";
+exports.EXPLORER_RESPONSE = "ac-devtools:explorer-response";
+exports.RELOADING_TAB = "ac-devtools:reloading-tab";
+exports.RELOAD_TAB_COMPLETE = "ac-devtools:reload-tab-complete";
 
 
 /***/ }),
@@ -4859,7 +4859,7 @@ function initializeHook() {
     });
     const clientRelay = new Relay_1.default();
     clientRelay.addConnection("tab", (message) => {
-        window.postMessage(message, "*");
+        window.postMessage(message);
     });
     window.addEventListener("message", ({ data }) => {
         clientRelay.broadcast(data);
diff --git a/node_modules/apollo-client-devtools/build/panel.js b/node_modules/apollo-client-devtools/build/panel.js
index 4b3ad6e..f7e021e 100644
--- a/node_modules/apollo-client-devtools/build/panel.js
+++ b/node_modules/apollo-client-devtools/build/panel.js
@@ -54713,21 +54713,21 @@ exports["default"] = EventTarget;
 
 Object.defineProperty(exports, "__esModule", ({ value: true }));
 exports.RELOAD_TAB_COMPLETE = exports.RELOADING_TAB = exports.EXPLORER_RESPONSE = exports.EXPLORER_REQUEST = exports.PANEL_CLOSED = exports.PANEL_OPEN = exports.UPDATE = exports.REQUEST_DATA = exports.ACTION_HOOK_FIRED = exports.CREATE_DEVTOOLS_PANEL = exports.APOLLO_CLIENT_FOUND = exports.FIND_APOLLO_CLIENT = exports.DEVTOOLS_INITIALIZED = exports.REQUEST_TAB_ID = exports.CLIENT_FOUND = void 0;
-exports.CLIENT_FOUND = "client-found";
-exports.REQUEST_TAB_ID = "request-tab-id";
-exports.DEVTOOLS_INITIALIZED = "devtools-initialized";
-exports.FIND_APOLLO_CLIENT = "find-apollo-client";
-exports.APOLLO_CLIENT_FOUND = "apollo-client-found";
-exports.CREATE_DEVTOOLS_PANEL = "create-devtools-panel";
-exports.ACTION_HOOK_FIRED = "action-hook-fired";
-exports.REQUEST_DATA = "request-data";
-exports.UPDATE = "update";
-exports.PANEL_OPEN = "panel-open";
-exports.PANEL_CLOSED = "panel-closed";
-exports.EXPLORER_REQUEST = "explorer-request";
-exports.EXPLORER_RESPONSE = "explorer-response";
-exports.RELOADING_TAB = "reloading-tab";
-exports.RELOAD_TAB_COMPLETE = "reload-tab-complete";
+exports.CLIENT_FOUND = "ac-devtools:client-found";
+exports.REQUEST_TAB_ID = "ac-devtools:request-tab-id";
+exports.DEVTOOLS_INITIALIZED = "ac-devtools:devtools-initialized";
+exports.FIND_APOLLO_CLIENT = "ac-devtools:find-apollo-client";
+exports.APOLLO_CLIENT_FOUND = "ac-devtools:apollo-client-found";
+exports.CREATE_DEVTOOLS_PANEL = "ac-devtools:create-devtools-panel";
+exports.ACTION_HOOK_FIRED = "ac-devtools:action-hook-fired";
+exports.REQUEST_DATA = "ac-devtools:request-data";
+exports.UPDATE = "ac-devtools:update";
+exports.PANEL_OPEN = "ac-devtools:panel-open";
+exports.PANEL_CLOSED = "ac-devtools:panel-closed";
+exports.EXPLORER_REQUEST = "ac-devtools:explorer-request";
+exports.EXPLORER_RESPONSE = "ac-devtools:explorer-response";
+exports.RELOADING_TAB = "ac-devtools:reloading-tab";
+exports.RELOAD_TAB_COMPLETE = "ac-devtools:reload-tab-complete";
 
 
 /***/ }),
diff --git a/node_modules/apollo-client-devtools/build/tab.js b/node_modules/apollo-client-devtools/build/tab.js
index 9ed84be..702f76c 100644
--- a/node_modules/apollo-client-devtools/build/tab.js
+++ b/node_modules/apollo-client-devtools/build/tab.js
@@ -135,21 +135,21 @@ exports["default"] = EventTarget;
 
 Object.defineProperty(exports, "__esModule", ({ value: true }));
 exports.RELOAD_TAB_COMPLETE = exports.RELOADING_TAB = exports.EXPLORER_RESPONSE = exports.EXPLORER_REQUEST = exports.PANEL_CLOSED = exports.PANEL_OPEN = exports.UPDATE = exports.REQUEST_DATA = exports.ACTION_HOOK_FIRED = exports.CREATE_DEVTOOLS_PANEL = exports.APOLLO_CLIENT_FOUND = exports.FIND_APOLLO_CLIENT = exports.DEVTOOLS_INITIALIZED = exports.REQUEST_TAB_ID = exports.CLIENT_FOUND = void 0;
-exports.CLIENT_FOUND = "client-found";
-exports.REQUEST_TAB_ID = "request-tab-id";
-exports.DEVTOOLS_INITIALIZED = "devtools-initialized";
-exports.FIND_APOLLO_CLIENT = "find-apollo-client";
-exports.APOLLO_CLIENT_FOUND = "apollo-client-found";
-exports.CREATE_DEVTOOLS_PANEL = "create-devtools-panel";
-exports.ACTION_HOOK_FIRED = "action-hook-fired";
-exports.REQUEST_DATA = "request-data";
-exports.UPDATE = "update";
-exports.PANEL_OPEN = "panel-open";
-exports.PANEL_CLOSED = "panel-closed";
-exports.EXPLORER_REQUEST = "explorer-request";
-exports.EXPLORER_RESPONSE = "explorer-response";
-exports.RELOADING_TAB = "reloading-tab";
-exports.RELOAD_TAB_COMPLETE = "reload-tab-complete";
+exports.CLIENT_FOUND = "ac-devtools:client-found";
+exports.REQUEST_TAB_ID = "ac-devtools:request-tab-id";
+exports.DEVTOOLS_INITIALIZED = "ac-devtools:devtools-initialized";
+exports.FIND_APOLLO_CLIENT = "ac-devtools:find-apollo-client";
+exports.APOLLO_CLIENT_FOUND = "ac-devtools:apollo-client-found";
+exports.CREATE_DEVTOOLS_PANEL = "ac-devtools:create-devtools-panel";
+exports.ACTION_HOOK_FIRED = "ac-devtools:action-hook-fired";
+exports.REQUEST_DATA = "ac-devtools:request-data";
+exports.UPDATE = "ac-devtools:update";
+exports.PANEL_OPEN = "ac-devtools:panel-open";
+exports.PANEL_CLOSED = "ac-devtools:panel-closed";
+exports.EXPLORER_REQUEST = "ac-devtools:explorer-request";
+exports.EXPLORER_RESPONSE = "ac-devtools:explorer-response";
+exports.RELOADING_TAB = "ac-devtools:reloading-tab";
+exports.RELOAD_TAB_COMPLETE = "ac-devtools:reload-tab-complete";
 
 
 /***/ }),
@@ -260,22 +260,22 @@ __webpack_require__(/*! ./tabRelay */ "./src/extension/tab/tabRelay.ts");
   A common workaround for this issue is to inject an inlined function
   into the inspected tab.
 */
-if (typeof document === "object" && document instanceof HTMLDocument) {
-    const script = document.createElement("script");
-    script.setAttribute("type", "module");
-    script.setAttribute("src", chrome.extension.getURL("hook.js"));
-    document.addEventListener("DOMContentLoaded", () => {
-        var _a;
-        const importMap = document.querySelector("script[type=\"importmap\"]");
-        if (importMap != null) {
-            (_a = importMap.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(script, importMap.nextSibling);
-        }
-        else {
-            const head = document.head || document.getElementsByTagName("head")[0] || document.documentElement;
-            head.insertBefore(script, head.lastChild);
-        }
-    });
-}
+// if (typeof document === "object" && document instanceof HTMLDocument) {
+//     const script = document.createElement("script");
+//     script.setAttribute("type", "module");
+//     script.setAttribute("src", chrome.extension.getURL("hook.js"));
+//     document.addEventListener("DOMContentLoaded", () => {
+//         var _a;
+//         const importMap = document.querySelector("script[type=\"importmap\"]");
+//         if (importMap != null) {
+//             (_a = importMap.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(script, importMap.nextSibling);
+//         }
+//         else {
+//             const head = document.head || document.getElementsByTagName("head")[0] || document.documentElement;
+//             head.insertBefore(script, head.lastChild);
+//         }
+//     });
+// }
 
 })();
 


================================================
FILE: docs/README.md
================================================
# Documentation

- [Getting Started](getting-started.md)
- [Debugger Integration](debugger-integration.md)
- [React DevTools Integration](react-devtools-integration.md)
- [Redux DevTools Integration](redux-devtools-integration.md)
- [Apollo Client DevTools Integration](apollo-client-devtools-integration.md)
- [Shortcuts references](shortcut-references.md)
- [Network inspect of Chrome Developer Tools](network-inspect-of-chrome-devtools.md)
- [Enable open in editor in console](enable-open-in-editor-in-console.md)
- [Config file in home directory](config-file-in-home-directory.md)
- [Troubleshooting](troubleshooting.md)
- [Contributing](contributing.md)


================================================
FILE: docs/apollo-client-devtools-integration.md
================================================
# Apollo Client DevTools Integration

React Native debugger has integration for the [Apollo Client DevTools](https://github.com/apollographql/apollo-client-devtools), you can see the `Apollo` tab in Developer Tools:

<img width="547" alt="screen shot 2019-02-01 at 1 51 27 pm" src="https://user-images.githubusercontent.com/3001525/52105143-8006fe00-2628-11e9-8276-09bdeb23e3b2.png">

To ensure it works, you must use Apollo Client ^2.0.

If the apollo tab doesn't appear, toggle developer tools off and on again.

You can read Apollo DevTools [documentation](https://github.com/apollographql/apollo-client-devtools#apollo-client-devtools)). 


## Other documentations

- [Getting Started](getting-started.md)
- [Debugger Integration](debugger-integration.md)
- [React DevTools Integration](react-devtools-integration.md)
- [Redux DevTools Integration](redux-devtools-integration.md)
- [Shortcut references](shortcut-references.md)
- [Network inspect of Chrome Developer Tools](network-inspect-of-chrome-devtools.md)
- [Enable open in editor in console](enable-open-in-editor-in-console.md)
- [Config file in home directory](config-file-in-home-directory.md)
- [Troubleshooting](troubleshooting.md)
- [Contributing](contributing.md)


================================================
FILE: docs/config-file-in-home-directory.md
================================================
# Config file in home directory

We could configure RNDebugger app in `~/.rndebuggerrc` (the config can be opened from the main menu: Debugger → Open Config File), the file used [json5](https://github.com/json5/json5) as format, see the following default template:


```json5
{
  // Font family of the debugger window
  fontFamily: 'monaco, Consolas, Lucida Console, monospace',

  // Zoom level of the debugger window, it will override persited zoomLevel
  zoomLevel: 0,

  // Settings of debugger window,
  windowBounds: {
    // Size of the debugger window, it will override persisted size
    width: 1024,
    height: 750,

    // Show frame for debugger window
    // but due to https://github.com/electron/electron/issues/3647
    // so we can't have custom title bar if no frame
    frame: true,
  },

  // Auto check update on RNDebugger startup
  autoUpdate: true,

  // RNDebugger will open debugger window with the ports when app launched
  defaultRNPackagerPorts: [8081],

  // Env for
  // open React DevTools source file link
  // and enable open in editor for console log for RNDebugger
  editor: '',

  // Set default react-devtools theme (default is match Chrome DevTools theme)
  // but the default theme doesn't change manually changed theme
  // see https://github.com/facebook/react-devtools/blob/master/frontend/Themes/Themes.js to get more
  defaultReactDevToolsTheme: 'RNDebugger',

  // Set default react-devtools port (default is \`19567+\` if it is not being used).
  // The devtools backend of React Native will use the port to connect to the devtools server.
  // You should use that if you have some rules for binding port.
  //   (like https://github.com/jhen0409/react-native-debugger/issues/397)
  defaultReactDevToolsPort: 19567,

  // Enable Network Inspect by default
  // See https://github.com/jhen0409/react-native-debugger/blob/master/docs/network-inspect-of-chrome-devtools.md
  defaultNetworkInspect: false,

  // Refresh devtools when doing JS reload every N times. (-1 for disabled)
  // This can effectively avoid possible memory leaks (Like
  // https://github.com/jhen0409/react-native-debugger/issues/405) in devtools.
  timesJSLoadToRefreshDevTools: -1,
}
```

## Other documentations

- [Getting Started](getting-started.md)
- [Debugger Integration](debugger-integration.md)
- [React DevTools Integration](react-devtools-integration.md)
- [Redux DevTools Integration](redux-devtools-integration.md)
- [Apollo Client DevTools Integration](apollo-client-devtools-integration.md)
- [Shortcut references](shortcut-references.md)
- [Network inspect of Chrome Developer Tools](network-inspect-of-chrome-devtools.md)
- [Enable open in editor in console](enable-open-in-editor-in-console.md)
- [Troubleshooting](troubleshooting.md)
- [Contributing](contributing.md)


================================================
FILE: docs/contributing.md
================================================
# Contributing

## Development

### Fork this repo & install dependencies

We're recommended use yarn because we keep the dependencies lock of yarn.

```bash
# In react-native-debugger directory
$ yarn
$ cd npm-package && yarn && cd ..
```

If you want to debug the [NPM package](../npm-package), just run `npm link <the package path>` on your React Native project.

### Run on development mode
_Please ensure the `React Native Debugger` production / distribution app is closed._

```bash
$ yarn dev:webpack  # Then open the another terminal tab
$ yarn dev:electron
```
1. From here, you can open a react-native project with remote debugging enabled. 
1. To see the development build of the react-native-debugger, do x,y,z

### Run on production mode

```bash
$ yarn build
$ yarn start
```

### Run test

Run lint and test, currently we just wrote E2E test for RNDebugger.

```bash
$ yarn test
$ yarn test-e2e
```

You need to closes all React Native packager (make sure `8081` or `8088` port not listening) when running the test.

### Packaging app

```bash
$ yarn run pack-macos # Use --notarize to notarize app
# On macOS: brew install fakeroot dpkg rpm
$ yarn run pack-linux
# On macOS: brew install wine mono
$ yarn run pack-windows
$ yarn run pack # all
```

If you want to build binaries yourself, please remove [../electron/update.js](electron/update.js) (and [electon/main.js usage](electon/main.js)).

For macOS, note that if your app binary is not code signed, you will often get a firewall prompt from React DevTools server.

### [Optional] Prerequisites for packaging Linux / Windows app on macOS

```bash
# Linux
brew install fakeroot dpkg rpm

# Windows
brew tap homebrew/cask-versions
brew install wine-stable mono
```

## Financial contributions

We also welcome financial contributions in full transparency on our [open collective](https://opencollective.com/react-native-debugger).
Anyone can file an expense. If the expense makes sense for the development of the community, it will be "merged" in the ledger of our open collective by the core contributors and the person who filed the expense will be reimbursed.

## Credits

### Contributors

Thank you to all the people who have already contributed to react-native-debugger!

### Backers

Thank you to all our backers! [[Become a backer](https://opencollective.com/react-native-debugger#backer)]

<a href="https://opencollective.com/react-native-debugger#backers" target="_blank"><img src="https://opencollective.com/react-native-debugger/backers.svg?width=890"></a>

### Sponsors

Thank you to all our sponsors! (please ask your company to also support this open source project by [becoming a sponsor](https://opencollective.com/react-native-debugger#sponsor))

<a href="https://opencollective.com/react-native-debugger#backers" target="_blank"><img src="https://opencollective.com/react-native-debugger/sponsors.svg?width=890"></a>

## Other documentations

- [Getting Started](getting-started.md)
- [Debugger Integration](debugger-integration.md)
- [React DevTools Integration](react-devtools-integration.md)
- [Redux DevTools Integration](redux-devtools-integration.md)
- [Apollo Client DevTools Integration](apollo-client-devtools-integration.md)
- [Shortcut references](shortcut-references.md)
- [Network inspect of Chrome Developer Tools](network-inspect-of-chrome-devtools.md)
- [Enable open in editor in console](enable-open-in-editor-in-console.md)
- [Config file in home directory](config-file-in-home-directory.md)
- [Troubleshooting](troubleshooting.md)


================================================
FILE: docs/debugger-integration.md
================================================
# Debugger integration

The Debugger worker is referenced from [react-native](https://github.com/facebook/react-native/blob/master/local-cli/server/util/) debugger-ui, so it's only working if you're enabled `Debug JS Remotely`, you can debug your app in Chrome Developer Tools, we keep the following tabs:

- `Console`
- `Sources`
- `Network` (Inspect Network requests if you are enabled [Network Inspect](network-inspect-of-chrome-devtools.md))
- `Memory`

## Multiple React Native packager (custom port) support

We can use [`react-native-debugger-open`](../npm-package) package to detect RN packager port, it will open an another window automatically if another debugger workers are running.

If you don't use [the npm package](../npm-package) and want to change port, click `Debugger` -> `New Window` (`Command⌘ + T` for macOS, `Ctrl + T` for Linux / Windows) in application menu, you need to type an another RN packager port. The default port is use [`Expo`](https://github.com/expo/expo) (and [`create-react-native-app`](https://github.com/react-community/create-react-native-app)) default port.

For macOS (10.12+), it used native tabs feature, see [the support page](https://support.apple.com/en-us/HT206998) for known how to use and setting.

## Debugging tips

#### Global variables in console

When you enabled remote debugging, RNDebugger should switched context to `RNDebuggerWorker.js` automatically, so you can get global variables of React Native runtime in the console.

- `$r`: You selected element on react-devtools.
- `showAsyncStorageContentInDev()` - Log AsyncStorage content
- `$reactNative.*` - Get react-native modules. For example, you can get `$reactNative.AsyncStorage`

#### Enable `Debug Remotely` programmatically

For enable `Debug Remotely` without using dev menu, you can use the built-in `DevSettings` native module:

```js
import { NativeModules } from 'react-native'

if (__DEV__) {
  NativeModules.DevSettings.setIsDebuggingRemotely(true)
}
```

If you're using Expo, you can still use the method, but it probably only works with `jsEngine: jsc` in `app.json`, `jsEngine: hermes` may not works.

## Other documentations

- [Getting Started](getting-started.md)
- [React DevTools Integration](react-devtools-integration.md)
- [Redux DevTools Integration](redux-devtools-integration.md)
- [Apollo Client DevTools Integration](apollo-client-devtools-integration.md)
- [Shortcut references](shortcut-references.md)
- [Network inspect of Chrome Developer Tools](network-inspect-of-chrome-devtools.md)
- [Enable open in editor in console](enable-open-in-editor-in-console.md)
- [Config file in home directory](config-file-in-home-directory.md)
- [Troubleshooting](troubleshooting.md)
- [Contributing](contributing.md)


================================================
FILE: docs/enable-open-in-editor-in-console.md
================================================
# Enable open in editor in console

You can toggle the application menu item:

<img width="386" alt="2017-08-16 10 44 41" src="https://user-images.githubusercontent.com/3001525/29369913-91f2e584-8269-11e7-8ebb-10d881aa5f0a.png">

Instead of open file in `Sources` tab, you can open file in editor by click source link in console. This feature is disabled by default.

## Known issues

- Currently this feature doesn't work with Haul bundler, please tracking [issue #141](https://github.com/jhen0409/react-native-debugger/issues/141).

## Other documentations

- [Getting Started](getting-started.md)
- [Debugger Integration](debugger-integration.md)
- [React DevTools Integration](react-devtools-integration.md)
- [Redux DevTools Integration](redux-devtools-integration.md)
- [Apollo Client DevTools Integration](apollo-client-devtools-integration.md)
- [Shortcut references](shortcut-references.md)
- [Network inspect of Chrome Developer Tools](network-inspect-of-chrome-devtools.md)
- [Config file in home directory](config-file-in-home-directory.md)
- [Troubleshooting](troubleshooting.md)
- [Contributing](contributing.md)


================================================
FILE: docs/getting-started.md
================================================
# Getting Started

Just these steps will let you start RNDebugger out of box:

- Install the latest version ([download page](https://github.com/jhen0409/react-native-debugger/releases)).
- Make sure all debugger clients of React Native are closed, usually are `http://localhost:<port>/debugger-ui`
- Make sure RNDebugger is open and wait state.
- RNDebugger will try connect to debugger proxy, use port `8081` by default, you can create a new debugger window (macOS: `Command+T`, Linux/Windows: `Ctrl+T`) to specify the port if you want.
- Enable `Debug JS Remotely` of [developer menu](https://reactnative.dev/docs/debugging#accessing-the-in-app-developer-menu) on your app

## Launch by CLI or React Native packager

Platform: macOS / Linux

### The `rndebugger:` URI scheme

Launch RNDebugger by typing the following command:

```bash
$ open "rndebugger://set-debugger-loc?host=localhost&port=8081"
```

Or `xdg-open` for Linux:

```bash
$ xdg-open "rndebugger://set-debugger-loc?host=localhost&port=8081"
```

The `host` / `port` means React Native packager. You may need to set `port` if you customize the packager port. (`8081` by default)

From [`Debugging using a custom JavaScript debugger`](https://reactnative.dev/docs/0.71/debugging#debugging-using-a-custom-javascript-debugger) of React Native docs, you can use `REACT_DEBUGGER` env on react-native packager, it will try to launch RNDebugger when you turn on `Debug JS Remotely`:

```bash
$ REACT_DEBUGGER="unset ELECTRON_RUN_AS_NODE && open -g 'rndebugger://set-debugger-loc?port=19000' ||" npm start
```

You can use `open` on macOS or `xdg-open` on Linux, currently it is not supported for Windows.

### Use [`react-native-debugger-open`](../npm-package)

If you don‘t need to add a dependency, you can use the package, it can help with:

- Replace `open debugger-ui with Chrome` to `open React Native Debugger` in react-native packager, saving you from closing the debugger-ui page everytime it automatically opens :)
- Detect react-native packager port then send to the app, if you launch packager with custom `--port` or use Expo, this will be very useful

### What about Windows support?

Currently the `rndebugger:` URI scheme doesn't support for Windows.

In [`react-native-debugger-open`](../npm-package), it can be sent the `host` / `port` setting if RNDebugger opened, but can't automatically open if closed.

If you want to have the feature (`rndebugger:` or another way), you are welcome to contribute. Please read [contributing](https://github.com/jhen0409/react-native-debugger/blob/master/docs/contributing.md) to become a maintainer.

## Use Redux DevTools Extension API

Using the same API as [`redux-devtools-extension`](https://github.com/zalmoxisus/redux-devtools-extension#1-with-redux) is very simple:

```js
const store = createStore(
  reducer /* preloadedState, */,
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
)
```

See [`Redux DevTools Integration`](redux-devtools-integration.md) section for more information.

## Platform support

- [React Native](https://github.com/facebook/react-native) >= 0.43
- [React Native for macOS](https://github.com/ptmt/react-native-macos) (formerly react-native-desktop) >= 0.14.0
- [React Native for Windows](https://github.com/Microsoft/react-native-windows)

## Auto-update RNDebugger app (Supported v0.5.0 after)

Currently auto-update is only supported for macOS. Linux and Windows will show a dialog of new versions available for download.

You can also click `React Native Debugger` (`RND` for Linux / Windows) -> `Check for Updates...` in the application menu.

## Other documentations

- [Debugger Integration](debugger-integration.md)
- [React DevTools Integration](react-devtools-integration.md)
- [Redux DevTools Integration](redux-devtools-integration.md)
- [Apollo Client DevTools Integration](apollo-client-devtools-integration.md)
- [Shortcut references](shortcut-references.md)
- [Network inspect of Chrome Developer Tools](network-inspect-of-chrome-devtools.md)
- [Enable open in editor in console](enable-open-in-editor-in-console.md)
- [Config file in home directory](config-file-in-home-directory.md)
- [Troubleshooting](troubleshooting.md)
- [Contributing](contributing.md)


================================================
FILE: docs/network-inspect-of-chrome-devtools.md
================================================
# Network Inspect of Chrome Developer Tools

**_WARNING_**: You should read [the limitations](#limitations) if you want to use this feature.

When you have Network Inspect enabled you can inspect network requests that use `XMLHttpRequest` or `fetch` on the `Network` tab of Chrome Developer Tools.

You can enable this feature by one of these ways:

- [context menu or Touch Bar](shortcut-references.md) (Network Inspect will be enabled while the RNDebugger is running, after closing it will reset to the default value);
- by the `defaultNetworkInspect` option in the [config file](config-file-in-home-directory.md) (Network Inspect will be enabled permanently).

## How it works

See [the comments of `react-native/Libraries/Utilities/PolyfillFunctions#L15-L27`](https://github.com/facebook/react-native/blob/ab97b9f6021d2b31b7155970c2be0c83f7e43f04/Libraries/Utilities/PolyfillFunctions.js#L15-L27). It uses `XMLHttpRequest` from WebWorker in Chrome, basically it can manually setup by:

```js
global.XMLHttpRequest = global.originalXMLHttpRequest
  ? global.originalXMLHttpRequest
  : global.XMLHttpRequest;
global.FormData = global.originalFormData
  ? global.originalFormData
  : global.FormData;

fetch; // Ensure to get the lazy property

if (window.__FETCH_SUPPORT__) {
  // it's RNDebugger only to have
  window.__FETCH_SUPPORT__.blob = false;
} else {
  /*
   * Set __FETCH_SUPPORT__ to false is just work for `fetch`.
   * If you're using another way you can just use the native Blob and remove the `else` statement
   */
  global.Blob = global.originalBlob ? global.originalBlob : global.Blob;
  global.FileReader = global.originalFileReader
    ? global.originalFileReader
    : global.FileReader;
}
```

> Note that replace `global.Blob` will cause issue like [#56](https://github.com/jhen0409/react-native-debugger/issues/56).

This allows you can open the `Network` tab in devtools to inspect requests of `fetch` and `XMLHttpRequest`.

You can also do this on the official remote debugger, but it has two differences:

- RNDebugger is based on [Electron](https://github.com/electron/electron) so it doesn't have the CORS issue
- We support setting [`Forbidden header names`](https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name), so you can use headers like `Origin` and `User-Agent`.

## Limitations

There are some limitations of debugging network requests using Network Inspect:

- [iOS] Requests pass `NSExceptionDomains` checks. If you forget to set a domain name, the requests will break in production. You should be clear about the difference.
- [Android] If your network request would have caused `java.security.cert.CertPathValidatorException`, the Network Inpsect will skip that because it uses Debugger's network client.
- React Native `FormData` supports the `uri` property. You can use files from `CameraRoll`, but `originalFormData` isn't supported.
- It can't inspect request like `Image`s loaded from urls for `src`, so if your `Image` source has a set session, the session can't apply to `fetch` and `XMLHttpRequest`.

If you want to inspect deeper network requests (like requests made with `Image`), use tools like [Charles](https://www.charlesproxy.com) or [Flipper](https://github.com/facebook/flipper).

## Other documentations

- [Getting Started](getting-started.md)
- [Debugger Integration](debugger-integration.md)
- [React DevTools Integration](react-devtools-integration.md)
- [Redux DevTools Integration](redux-devtools-integration.md)
- [Apollo Client DevTools Integration](apollo-client-devtools-integration.md)
- [Shortcut references](shortcut-references.md)
- [Enable open in editor in console](enable-open-in-editor-in-console.md)
- [Config file in home directory](config-file-in-home-directory.md)
- [Troubleshooting](troubleshooting.md)
- [Contributing](contributing.md)


================================================
FILE: docs/react-devtools-integration.md
================================================
# React DevTools Integration

**_NOTE_** Supported React Native version is `>= 0.62`. Please downgrade RNDebugger version to `0.10` if you're using older versions of React Native.

The [React DevTools](https://reactnative.dev/docs/debugging#react-developer-tools) is built by [`facebook/react/packages/react-devtools-core`](https://github.com/facebook/react/tree/master/packages/react-devtools-core).

It will open a WebSocket server to waiting React Native connection. The connection is already included in React Native (see [`setUpReactDevTools.js`](https://github.com/facebook/react-native/blob/0.62-stable/Libraries/Core/setUpReactDevTools.js)), it will keep trying to connect the React DevTools server in development mode, it should work well without any specification.

We made the server listen to a random port and inject `window.__REACT_DEVTOOLS_PORT__` global variable in debugger worker.

For Android, we have the built-in `adb` util and it will reverse the port automatically.

## Get `$r` global variable of React Native runtime in the console

Refer to [`Debugger Integration`](debugger-integration.md#debugging-tips).

## **_Question_**: I got `Unsupported` message from React DevTools

If you're using React Native version >= 0.62 and keep React Native Debugger as the latest version, here is what you can do:

In your app project, make sure the `react-devtools-core` dependency to match the React DevTools version. Add resolutions in your `package.json` for Yarn:

```json
{
  "resolutions": {
    "react-devtools-core": "~4.28.0"
  }
}
```

or NPM:

```json
{
  "overrides": {
    "react-devtools-core": "~4.28.0"
  }
}
```

Reference: [Unsupported DevTools backend version - # React Native Debugger](https://gist.github.com/bvaughn/4bc90775530873fdf8e7ade4a039e579#react-native-debugger)

If the React Native version of your project doesn't support `react-devtools-core@4.25`, please consider downgrade React Native Debugger version to v0.12.

## Other documentations

- [Getting Started](getting-started.md)
- [Debugger Integration](debugger-integration.md)
- [Redux DevTools Integration](redux-devtools-integration.md)
- [Apollo Client DevTools Integration](apollo-client-devtools-integration.md)
- [Shortcut references](shortcut-references.md)
- [Network inspect of Chrome Developer Tools](network-inspect-of-chrome-devtools.md)
- [Enable open in editor in console](enable-open-in-editor-in-console.md)
- [Config file in home directory](config-file-in-home-directory.md)
- [Troubleshooting](troubleshooting.md)
- [Contributing](contributing.md)


================================================
FILE: docs/redux-devtools-integration.md
================================================
# Redux DevTools Integration

We used [@redux-devtools/app](https://github.com/reduxjs/redux-devtools/tree/main/packages/redux-devtools-app) and made the API same with [Redux DevTools Extension](https://github.com/reduxjs/redux-devtools/tree/main/extension).

If you've enabled `Debug JS remotely` with React Native Debugger, the following API is already included in global:

- `window.__REDUX_DEVTOOLS_EXTENSION__`
- `window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__`
- `window.__REDUX_DEVTOOLS_EXTENSION__.connect`
- You can just use [`redux-devtools-extension`](https://www.npmjs.com/package/redux-devtools-extension) npm package.

See also:

- [Redux DevTools main repository]](https://github.com/reduxjs/redux-devtools/blob/main/README.md)
- [API Reference](https://github.com/reduxjs/redux-devtools/tree/main/extension/docs/API)
- [Troubleshooting](https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/Troubleshooting.md)
- Other Integrations
  - [`mobx-state-tree`](https://github.com/mobxjs/mobx-state-tree) - Use [`connectReduxDevtools`](https://github.com/mobxjs/mobx-state-tree/tree/3fc79b0b3ce7ad3e26d6bd5745fd9412d35c431c/packages/mst-middlewares#connectreduxdevtools) middleware.

You can ignore the things specified by the browser extension.

## About `trace` feature

- The debugger app might be slowed down if you enabled the `trace` feature and visited the `Trace` tab, because it will load and parse the source map for every selected action.

## Other documentations

- [Getting Started](getting-started.md)
- [Debugger Integration](debugger-integration.md)
- [React DevTools Integration](react-devtools-integration.md)
- [Apollo Client DevTools Integration](apollo-client-devtools-integration.md)
- [Shortcut references](shortcut-references.md)
- [Network inspect of Chrome Developer Tools](network-inspect-of-chrome-devtools.md)
- [Enable open in editor in console](enable-open-in-editor-in-console.md)
- [Config file in home directory](config-file-in-home-directory.md)
- [Troubleshooting](troubleshooting.md)
- [Contributing](contributing.md)


================================================
FILE: docs/shortcut-references.md
================================================
# Shortcut references

This section will explain about the following items in RNDebugger.

- [Content menu](#context-menu)
- [Touch Bar](#touch-bar-in-macos)
- [Keyboard shortcuts](#keyboard-shortcuts)

## Context menu

We have context menu (right-click) for provides useful features:

![Context menu](https://cloud.githubusercontent.com/assets/3001525/25920996/5c488966-3606-11e7-8d0c-cb564671067b.gif)

- Reload
- Toggle Elements Inspector
- Show Developer Menu [iOS only]
- Enable / Disable [Network Inspect](debugger-integration.md#how-network-inspect-works)
- Log AsyncStorage content
- Clear AsyncStorage

It includes the developer menu features, these would be useful for real device, instead of open developer menu in device manually.

## Keyboard shortcuts

- Reload JS (macOS: `Command+R`, Windows / Linux: `Ctrl+R`)
- Toggle Elements Inspector (macOS: `Command+I`, Windows / Linux: `Ctrl+I`)
- New Debugger Window (macOS: `Command+T`, Windows / Linux: `Ctrl+T`)
- Toggle Developer Tools (macOS: `Command+Option+I`, Windows / Linux: `Ctrl+Alt+I`)
- Toggle Redux DevTools (macOS: `Command+Option+J`, Windows / Linux: `Ctrl+Alt+J`)
- Toggle React DevTools (macOS: `Command+Option+K`, Windows / Linux: `Ctrl+Alt+K`)
- Quickly into search field of React DevTools (Type `/`)

You can also read [Keyboard Shortcuts Reference of Chrome Developer Tools](https://developers.google.com/web/tools/chrome-devtools/shortcuts).

## Touch Bar in macOS

<img alt="touch-bar" src="https://user-images.githubusercontent.com/3001525/27730359-8565810a-5dbb-11e7-9052-9fd4feb72181.png">

The `Redux Slider` will shown on right if you're using [`Redux API`](redux-devtools-integration.md),

If your Mac haven't TouchBar support and you still want to use the feature, you can use [Touché](https://redsweater.com/touche/).

## Other documentations

- [Getting Started](getting-started.md)
- [Debugger Integration](debugger-integration.md)
- [React DevTools Integration](react-devtools-integration.md)
- [Redux DevTools Integration](redux-devtools-integration.md)
- [Apollo Client DevTools Integration](apollo-client-devtools-integration.md)
- [Network inspect of Chrome Developer Tools](network-inspect-of-chrome-devtools.md)
- [Enable open in editor in console](enable-open-in-editor-in-console.md)
- [Config file in home directory](config-file-in-home-directory.md)
- [Troubleshooting](troubleshooting.md)
- [Contributing](contributing.md)


================================================
FILE: docs/troubleshooting.md
================================================
# Troubleshooting

## I got `Unsupported` meesage from React DevTools

If you're using React Native version >= 0.62 and keep React Native Debugger as the latest version, here is what you can do:

In your app project, make sure the `react-devtools-core` dependency to match the React DevTools version. Add resolutions in your `package.json` for Yarn:

```json
{
  "resolutions": {
    "react-devtools-core": "~4.28.0"
  }
}
```

or NPM:

```json
{
  "overrides": {
    "react-devtools-core": "~4.28.0"
  }
}
```

Reference: [Unsupported DevTools backend version - # React Native Debugger](https://gist.github.com/bvaughn/4bc90775530873fdf8e7ade4a039e579#react-native-debugger)

If the React Native version of your project doesn't support `react-devtools-core@4.25`, please consider downgrade React Native Debugger version to v0.12.

## Network fetch got issue like [`SyntaxError: Unexpected token o in JSON at position 1`](https://github.com/jhen0409/react-native-debugger/issues/382#issuecomment-544226529) if Network Inspect enabled

This may be caused by some library used / made fetch polyfills, it may used `Blob` but RNDebugger does not support it. If you got this issue, try to use global `fetch` / `XMLHttpRequest` instead, or try [#382#issuecomment-544226529](https://github.com/jhen0409/react-native-debugger/issues/382#issuecomment-544226529).

## Debugger causes app to load stale JS bundle ([#423](https://github.com/jhen0409/react-native-debugger/issues/423))

This issue was fixed by [v0.10.9](https://github.com/jhen0409/react-native-debugger/releases/tag/v0.10.9) and [v0.11.1](https://github.com/jhen0409/react-native-debugger/releases/tag/v0.11.1). If you are still using the old version for some reason, you can turn off Network cache manually on devtools:

![image](https://user-images.githubusercontent.com/848589/69504219-b0d46d00-0f85-11ea-99ed-de5e4e2e59c0.png)

## Some shortcuts (e.g. `Reload` / `Clear AsyncStorage`) are missing on the Debugger

- For Android and React Native version less than v0.60, you need to add and link [`react-native-devsettings-android`](https://github.com/jhen0409/react-native-devsettings-android) package
- If you're not using dev bundle (dev=true) from React Native packager, it will not working as expected.
- For some reasons, some dependencies may affected [Promise](https://github.com/jhen0409/react-native-debugger/blob/master/app/worker/utils.js#L7) behavior. It is recommended to use the initial project to find out the reason.
- If you are sure it is caused by a new version of React Native, please file an new issue.

## How to resolve problem of high memory usage on devtools?

You may have got a problem when you often reload JS, devtools process takes your RAM even more than 1G, it does not seem to clean.

In case of using [official remote debugger](https://reactnative.dev/docs/debugging#chrome-developer-tools), tested a initial project with remote debugging mode on Chrome 62 (beta), continuous reload JS 30 times:

Before:  
<img width="600" alt="2017-09-19 5 32 05 pm" src="https://user-images.githubusercontent.com/3001525/30585922-ed1e557a-9cf3-11e7-9730-3b941618924f.png">

After:  
<img width="600" alt="2017-09-19 5 31 33 pm" src="https://user-images.githubusercontent.com/3001525/30585923-ed1e3a54-9cf3-11e7-8d09-9915f8cffea6.png">

Fortunately, the current versions of RNDebugger (Chromium 58) is better than Chrome (maybe >= 59?), but it still has a amount of growth:

Before:  
<img width="704" alt="2017-09-19 5 40 18 pm" src="https://user-images.githubusercontent.com/3001525/30586300-27e0df7e-9cf5-11e7-9614-07162e86680c.png">

After:  
<img width="704" alt="2017-09-19 5 41 27 pm" src="https://user-images.githubusercontent.com/3001525/30586302-29e0b268-9cf5-11e7-9206-e222bd753aa1.png">

To avoid similar problems in the future, there is a way to restart the Chrome devtools (macOS: `CMD+OPTION+I`, Linux/Windows: `CTRL+ALT+I`), the same applies to official remote debugger on Chrome. You can also consider to use [`timesJSLoadToRefreshDevTools` option in Config file in home directory](config-file-in-home-directory.md).

## [iOS] Debugger can't load bundle when I use real device

If you're getting the following error:

![](https://user-images.githubusercontent.com/3001525/28763926-214df82c-75f4-11e7-98bc-1be54638f91b.png)

It may caused by [`xip.io`](http://xip.io) service (RN use it for debug on real device), it lead your machine IP doesn't resolved sometimes. It's [enabled by default](https://github.com/facebook/react-native/blob/ca9202f2385354b7a6b4d818ceb46bd96a037a7b/scripts/react-native-xcode.sh#L94), you can disable it in RN custom script on Xcode if you sure you don't need the service:

<img width="839" alt="2017-07-31 1 19 34" src="https://user-images.githubusercontent.com/3001525/28763831-82811012-75f3-11e7-9675-d5ae515f4f38.png">

## React Inspector get stuck at "Connecting to React…" for RN ^0.43 ([#45](https://github.com/jhen0409/react-native-debugger/issues/45))

It usually on Android, the problem is related to `requestIdleCallback` API (try to check if it not work on debug mode).

This issue have been fixed in `react-devtools-core@^2.3.0`, please ensure the version is correct in your React Native project (Note that it's dependency of `react-native`).

Also, sometimes it have timer problem between host machine and device (emulator), you need make sure `date & time` setting is correct:

<img width="300" alt="2017-07-18 10 09 01" src="https://user-images.githubusercontent.com/3001525/28492059-3c6957ea-6f2e-11e7-8901-8f4431f67a71.png">

Or try to restart your device (emulator).

## [Windows 10] React native debugger process starts but no visible window ([#459](https://github.com/jhen0409/react-native-debugger/issues/459))

This issue is caused by Windows 10 dark mode, for a workaround please disable dark mode and enable it again after launching react-native-debugger

## Other documentations

- [Getting Started](getting-started.md)
- [Debugger Integration](debugger-integration.md)
- [React DevTools Integration](react-devtools-integration.md)
- [Redux DevTools Integration](redux-devtools-integration.md)
- [Apollo Client DevTools Integration](apollo-client-devtools-integration.md)
- [Shortcut references](shortcut-references.md)
- [Network inspect of Chrome Developer Tools](network-inspect-of-chrome-devtools.md)
- [Enable open in editor in console](enable-open-in-editor-in-console.md)
- [Config file in home directory](config-file-in-home-directory.md)
- [Contributing](contributing.md)


================================================
FILE: electron/app.html
================================================
<!doctype html>
<html>
  <head>
    <meta charset=utf-8>
    <title>React Native Debugger</title>
    <link href='../dist/css/style.css' rel="stylesheet" />
  </head>
  <body>
    <div id="root">
      <div id="loading">Loading...</div>
    </div>
    <script src="http://localhost:3000/js/bundle.js"></script>
  </body>
</html>


================================================
FILE: electron/config/__tests__/__snapshots__/index.test.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`openConfigFile 1`] = `
{
  "config": {
    "autoUpdate": true,
    "defaultNetworkInspect": false,
    "defaultRNPackagerPorts": [
      8081,
    ],
    "defaultReactDevToolsPort": 19567,
    "defaultReactDevToolsTheme": "RNDebugger",
    "editor": "",
    "timesJSLoadToRefreshDevTools": -1,
    "windowBounds": {
      "frame": true,
    },
  },
}
`;

exports[`readConfig 1`] = `
{
  "config": {
    "autoUpdate": true,
    "defaultNetworkInspect": false,
    "defaultRNPackagerPorts": [
      8081,
    ],
    "defaultReactDevToolsPort": 19567,
    "defaultReactDevToolsTheme": "RNDebugger",
    "editor": "",
    "timesJSLoadToRefreshDevTools": -1,
    "windowBounds": {
      "frame": true,
    },
  },
}
`;

exports[`readConfig 2`] = `
{
  "config": {
    "autoUpdate": false,
  },
}
`;

exports[`readConfig 3`] = `
{
  "config": {
    "autoUpdate": true,
    "defaultNetworkInspect": false,
    "defaultRNPackagerPorts": [
      8081,
    ],
    "defaultReactDevToolsPort": 19567,
    "defaultReactDevToolsTheme": "RNDebugger",
    "editor": "",
    "timesJSLoadToRefreshDevTools": -1,
    "windowBounds": {
      "frame": true,
    },
  },
  "error": [SyntaxError: Unexpected 'i' at line 1 column 16 of the JSON5 data. Still to read: "is_broken, }"],
  "isConfigBroken": true,
}
`;


================================================
FILE: electron/config/__tests__/index.test.js
================================================
import fs from 'fs'
import path from 'path'

jest.mock('electron', () => ({
  shell: {
    openPath: jest.fn(),
  },
}))

const testFile = path.join(__dirname, 'config_test')

beforeAll(() => fs.existsSync(testFile) && fs.unlinkSync(testFile))

/* eslint-disable global-require */
test('readConfig', () => {
  const { readConfig } = require('..')

  expect(readConfig(testFile)).toMatchSnapshot()

  // User custom config
  fs.writeFileSync(testFile, '{ autoUpdate: false, }')
  expect(readConfig(testFile)).toMatchSnapshot()

  // Broken config
  fs.writeFileSync(testFile, '{ autoUpdate: is_broken, }')
  expect(readConfig(testFile)).toMatchSnapshot()
})

test('openConfigFile', () => {
  const { readConfig, openConfigFile } = require('..')
  const { shell } = require('electron')

  openConfigFile(testFile)
  expect(shell.openPath).toBeCalledWith(testFile)
  shell.openPath.mockClear()

  fs.unlinkSync(testFile)
  openConfigFile(testFile)
  expect(readConfig(testFile)).toMatchSnapshot()
})


================================================
FILE: electron/config/index.js
================================================
import fs from 'fs'
import path from 'path'
import json5 from 'json5'
import { shell } from 'electron'
import template from './template'

export const filePath = path.join(
  process.env[process.platform === 'win32' ? 'USERPROFILE' : 'HOME'],
  '.rndebuggerrc',
)

export const readConfig = (configFile = filePath) => {
  if (!fs.existsSync(configFile)) {
    // Create a new one
    fs.writeFileSync(configFile, template)
    return { config: json5.parse(template) }
  }
  try {
    // eslint-disable-next-line
    return { config: json5.parse(fs.readFileSync(configFile, 'utf-8')) };
  } catch (error) {
    // Alert parse config not successful
    return { config: json5.parse(template), isConfigBroken: true, error }
  }
}

export const openConfigFile = (configFile = filePath) => {
  readConfig()
  shell.openPath(configFile)
}


================================================
FILE: electron/config/template.js
================================================
// json5
module.exports = `{
  // Font family of the debugger window
  // fontFamily: 'monaco, Consolas, Lucida Console, monospace',

  // Zoom level of the debugger window, it will override persited zoomLevel
  // zoomLevel: 0,

  // Settings of debugger window, 
  windowBounds: {
    // Size of the debugger window, it will override persisted size
    // width: 1024,
    // height: 750,

    // Show frame for debugger window
    // but due to https://github.com/electron/electron/issues/3647
    // so we can't have custom title bar if no frame
    // titleBarStyle: 'hidden',
    frame: true,
  },

  // Auto check update on RNDebugger startup
  autoUpdate: true,

  // RNDebugger will open debugger window with the ports when app launched
  defaultRNPackagerPorts: [8081],

  // Env for
  // open React DevTools source file link
  // and enable open in editor for console log for RNDebugger
  editor: '',

  // Set default react-devtools theme (default is match Chrome DevTools theme)
  // but the default theme doesn't change manually changed theme
  // see https://github.com/facebook/react-devtools/blob/master/frontend/Themes/Themes.js to get more
  defaultReactDevToolsTheme: 'RNDebugger',

  // Set default react-devtools port (default is \`19567+\` if it is not being used).
  // The devtools backend of React Native will use the port to connect to the devtools server.
  // You should use that if you have some rules for binding port.
  //   (like https://github.com/jhen0409/react-native-debugger/issues/397)
  defaultReactDevToolsPort: 19567,

  // Enable Network Inspect by default
  // See https://github.com/jhen0409/react-native-debugger/blob/master/docs/network-inspect-of-chrome-devtools.md
  defaultNetworkInspect: false,

  // Refresh devtools when doing JS reload every N times. (-1 for disabled)
  // This can effectively avoid possible memory leaks (Like
  // https://github.com/jhen0409/react-native-debugger/issues/405) in devtools.
  timesJSLoadToRefreshDevTools: -1,
}
`


================================================
FILE: electron/context-menu.js
================================================
import { ipcMain } from 'electron'
import contextMenu from 'electron-context-menu'
import { readConfig } from './config'
import {
  toggleDevTools, n, item, separator,
} from './menu/common'

const invokeDevMethod = (win, name) => win.webContents.executeJavaScript(
  `window.invokeDevMethod && window.invokeDevMethod('${name}')`,
)

export const registerContextMenu = (win) => {
  const { config } = readConfig()
  const defaultContextMenuItems = [
    item('Toggle Developer Tools', n, () => toggleDevTools(win, 'chrome')),
    item('Toggle React DevTools', n, () => toggleDevTools(win, 'react')),
    item('Toggle Redux DevTools', n, () => toggleDevTools(win, 'redux')),
  ]
  let networkInspectEnabled = !!config.networkInspect
  let availableMethods = []
  contextMenu({
    window: win,
    showInspectElement: process.env.NODE_ENV === 'development',
    prepend: () => [
      availableMethods.includes('reload')
          && item('Reload JS', n, () => invokeDevMethod(win, 'reload')),
      availableMethods.includes('toggleElementInspector')
          && item('Toggle Element Inspector', n, () => invokeDevMethod(win, 'toggleElementInspector')),
      availableMethods.includes('show')
          && item('Show Developer Menu', n, () => invokeDevMethod(win, 'show')),
      item(
        networkInspectEnabled
          ? 'Disable Network Inspect'
          : 'Enable Network Inspect',
        n,
        () => invokeDevMethod(win, 'networkInspect'),
      ),
      availableMethods.includes('showAsyncStorage')
          && item('Log AsyncStorage content', n, () => invokeDevMethod(win, 'showAsyncStorage')),
      availableMethods.includes('clearAsyncStorage')
          && item('Clear AsyncStorage', n, () => invokeDevMethod(win, 'clearAsyncStorage')),
      separator,
    ]
      .filter((menuItem) => !!menuItem)
      .concat(defaultContextMenuItems),
  })

  const listener = (event, data) => {
    availableMethods = data.availableMethods || availableMethods
    networkInspectEnabled = typeof data.networkInspectEnabled === 'boolean'
      ? data.networkInspectEnabled
      : networkInspectEnabled
  }

  ipcMain.on(`context-menu-available-methods-update-${win.id}`, listener)
  return () => {
    ipcMain.off(`context-menu-available-methods-update-${win.id}`, listener)
  }
}


================================================
FILE: electron/debug.js
================================================
require('electron-debug')(); // eslint-disable-line


================================================
FILE: electron/devtools.js
================================================
export const getCatchConsoleLogScript = (port) => `
  window.__RN_PACKAGER_MATCHER__ = /^http:\\/\\/[^:]+:${port}/;
  if (!window.__INJECT_OPEN_IN_EDITOR_SCRIPT__) {
    const rndHelperQuery = 'iframe[data-devtools-extension="RNDebugger devtools helper"]';
    document.addEventListener('click', event => {
      if (!window.__IS_OPEN_IN_EDITOR_ENABLED__) {
        return;
      }
      const { target } = event;
      if (target.className === 'devtools-link') {
        const source = target.title;
        if (source && source.match(window.__RN_PACKAGER_MATCHER__)) {
          const rndHelper = document.querySelector(rndHelperQuery);
          if (rndHelper && rndHelper.contentWindow) {
            rndHelper.contentWindow.postMessage(
              {
                type: 'open-in-editor',
                source: source.replace(window.__RN_PACKAGER_MATCHER__, '')
              },
              '*'
            );
            return event.stopPropagation();
          }
        }
      }
    }, true);
    window.__INJECT_OPEN_IN_EDITOR_SCRIPT__ = true;
  }
`

export const catchConsoleLogLink = (win, host = 'localhost', port = 8081) => {
  if (win.devToolsWebContents) {
    return win.devToolsWebContents.executeJavaScript(`(() => {
      ${getCatchConsoleLogScript(host, port)}
    })()`)
  }
}

export const removeUnecessaryTabs = (win) => {
  if (
    process.env.NODE_ENV === 'production'
    && !process.env.DEBUG_RNDEBUGGER
    && win.devToolsWebContents
  ) {
    return win.devToolsWebContents.executeJavaScript(`(() => {
      const tabbedPane = UI.inspectorView.tabbedPane;
      if (tabbedPane) {
        tabbedPane.closeTab('elements');
        tabbedPane.closeTab('security');
        tabbedPane.closeTab('audits');
        tabbedPane.closeTab('audits2');
        tabbedPane.closeTab('lighthouse');

        tabbedPane.leftToolbar().element.remove();
      }
    })()`)
  }
}

export const activeTabs = (win) => {
  if (win.devToolsWebContents) {
    // Active network tab so we can do clearNetworkLogs
    return win.devToolsWebContents.executeJavaScript(`(() => {
      DevToolsAPI.showPanel('network');
      DevToolsAPI.showPanel('console');
    })()`)
  }
}


================================================
FILE: electron/extensions.js
================================================
import path from 'path'
import { session } from 'electron'

export default async () => {
  if (process.env.NODE_ENV === 'development') {
    await session.defaultSession.loadExtension(
      path.resolve('dist/devtools-helper/'),
      { allowFileAccess: true },
    )
    await session.defaultSession.loadExtension(
      path.join(
        __dirname,
        '../node_modules/apollo-client-devtools/build',
      ),
      { allowFileAccess: true },
    )
  } else if (process.env.PACKAGE === 'no') {
    await session.defaultSession.loadExtension(
      path.join(__dirname, 'devtools-helper/'),
      { allowFileAccess: true },
    )
    await session.defaultSession.loadExtension(
      path.join(
        __dirname,
        'node_modules/apollo-client-devtools/build',
      ),
      { allowFileAccess: true },
    )
  } else {
    await session.defaultSession.loadExtension(
      path.join(__dirname, '../devtools-helper/'),
      { allowFileAccess: true },
    )
    await session.defaultSession.loadExtension(
      path.join(
        __dirname,
        '../ac-devtools-ext-build/', // See package script for why
      ),
      { allowFileAccess: true },
    )
  }
}


================================================
FILE: electron/main.js
================================================
import path from 'path'
import {
  app, ipcMain, session, BrowserWindow, Menu,
} from 'electron'
import { initialize } from '@electron/remote/main'
import normalizeHeaderCase from 'header-case-normalizer'
import installExtensions from './extensions'
import { checkWindowInfo, createWindow } from './window'
import { startListeningHandleURL, handleURL, parseUrl } from './url-handle'
import { createMenuTemplate } from './menu'
import { readConfig } from './config'
import { sendSyncState } from './sync-state'

initialize()

// Uncomment if want to debug devtools backend
// app.commandLine.appendSwitch('remote-debugging-port', '9222');

app.commandLine.appendSwitch('disable-http-cache')

process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 1

const iconPath = path.resolve(__dirname, 'logo.png')
const defaultOptions = { iconPath }

const findWindow = async (_, port) => {
  const browserWindows = BrowserWindow.getAllWindows()
  const browserWindow = await browserWindows.reduce(async (promise, win) => {
    const acc = await promise
    if (acc) return acc

    const { isWorkerRunning, isPortSettingRequired, location } = await checkWindowInfo(win)
    return (!isWorkerRunning || location.port === port)
      && !isPortSettingRequired
      ? win
      : null
  }, Promise.resolve(null))
  if (!browserWindow) createWindow(defaultOptions)
  if (browserWindow) {
    if (browserWindow.isMinimized()) browserWindow.restore()
    browserWindow.focus()
  }
  return browserWindow
}

const handleCommandLine = async (commandLine) => {
  const url = commandLine.find((arg) => arg.startsWith('rndebugger://'))
  if (!url) {
    return
  }
  await handleURL(findWindow, url)
}

if (process.platform === 'linux') {
  const singleInstanceLock = app.requestSingleInstanceLock()
  if (!singleInstanceLock) {
    process.exit()
  } else {
    app.on('second-instance', async (event, commandLine) => {
      await handleCommandLine(commandLine)
    })
  }
}

startListeningHandleURL(findWindow)

ipcMain.on('check-port-available', async (event, arg) => {
  const port = Number(arg)
  const windows = BrowserWindow.getAllWindows()
  const isPortAvailable = await windows.reduce(async (promise, win) => {
    const isAvailable = await promise
    if (!isAvailable) return false

    if (win.webContents !== event.sender) {
      const { isPortSettingRequired, location } = await checkWindowInfo(win)
      if (location.port === port && !isPortSettingRequired) {
        return false
      }
    }
    return true
  }, Promise.resolve(true))
  event.sender.send('check-port-available-reply', isPortAvailable)
})

ipcMain.on('sync-state', sendSyncState)

app.on('activate', () => {
  if (BrowserWindow.getAllWindows().length !== 0) return
  createWindow(defaultOptions)
})

app.on('new-window-for-tab', () => {
  createWindow({ ...defaultOptions, isPortSettingRequired: true })
})

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

if (process.platform === 'darwin') {
  app.on('before-quit', async (event) => {
    event.preventDefault()
    BrowserWindow.getAllWindows().forEach((win) => {
      win.removeAllListeners('close')
      win.close()
    })
    process.exit()
  })
}

app.on('ready', async () => {
  await installExtensions()

  const { config } = readConfig()

  let { defaultRNPackagerPorts } = config
  if (!Array.isArray(defaultRNPackagerPorts)) {
    defaultRNPackagerPorts = [8081]
  }

  if (process.platform === 'linux') {
    const url = process.argv.find((arg) => arg.startsWith('rndebugger://'))
    const query = url ? parseUrl(url) : undefined
    if (query && query.port) {
      defaultRNPackagerPorts = [query.port]
    }
  }

  defaultRNPackagerPorts.forEach((port) => {
    createWindow({ port, ...defaultOptions })
  })

  const menuTemplate = createMenuTemplate(defaultOptions)
  const menu = Menu.buildFromTemplate(menuTemplate)
  Menu
Download .txt
gitextract_p_y_i4jj/

├── .eslintignore
├── .eslintrc
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE.md
│   ├── settings.yml
│   └── workflows/
│       ├── main.yml
│       └── release.yml
├── .gitignore
├── .prettierrc
├── LICENSE.md
├── README.md
├── __e2e__/
│   ├── app.spec.js
│   ├── buildTestBundle.js
│   ├── fixture/
│   │   ├── apollo.js
│   │   ├── app.js
│   │   ├── mobx.js
│   │   ├── redux.js
│   │   ├── remotedev.js
│   │   ├── setup.js
│   │   └── xhr-test.js
│   └── mockRNServer.js
├── app/
│   ├── actions/
│   │   ├── debugger.js
│   │   └── setting.js
│   ├── components/
│   │   ├── Draggable.js
│   │   └── FormInput.js
│   ├── containers/
│   │   ├── App.js
│   │   ├── ReactInspector.js
│   │   └── redux/
│   │       ├── DevTools.js
│   │       ├── Header.js
│   │       └── Settings.js
│   ├── globalStyles.js
│   ├── index.js
│   ├── middlewares/
│   │   ├── debuggerAPI.js
│   │   └── reduxAPI.js
│   ├── reducers/
│   │   ├── debugger.js
│   │   ├── index.js
│   │   └── setting.js
│   ├── setup.js
│   ├── store/
│   │   └── configureStore.js
│   ├── utils/
│   │   ├── adb.js
│   │   ├── config.js
│   │   ├── devMenu.js
│   │   └── devtools.js
│   └── worker/
│       ├── .eslintrc
│       ├── apollo.js
│       ├── asyncStorage.js
│       ├── devMenu.js
│       ├── index.js
│       ├── networkInspect.js
│       ├── polyfills/
│       │   └── fetch.js
│       ├── reactDevTools.js
│       ├── reduxAPI.js
│       ├── remotedev.js
│       ├── setup.js
│       └── utils.js
├── auto_update.json
├── auto_updater.json
├── babel.config.js
├── dist/
│   ├── app.html
│   ├── css/
│   │   └── style.css
│   ├── devtools-helper/
│   │   ├── main.html
│   │   ├── main.js
│   │   └── manifest.json
│   ├── package.json
│   └── patches/
│       └── apollo-client-devtools+4.1.4.patch
├── docs/
│   ├── README.md
│   ├── apollo-client-devtools-integration.md
│   ├── config-file-in-home-directory.md
│   ├── contributing.md
│   ├── debugger-integration.md
│   ├── enable-open-in-editor-in-console.md
│   ├── getting-started.md
│   ├── network-inspect-of-chrome-devtools.md
│   ├── react-devtools-integration.md
│   ├── redux-devtools-integration.md
│   ├── shortcut-references.md
│   └── troubleshooting.md
├── electron/
│   ├── app.html
│   ├── config/
│   │   ├── __tests__/
│   │   │   ├── __snapshots__/
│   │   │   │   └── index.test.js.snap
│   │   │   └── index.test.js
│   │   ├── index.js
│   │   └── template.js
│   ├── context-menu.js
│   ├── debug.js
│   ├── devtools.js
│   ├── extensions.js
│   ├── logo.icns
│   ├── main.js
│   ├── menu/
│   │   ├── common.js
│   │   ├── darwin.js
│   │   ├── dialog.js
│   │   ├── index.js
│   │   └── linux+win.js
│   ├── sync-state.js
│   ├── update.js
│   ├── url-handle/
│   │   ├── handleURL.js
│   │   ├── index.js
│   │   └── port.js
│   └── window.js
├── examples/
│   ├── .eslintrc
│   └── test-old-bridge/
│       ├── .gitignore
│       ├── App.js
│       ├── README.md
│       ├── app.json
│       ├── babel.config.js
│       ├── examples/
│       │   ├── apollo/
│       │   │   ├── App.js
│       │   │   └── SimpleQuery.js
│       │   └── redux/
│       │       ├── App.js
│       │       ├── app/
│       │       │   └── store.js
│       │       └── features/
│       │           └── counter/
│       │               ├── Counter.js
│       │               ├── counterAPI.js
│       │               └── counterSlice.js
│       └── package.json
├── npm-package/
│   ├── .eslintrc
│   ├── .gitignore
│   ├── README.md
│   ├── babel.config.js
│   ├── bin/
│   │   └── rndebugger-open.js
│   ├── package.json
│   └── src/
│       ├── __tests__/
│       │   ├── __snapshots__/
│       │   │   └── injectDevToolsMiddleware.test.js.snap
│       │   └── injectDevToolsMiddleware.test.js
│       ├── injectDevToolsMiddleware.js
│       ├── main.js
│       └── open.js
├── package.json
├── patches/
│   ├── @redux-devtools+inspector-monitor-trace-tab+1.0.0.patch
│   ├── @redux-devtools+ui+1.3.0.patch
│   ├── apollo-client-devtools+4.1.4.patch
│   ├── electron-gh-releases+2.0.4.patch
│   └── react-dev-utils+4.2.3.patch
├── scripts/
│   ├── config.json
│   ├── mac/
│   │   ├── createDMG.js
│   │   ├── createUniversalApp.js
│   │   └── entitlements.plist
│   ├── package-linux.sh
│   ├── package-macos.sh
│   ├── package-windows.sh
│   ├── patch-modules.js
│   └── postinstall.js
└── webpack/
    ├── .eslintrc
    ├── base.js
    ├── main.prod.js
    ├── renderer.dev.js
    └── renderer.prod.js
Download .txt
SYMBOL INDEX (96 symbols across 36 files)

FILE: __e2e__/buildTestBundle.js
  function buildTestBundle (line 11) | function buildTestBundle() {

FILE: __e2e__/fixture/apollo.js
  function run (line 15) | async function run() {

FILE: __e2e__/fixture/mobx.js
  function run (line 7) | function run() {

FILE: __e2e__/fixture/redux.js
  function run (line 5) | function run() {

FILE: __e2e__/fixture/remotedev.js
  function run (line 21) | function run() {

FILE: __e2e__/fixture/xhr-test.js
  function run (line 3) | async function run() {

FILE: __e2e__/mockRNServer.js
  function createMockRNServer (line 4) | function createMockRNServer(port = 8081) {

FILE: app/actions/debugger.js
  constant SET_DEBUGGER_LOCATION (line 1) | const SET_DEBUGGER_LOCATION = 'SET_DEBUGGER_LOCATION'
  constant SET_DEBUGGER_STATUS (line 2) | const SET_DEBUGGER_STATUS = 'SET_DEBUGGER_STATUS'
  constant SET_DEBUGGER_WORKER (line 3) | const SET_DEBUGGER_WORKER = 'SET_DEBUGGER_WORKER'
  constant SYNC_STATE (line 4) | const SYNC_STATE = 'SYNC_STATE'
  constant BEFORE_WINDOW_CLOSE (line 5) | const BEFORE_WINDOW_CLOSE = 'BEFORE_WINDOW_CLOSE'

FILE: app/actions/setting.js
  constant TOGGLE_DEVTOOLS (line 1) | const TOGGLE_DEVTOOLS = 'TOGGLE_DEVTOOLS'
  constant RESIZE_DEVTOOLS (line 2) | const RESIZE_DEVTOOLS = 'RESIZE_DEVTOOLS'
  constant CHANGE_DEFAULT_THEME (line 3) | const CHANGE_DEFAULT_THEME = 'CHANGE_DEFAULT_THEME'

FILE: app/components/Draggable.js
  class Draggable (line 15) | class Draggable extends PureComponent {
    method render (line 38) | render() {

FILE: app/components/FormInput.js
  class FormInput (line 30) | class FormInput extends PureComponent {
    method constructor (line 31) | constructor(props) {
    method render (line 51) | render() {

FILE: app/containers/App.js
  class App (line 66) | class App extends Component {
    method componentDidMount (line 67) | componentDidMount() {
    method componentWillUnmount (line 84) | componentWillUnmount() {
    method setDebuggerLocation (line 94) | setDebuggerLocation({ projectRoots, ...location }) {
    method getDevToolsSize (line 122) | getDevToolsSize() {
    method renderPortSetting (line 150) | renderPortSetting() {
    method renderReduxDevTools (line 167) | renderReduxDevTools(size) {
    method renderReactInspector (line 176) | renderReactInspector(size) {
    method render (line 184) | render() {

FILE: app/containers/ReactInspector.js
  class ReactInspector (line 41) | class ReactInspector extends Component {
    method setProjectRoots (line 42) | static setProjectRoots(projectRoots) {
    method componentDidMount (line 48) | componentDidMount() {
    method UNSAFE_componentWillReceiveProps (line 57) | UNSAFE_componentWillReceiveProps(nextProps) {
    method shouldComponentUpdate (line 80) | shouldComponentUpdate() {
    method componentWillUnmount (line 84) | componentWillUnmount() {
    method startServer (line 111) | startServer(port = this.listeningPort) {
    method render (line 133) | render() {

FILE: app/containers/redux/DevTools.js
  function App (line 12) | function App() {

FILE: app/containers/redux/Header.js
  function Header (line 22) | function Header(props) {

FILE: app/containers/redux/Settings.js
  class Settings (line 6) | class Settings extends Component {
    method constructor (line 11) | constructor(props) {
    method render (line 20) | render() {

FILE: app/middlewares/debuggerAPI.js
  constant APOLLO_MESSAGE_PREFIX (line 32) | const APOLLO_MESSAGE_PREFIX = 'ac-devtools:'

FILE: app/reducers/debugger.js
  function getStatusMessage (line 8) | function getStatusMessage(status, port) {

FILE: app/utils/devMenu.js
  method toggle (line 45) | toggle() {
  method change (line 159) | change(nextIndex) {
  method click (line 168) | click() {
  method click (line 177) | click() {

FILE: app/worker/apollo.js
  function handleApolloClient (line 2) | function handleApolloClient() {

FILE: app/worker/asyncStorage.js
  function convertError (line 6) | function convertError(error) {
  function convertErrors (line 15) | function convertErrors(errs) {
  method getItem (line 32) | getItem(key) {
  method setItem (line 47) | async setItem(key, value) {
  method clear (line 60) | clear() {
  method getAllKeys (line 72) | getAllKeys() {

FILE: app/worker/index.js
  method executeApplicationScript (line 61) | executeApplicationScript(message, sendReply) {
  method emitReduxMessage (line 82) | emitReduxMessage() {
  method emitApolloMessage (line 86) | emitApolloMessage() {
  method invokeDevMenuMethod (line 90) | invokeDevMenuMethod({ name, args }) {
  method beforeTerminate (line 94) | beforeTerminate() {

FILE: app/worker/polyfills/fetch.js
  function getRNDebuggerFetchPolyfills (line 8) | function getRNDebuggerFetchPolyfills() {

FILE: app/worker/reduxAPI.js
  function configureStore (line 16) | function configureStore(next, subscriber, options) {
  function getStackTrace (line 30) | function getStackTrace(config, toExcludeFromTrace) {
  function getLiftedState (line 65) | function getLiftedState(store, filters) {
  function relay (line 69) | function relay(type, state, instance, action, nextActionId) {
  function dispatchRemotely (line 118) | function dispatchRemotely(action, instance) {
  function importPayloadFrom (line 128) | function importPayloadFrom(store, state, instance) {
  function exportState (line 139) | function exportState({ id: instanceId, store, serializeState }) {
  function handleMessages (line 160) | function handleMessages(message) {
  function start (line 198) | function start(instance) {
  function checkForReducerErrors (line 215) | function checkForReducerErrors(liftedState, instance) {
  function monitorReducer (line 223) | function monitorReducer(state = {}, action = {}) {
  function handleChange (line 228) | function handleChange(state, liftedState, maxAge, instance) {
  function devToolsEnhancer (line 254) | function devToolsEnhancer(options = {}) {
  function composeWithDevTools (line 365) | function composeWithDevTools(...funcs) {

FILE: app/worker/remotedev.js
  function extractState (line 9) | function extractState(message) {
  function handleMessages (line 15) | function handleMessages(message) {
  function start (line 30) | function start() {
  function transformAction (line 42) | function transformAction(action, config) {
  function send (line 61) | function send(action, state, type, options) {
  function connect (line 82) | function connect(options = {}) {
  function disconnect (line 122) | function disconnect() {}

FILE: app/worker/utils.js
  constant RN_DEBUGGER_URL_PART (line 98) | const RN_DEBUGGER_URL_PART = 'RNDebuggerWorker.js'
  constant BUNDLE_URL_REGEXP (line 99) | const BUNDLE_URL_REGEXP = /(http[\S]*?index\.bundle\?[\S]*?)(:\d+:?\d?)/
  function updateStackWithSourceMap (line 105) | function updateStackWithSourceMap(stack) {

FILE: electron/url-handle/port.js
  function read (line 12) | function read() {

FILE: examples/test-old-bridge/App.js
  function App (line 15) | function App() {

FILE: examples/test-old-bridge/examples/apollo/App.js
  function App (line 26) | function App() {

FILE: examples/test-old-bridge/examples/apollo/SimpleQuery.js
  constant GET_DATA (line 14) | const GET_DATA = gql`
  function SimpleQuery (line 24) | function SimpleQuery() {

FILE: examples/test-old-bridge/examples/redux/features/counter/Counter.js
  function Counter (line 34) | function Counter() {

FILE: examples/test-old-bridge/examples/redux/features/counter/counterAPI.js
  function fetchCount (line 2) | function fetchCount(amount = 1) {

FILE: npm-package/src/injectDevToolsMiddleware.js
  function getFlag (line 136) | function getFlag(moduleName, version) {

FILE: npm-package/src/open.js
  function connectToRND (line 9) | function connectToRND(rndPath, log, cb) {

FILE: scripts/mac/createUniversalApp.js
  function run (line 11) | async function run() {

FILE: scripts/postinstall.js
  function run (line 3) | async function run() {
Condensed preview — 144 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (396K chars).
[
  {
    "path": ".eslintignore",
    "chars": 68,
    "preview": "npm-package/lib/\n*.tmpl.js\n*.bundle.js\ndist/\nrelease/\nnode_modules/\n"
  },
  {
    "path": ".eslintrc",
    "chars": 1016,
    "preview": "{\n  \"parser\": \"@babel/eslint-parser\",\n  \"extends\": [\"airbnb\", \"prettier\"],\n  \"env\": {\n    \"browser\": true,\n    \"node\": t"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 56,
    "preview": "github: jhen0409\nopen_collective: react-native-debugger\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "chars": 1071,
    "preview": "<!--\nBefore submitting the issue:\n\n- You're using the latest version of react-native-debugger\n- You have read the docume"
  },
  {
    "path": ".github/settings.yml",
    "chars": 1308,
    "preview": "repository:\n  name: react-native-debugger\n  has_issues: true\n  has_wiki: true\n  has_downloads: true\n  default_branch: ma"
  },
  {
    "path": ".github/workflows/main.yml",
    "chars": 2182,
    "preview": "name: CI\n\non: [push, pull_request]\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number ||"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 1243,
    "preview": "name: Release\n\non:\n  release:\n    types: [published]\n\njobs:\n  release-linux:\n    runs-on: ubuntu-latest\n    steps:\n     "
  },
  {
    "path": ".gitignore",
    "chars": 130,
    "preview": "node_modules\nnpm-debug.log\nyarn-error.log\n.DS_Store\ndist/js\ndist/main.js*\nrelease/\n*.bundle.js\ntmp/\nconfig_test\n.idea/\na"
  },
  {
    "path": ".prettierrc",
    "chars": 106,
    "preview": "{\n  \"trailingComma\": \"all\",\n  \"tabWidth\": 2,\n  \"semi\": false,\n  \"singleQuote\": true,\n  \"printWidth\": 80\n}\n"
  },
  {
    "path": "LICENSE.md",
    "chars": 1081,
    "preview": "\nThe MIT License (MIT)\n\nCopyright (c) 2016 Jhen-Jie Hong\n\nPermission is hereby granted, free of charge, to any person ob"
  },
  {
    "path": "README.md",
    "chars": 5574,
    "preview": "# React Native Debugger\n\n[![Backers on Open Collective](https://opencollective.com/react-native-debugger/backers/badge.s"
  },
  {
    "path": "__e2e__/app.spec.js",
    "chars": 10982,
    "preview": "import fs from 'fs'\nimport path from 'path'\nimport net from 'net'\nimport http from 'http'\nimport executablePath from 'el"
  },
  {
    "path": "__e2e__/buildTestBundle.js",
    "chars": 672,
    "preview": "import path from 'path'\nimport webpack from 'webpack'\n\nconst outputPath = '__e2e__/fixture'\nconst filename = 'app.bundle"
  },
  {
    "path": "__e2e__/fixture/apollo.js",
    "chars": 577,
    "preview": "/* eslint-disable import/no-extraneous-dependencies */\n/*\n * Create an Apollo Client to test the bridge messages sent\n *"
  },
  {
    "path": "__e2e__/fixture/app.js",
    "chars": 397,
    "preview": "import './setup'\n\nimport runXHRTest from './xhr-test' // Install fetch polyfill before initial apollo-client\nimport runA"
  },
  {
    "path": "__e2e__/fixture/mobx.js",
    "chars": 586,
    "preview": "/* eslint prefer-arrow-callback: 0 */\nimport { observable, action, useStrict } from 'mobx'\nimport remotedev from 'mobx-r"
  },
  {
    "path": "__e2e__/fixture/redux.js",
    "chars": 1180,
    "preview": "/* eslint no-underscore-dangle: 0 */\n\nimport { createStore } from 'redux'\n\nexport default function run() {\n  // Enhancer"
  },
  {
    "path": "__e2e__/fixture/remotedev.js",
    "chars": 689,
    "preview": "import { createStore } from 'redux'\n\nconst connectViaExtension = window.devToolsExtension.connect\n\nconst logReducer = (r"
  },
  {
    "path": "__e2e__/fixture/setup.js",
    "chars": 975,
    "preview": "/* eslint-disable no-restricted-globals */\n/* eslint no-underscore-dangle: 0 */\n\nself.window = global\n\n// Remove native "
  },
  {
    "path": "__e2e__/fixture/xhr-test.js",
    "chars": 416,
    "preview": "import 'whatwg-fetch'\n\nexport default async function run() {\n  // Fetch with forbidden header names\n  await fetch('http:"
  },
  {
    "path": "__e2e__/mockRNServer.js",
    "chars": 419,
    "preview": "import http from 'http'\nimport WebSocket from 'ws'\n\nexport default function createMockRNServer(port = 8081) {\n  const se"
  },
  {
    "path": "app/actions/debugger.js",
    "chars": 711,
    "preview": "export const SET_DEBUGGER_LOCATION = 'SET_DEBUGGER_LOCATION'\nexport const SET_DEBUGGER_STATUS = 'SET_DEBUGGER_STATUS'\nex"
  },
  {
    "path": "app/actions/setting.js",
    "chars": 416,
    "preview": "export const TOGGLE_DEVTOOLS = 'TOGGLE_DEVTOOLS'\nexport const RESIZE_DEVTOOLS = 'RESIZE_DEVTOOLS'\nexport const CHANGE_DE"
  },
  {
    "path": "app/components/Draggable.js",
    "chars": 1253,
    "preview": "import React, { PureComponent } from 'react'\nimport PropTypes from 'prop-types'\n\nconst styles = {\n  draggable: {\n    pos"
  },
  {
    "path": "app/components/FormInput.js",
    "chars": 2127,
    "preview": "import React, { PureComponent } from 'react'\nimport PropTypes from 'prop-types'\n\nconst styles = {\n  title: { textAlign: "
  },
  {
    "path": "app/containers/App.js",
    "chars": 6525,
    "preview": "import { ipcRenderer } from 'electron'\nimport { getCurrentWindow } from '@electron/remote'\nimport React, { Component } f"
  },
  {
    "path": "app/containers/ReactInspector.js",
    "chars": 4234,
    "preview": "import { connect } from 'react-redux'\nimport React, { Component } from 'react'\nimport PropTypes from 'prop-types'\nimport"
  },
  {
    "path": "app/containers/redux/DevTools.js",
    "chars": 1171,
    "preview": "import React from 'react'\nimport { useSelector, useDispatch } from 'react-redux'\nimport styled from 'styled-components'\n"
  },
  {
    "path": "app/containers/redux/Header.js",
    "chars": 1418,
    "preview": "import React, { useCallback } from 'react'\nimport PropTypes from 'prop-types'\nimport { useDispatch } from 'react-redux'\n"
  },
  {
    "path": "app/containers/redux/Settings.js",
    "chars": 670,
    "preview": "/* eslint-disable import/no-named-as-default */\nimport React, { Component } from 'react'\nimport Tabs from '@redux-devtoo"
  },
  {
    "path": "app/globalStyles.js",
    "chars": 454,
    "preview": "import { css, createGlobalStyle } from 'styled-components'\n\nconst commonStyles = css``\n\nexport const GlobalStyle =\n  pro"
  },
  {
    "path": "app/index.js",
    "chars": 3279,
    "preview": "import { findAPortNotInUse } from 'portscanner'\nimport { webFrame } from 'electron'\nimport { getCurrentWindow } from '@e"
  },
  {
    "path": "app/middlewares/debuggerAPI.js",
    "chars": 6835,
    "preview": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the B"
  },
  {
    "path": "app/middlewares/reduxAPI.js",
    "chars": 3978,
    "preview": "import { bindActionCreators } from 'redux'\nimport { ipcRenderer } from 'electron'\nimport { getGlobal } from '@electron/r"
  },
  {
    "path": "app/reducers/debugger.js",
    "chars": 2020,
    "preview": "import {\n  SET_DEBUGGER_STATUS,\n  SET_DEBUGGER_WORKER,\n  SET_DEBUGGER_LOCATION,\n} from '../actions/debugger'\nimport conf"
  },
  {
    "path": "app/reducers/index.js",
    "chars": 853,
    "preview": "import { combineReducers } from 'redux'\nimport { section } from '@redux-devtools/app/lib/esm/reducers/section'\n// import"
  },
  {
    "path": "app/reducers/setting.js",
    "chars": 845,
    "preview": "import { TOGGLE_DEVTOOLS, RESIZE_DEVTOOLS, CHANGE_DEFAULT_THEME } from '../actions/setting'\n\nconst initialState = {\n  re"
  },
  {
    "path": "app/setup.js",
    "chars": 322,
    "preview": "import config from './utils/config'\n\nif (config.editor) {\n  process.env.EDITOR = config.editor\n}\n\nif (config.fontFamily)"
  },
  {
    "path": "app/store/configureStore.js",
    "chars": 1345,
    "preview": "import { createStore, applyMiddleware, compose } from 'redux'\nimport { persistReducer, persistStore } from 'redux-persis"
  },
  {
    "path": "app/utils/adb.js",
    "chars": 388,
    "preview": "import adb from 'adbkit'\n\nexport const client = adb.createClient({ host: '127.0.0.1' })\n\nconst reverse = (device, port) "
  },
  {
    "path": "app/utils/config.js",
    "chars": 108,
    "preview": "import { getCurrentWindow } from '@electron/remote'\n\nexport default getCurrentWindow().debuggerConfig || {}\n"
  },
  {
    "path": "app/utils/devMenu.js",
    "chars": 5625,
    "preview": "import { TouchBar, nativeImage, getCurrentWindow } from '@electron/remote'\n\nimport { ipcRenderer } from 'electron'\nimpor"
  },
  {
    "path": "app/utils/devtools.js",
    "chars": 1308,
    "preview": "import { getCatchConsoleLogScript } from '../../electron/devtools'\n\nlet enabled = false\nexport const toggleOpenInEditor "
  },
  {
    "path": "app/worker/.eslintrc",
    "chars": 55,
    "preview": "{\n  \"rules\": {\n    \"no-restricted-globals\": \"off\"\n  }\n}"
  },
  {
    "path": "app/worker/apollo.js",
    "chars": 134,
    "preview": "\nexport function handleApolloClient() {\n  // eslint-disable-next-line global-require\n  require('apollo-client-devtools/b"
  },
  {
    "path": "app/worker/asyncStorage.js",
    "chars": 2904,
    "preview": "export const getClearAsyncStorageFn = (AsyncStorage) => {\n  if (!AsyncStorage.clear) return\n  return () => AsyncStorage."
  },
  {
    "path": "app/worker/devMenu.js",
    "chars": 1340,
    "preview": "/* eslint-disable no-underscore-dangle */\n\nimport { toggleNetworkInspect } from './networkInspect'\nimport { getClearAsyn"
  },
  {
    "path": "app/worker/index.js",
    "chars": 3885,
    "preview": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the B"
  },
  {
    "path": "app/worker/networkInspect.js",
    "chars": 3885,
    "preview": "import getRNDebuggerFetchPolyfills from './polyfills/fetch'\n\nconst isWorkerMethod = (fn) => String(fn).indexOf('[native "
  },
  {
    "path": "app/worker/polyfills/fetch.js",
    "chars": 14277,
    "preview": "/* eslint-disable no-underscore-dangle */\n/* eslint-disable no-param-reassign */\n/* eslint-disable no-prototype-builtins"
  },
  {
    "path": "app/worker/reactDevTools.js",
    "chars": 906,
    "preview": "/* eslint-disable no-underscore-dangle */\n\nconst methodGlobalName = '__REPORT_REACT_DEVTOOLS_PORT__'\n\nconst reportReactD"
  },
  {
    "path": "app/worker/reduxAPI.js",
    "chars": 9907,
    "preview": "import { instrument } from '@redux-devtools/instrument'\nimport {\n  evalAction,\n  getActionsArray,\n  generateId,\n  string"
  },
  {
    "path": "app/worker/remotedev.js",
    "chars": 3149,
    "preview": "// Edit from https://github.com/zalmoxisus/remotedev/blob/master/src/devTools.js\n\nimport { stringify, parse } from 'jsan"
  },
  {
    "path": "app/worker/setup.js",
    "chars": 1355,
    "preview": "import {\n  replaceForbiddenHeadersForWorkerXHR,\n  addURIWarningForWorkerFormData,\n} from './networkInspect'\n\n// Add the "
  },
  {
    "path": "app/worker/utils.js",
    "chars": 3533,
    "preview": "/* eslint-disable no-underscore-dangle */\n\n// Avoid warning of use metro require on dev mode\n// it actually unnecessary "
  },
  {
    "path": "auto_update.json",
    "chars": 361,
    "preview": "{\n  \"url\": \"https://github.com/jhen0409/react-native-debugger/releases/download/v0.14.0/rn-debugger-macos-universal.zip\""
  },
  {
    "path": "auto_updater.json",
    "chars": 194,
    "preview": "{\n  \"url\": \"https://github.com/jhen0409/react-native-debugger/releases/download/v0.10.13/rn-debugger-macos-x64.zip\",\n  \""
  },
  {
    "path": "babel.config.js",
    "chars": 416,
    "preview": "module.exports = (api) => {\n  api.cache(true)\n  return {\n    presets: [['@babel/preset-env', { targets: { node: '18.5' }"
  },
  {
    "path": "dist/app.html",
    "chars": 299,
    "preview": "<!doctype html>\n<html>\n  <head>\n    <meta charset=utf-8>\n    <title>React Native Debugger</title>\n    <link href='css/st"
  },
  {
    "path": "dist/css/style.css",
    "chars": 829,
    "preview": "html,\nbody {\n  font-family: monaco, Consolas, Lucida Console, monospace;\n  overflow: hidden;\n  font-size: 100%;\n  margin"
  },
  {
    "path": "dist/devtools-helper/main.html",
    "chars": 134,
    "preview": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <script src=\"./main.js\"></script>\n  </head>\n  <body>\n  </"
  },
  {
    "path": "dist/devtools-helper/main.js",
    "chars": 697,
    "preview": "const detectChromeDevToolsTheme = () => chrome.devtools.panels.themeName || 'default';\n\nconst themeName = detectChromeDe"
  },
  {
    "path": "dist/devtools-helper/manifest.json",
    "chars": 122,
    "preview": "{\n  \"manifest_version\": 2,\n  \"name\": \"RNDebugger devtools helper\",\n  \"version\": \"0.0.1\",\n  \"devtools_page\": \"main.html\"\n"
  },
  {
    "path": "dist/package.json",
    "chars": 672,
    "preview": "{\n  \"name\": \"react-native-debugger\",\n  \"version\": \"0.14.0\",\n  \"productName\": \"React Native Debugger\",\n  \"description\": \""
  },
  {
    "path": "dist/patches/apollo-client-devtools+4.1.4.patch",
    "chars": 14013,
    "preview": "diff --git a/node_modules/apollo-client-devtools/build/background.js b/node_modules/apollo-client-devtools/build/backgro"
  },
  {
    "path": "docs/README.md",
    "chars": 659,
    "preview": "# Documentation\n\n- [Getting Started](getting-started.md)\n- [Debugger Integration](debugger-integration.md)\n- [React DevT"
  },
  {
    "path": "docs/apollo-client-devtools-integration.md",
    "chars": 1233,
    "preview": "# Apollo Client DevTools Integration\n\nReact Native debugger has integration for the [Apollo Client DevTools](https://git"
  },
  {
    "path": "docs/config-file-in-home-directory.md",
    "chars": 2808,
    "preview": "# Config file in home directory\n\nWe could configure RNDebugger app in `~/.rndebuggerrc` (the config can be opened from t"
  },
  {
    "path": "docs/contributing.md",
    "chars": 3539,
    "preview": "# Contributing\n\n## Development\n\n### Fork this repo & install dependencies\n\nWe're recommended use yarn because we keep th"
  },
  {
    "path": "docs/debugger-integration.md",
    "chars": 2750,
    "preview": "# Debugger integration\n\nThe Debugger worker is referenced from [react-native](https://github.com/facebook/react-native/b"
  },
  {
    "path": "docs/enable-open-in-editor-in-console.md",
    "chars": 1127,
    "preview": "# Enable open in editor in console\n\nYou can toggle the application menu item:\n\n<img width=\"386\" alt=\"2017-08-16 10 44 41"
  },
  {
    "path": "docs/getting-started.md",
    "chars": 4256,
    "preview": "# Getting Started\n\nJust these steps will let you start RNDebugger out of box:\n\n- Install the latest version ([download p"
  },
  {
    "path": "docs/network-inspect-of-chrome-devtools.md",
    "chars": 3841,
    "preview": "# Network Inspect of Chrome Developer Tools\n\n**_WARNING_**: You should read [the limitations](#limitations) if you want "
  },
  {
    "path": "docs/react-devtools-integration.md",
    "chars": 2567,
    "preview": "# React DevTools Integration\n\n**_NOTE_** Supported React Native version is `>= 0.62`. Please downgrade RNDebugger versio"
  },
  {
    "path": "docs/redux-devtools-integration.md",
    "chars": 2075,
    "preview": "# Redux DevTools Integration\n\nWe used [@redux-devtools/app](https://github.com/reduxjs/redux-devtools/tree/main/packages"
  },
  {
    "path": "docs/shortcut-references.md",
    "chars": 2428,
    "preview": "# Shortcut references\n\nThis section will explain about the following items in RNDebugger.\n\n- [Content menu](#context-men"
  },
  {
    "path": "docs/troubleshooting.md",
    "chars": 6531,
    "preview": "# Troubleshooting\n\n## I got `Unsupported` meesage from React DevTools\n\nIf you're using React Native version >= 0.62 and "
  },
  {
    "path": "electron/app.html",
    "chars": 329,
    "preview": "<!doctype html>\n<html>\n  <head>\n    <meta charset=utf-8>\n    <title>React Native Debugger</title>\n    <link href='../dis"
  },
  {
    "path": "electron/config/__tests__/__snapshots__/index.test.js.snap",
    "chars": 1344,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`openConfigFile 1`] = `\n{\n  \"config\": {\n    \"autoUpdate\": true,\n    "
  },
  {
    "path": "electron/config/__tests__/index.test.js",
    "chars": 997,
    "preview": "import fs from 'fs'\nimport path from 'path'\n\njest.mock('electron', () => ({\n  shell: {\n    openPath: jest.fn(),\n  },\n}))"
  },
  {
    "path": "electron/config/index.js",
    "chars": 833,
    "preview": "import fs from 'fs'\nimport path from 'path'\nimport json5 from 'json5'\nimport { shell } from 'electron'\nimport template f"
  },
  {
    "path": "electron/config/template.js",
    "chars": 2003,
    "preview": "// json5\nmodule.exports = `{\n  // Font family of the debugger window\n  // fontFamily: 'monaco, Consolas, Lucida Console,"
  },
  {
    "path": "electron/context-menu.js",
    "chars": 2296,
    "preview": "import { ipcMain } from 'electron'\nimport contextMenu from 'electron-context-menu'\nimport { readConfig } from './config'"
  },
  {
    "path": "electron/debug.js",
    "chars": 52,
    "preview": "require('electron-debug')(); // eslint-disable-line\n"
  },
  {
    "path": "electron/devtools.js",
    "chars": 2188,
    "preview": "export const getCatchConsoleLogScript = (port) => `\n  window.__RN_PACKAGER_MATCHER__ = /^http:\\\\/\\\\/[^:]+:${port}/;\n  if"
  },
  {
    "path": "electron/extensions.js",
    "chars": 1176,
    "preview": "import path from 'path'\nimport { session } from 'electron'\n\nexport default async () => {\n  if (process.env.NODE_ENV === "
  },
  {
    "path": "electron/main.js",
    "chars": 4771,
    "preview": "import path from 'path'\nimport {\n  app, ipcMain, session, BrowserWindow, Menu,\n} from 'electron'\nimport { initialize } f"
  },
  {
    "path": "electron/menu/common.js",
    "chars": 1054,
    "preview": "export const toggleDevTools = (win, type) => {\n  if (!win || !type) return\n  if (type === 'chrome') {\n    win.toggleDevT"
  },
  {
    "path": "electron/menu/darwin.js",
    "chars": 3444,
    "preview": "import { app, shell, BrowserWindow } from 'electron'\nimport { createWindow } from '../window'\nimport checkUpdate from '."
  },
  {
    "path": "electron/menu/dialog.js",
    "chars": 681,
    "preview": "import { app, dialog, BrowserWindow } from 'electron'\nimport multiline from 'multiline-template'\n\nconst appName = app.na"
  },
  {
    "path": "electron/menu/index.js",
    "chars": 282,
    "preview": "/* eslint global-require: 0 */\n\nimport createMenuTemplateDarwin from './darwin'\nimport createMenuTemplateLinuxWin from '"
  },
  {
    "path": "electron/menu/linux+win.js",
    "chars": 2927,
    "preview": "import { shell, BrowserWindow } from 'electron'\nimport { createWindow } from '../window'\nimport checkUpdate from '../upd"
  },
  {
    "path": "electron/sync-state.js",
    "chars": 493,
    "preview": "import { BrowserWindow } from 'electron'\n\nlet syncState = false\n\nexport const isSyncState = () => syncState\n\n// Take by "
  },
  {
    "path": "electron/update.js",
    "chars": 2282,
    "preview": "import { app, dialog, shell } from 'electron'\nimport GhReleases from 'electron-gh-releases'\nimport fetch from 'electron-"
  },
  {
    "path": "electron/url-handle/handleURL.js",
    "chars": 2460,
    "preview": "import { app } from 'electron'\nimport net from 'net'\nimport url from 'url'\nimport qs from 'querystring'\nimport fs from '"
  },
  {
    "path": "electron/url-handle/index.js",
    "chars": 172,
    "preview": "import startListeningHandleURL, { handleURL, parseUrl } from './handleURL'\nimport * as port from './port'\n\nexport {\n  st"
  },
  {
    "path": "electron/url-handle/port.js",
    "chars": 689,
    "preview": "import fs from 'fs'\nimport path from 'path'\n\nconst homeEnv = process.platform === 'win32' ? 'USERPROFILE' : 'HOME'\nconst"
  },
  {
    "path": "electron/window.js",
    "chars": 5718,
    "preview": "import path from 'path'\nimport {\n  BrowserWindow, Menu, globalShortcut, dialog,\n} from 'electron'\nimport Store from 'ele"
  },
  {
    "path": "examples/.eslintrc",
    "chars": 95,
    "preview": "{\n  \"rules\": {\n    \"import/no-extraneous-dependencies\": 0,\n    \"import/no-unresolved\": 0\n  }\n}\n"
  },
  {
    "path": "examples/test-old-bridge/.gitignore",
    "chars": 216,
    "preview": "node_modules/\n.expo/\ndist/\nnpm-debug.*\n*.jks\n*.p8\n*.p12\n*.key\n*.mobileprovision\n*.orig.*\nweb-build/\n\n# macOS\n.DS_Store\n\n"
  },
  {
    "path": "examples/test-old-bridge/App.js",
    "chars": 524,
    "preview": "/* eslint-disable react/style-prop-object */\nimport { StatusBar } from 'expo-status-bar'\nimport React from 'react'\nimpor"
  },
  {
    "path": "examples/test-old-bridge/README.md",
    "chars": 311,
    "preview": "# test-old-bridge\n\nThis is example created by `npx create-expo-app -t blank@48`,  `\"jsEngine\": \"jsc\"` to `app.json`.\n\nTh"
  },
  {
    "path": "examples/test-old-bridge/app.json",
    "chars": 662,
    "preview": "{\n  \"expo\": {\n    \"jsEngine\": \"jsc\",\n    \"name\": \"test-old-bridge\",\n    \"slug\": \"test-old-bridge\",\n    \"version\": \"1.0.0"
  },
  {
    "path": "examples/test-old-bridge/babel.config.js",
    "chars": 99,
    "preview": "module.exports = (api) => {\n  api.cache(true)\n  return {\n    presets: ['babel-preset-expo'],\n  }\n}\n"
  },
  {
    "path": "examples/test-old-bridge/examples/apollo/App.js",
    "chars": 831,
    "preview": "import React from 'react'\nimport { StyleSheet, Text, View } from 'react-native'\nimport { ApolloClient, InMemoryCache, Ap"
  },
  {
    "path": "examples/test-old-bridge/examples/apollo/SimpleQuery.js",
    "chars": 923,
    "preview": "import React from 'react'\nimport { StyleSheet, Text, Button } from 'react-native'\nimport { useQuery } from '@apollo/clie"
  },
  {
    "path": "examples/test-old-bridge/examples/redux/App.js",
    "chars": 264,
    "preview": "import React from 'react'\nimport { Provider } from 'react-redux'\nimport { Counter } from './features/counter/Counter'\nim"
  },
  {
    "path": "examples/test-old-bridge/examples/redux/app/store.js",
    "chars": 201,
    "preview": "import { configureStore } from '@reduxjs/toolkit'\nimport counterReducer from '../features/counter/counterSlice'\n\nexport "
  },
  {
    "path": "examples/test-old-bridge/examples/redux/features/counter/Counter.js",
    "chars": 1549,
    "preview": "import React from 'react'\nimport {\n  StyleSheet, View, Text, TouchableHighlight,\n} from 'react-native'\nimport { useSelec"
  },
  {
    "path": "examples/test-old-bridge/examples/redux/features/counter/counterAPI.js",
    "chars": 198,
    "preview": "// A mock function to mimic making an async request for data\nexport function fetchCount(amount = 1) {\n  return new Promi"
  },
  {
    "path": "examples/test-old-bridge/examples/redux/features/counter/counterSlice.js",
    "chars": 2727,
    "preview": "import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'\nimport { fetchCount } from './counterAPI'\n\nconst initia"
  },
  {
    "path": "examples/test-old-bridge/package.json",
    "chars": 655,
    "preview": "{\n  \"name\": \"test-old-bridge\",\n  \"version\": \"1.0.0\",\n  \"main\": \"node_modules/expo/AppEntry.js\",\n  \"scripts\": {\n    \"star"
  },
  {
    "path": "npm-package/.eslintrc",
    "chars": 48,
    "preview": "{\n  \"rules\": {\n    \"global-require\": \"off\"\n  }\n}"
  },
  {
    "path": "npm-package/.gitignore",
    "chars": 5,
    "preview": "lib/\n"
  },
  {
    "path": "npm-package/README.md",
    "chars": 2434,
    "preview": "# react-native-debugger-open [![NPM version](http://img.shields.io/npm/v/react-native-debugger-open.svg?style=flat)](htt"
  },
  {
    "path": "npm-package/babel.config.js",
    "chars": 130,
    "preview": "module.exports = (api) => {\n  api.cache(true)\n  return {\n    presets: [['@babel/preset-env', { targets: { node: '12' } }"
  },
  {
    "path": "npm-package/bin/rndebugger-open.js",
    "chars": 700,
    "preview": "#! /usr/bin/env node\n\n'use strict'\n\nconst defaultPort = 8081\n\nconst argv = require('minimist')(process.argv.slice(2), {\n"
  },
  {
    "path": "npm-package/package.json",
    "chars": 1013,
    "preview": "{\n  \"name\": \"react-native-debugger-open\",\n  \"version\": \"0.4.3\",\n  \"description\": \"Replace `open debugger-ui with Chrome`"
  },
  {
    "path": "npm-package/src/__tests__/__snapshots__/injectDevToolsMiddleware.test.js.snap",
    "chars": 97146,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`Inject to devtoolsMiddleware of React Native packager inject / reve"
  },
  {
    "path": "npm-package/src/__tests__/injectDevToolsMiddleware.test.js",
    "chars": 5963,
    "preview": "import fs from 'fs-extra'\nimport path from 'path'\nimport fetch from 'node-fetch'\nimport { inject, revert } from '../inje"
  },
  {
    "path": "npm-package/src/injectDevToolsMiddleware.js",
    "chars": 7278,
    "preview": "import fs from 'fs'\nimport { join } from 'path'\nimport es6Template from 'es6-template'\nimport semver from 'semver'\n\ncons"
  },
  {
    "path": "npm-package/src/main.js",
    "chars": 2086,
    "preview": "import fs from 'fs'\nimport cp from 'child_process'\nimport path from 'path'\nimport chalk from 'chalk'\nimport { inject as "
  },
  {
    "path": "npm-package/src/open.js",
    "chars": 2455,
    "preview": "import fs from 'fs'\nimport path from 'path'\nimport net from 'net'\nimport childProcess from 'child_process'\n\nconst homeEn"
  },
  {
    "path": "package.json",
    "chars": 4149,
    "preview": "{\n  \"name\": \"react-native-debugger\",\n  \"version\": \"0.14.0\",\n  \"productName\": \"React Native Debugger In Dev\",\n  \"descript"
  },
  {
    "path": "patches/@redux-devtools+inspector-monitor-trace-tab+1.0.0.patch",
    "chars": 1881,
    "preview": "diff --git a/node_modules/@redux-devtools/inspector-monitor-trace-tab/src/openFile.ts b/node_modules/@redux-devtools/ins"
  },
  {
    "path": "patches/@redux-devtools+ui+1.3.0.patch",
    "chars": 952,
    "preview": "diff --git a/node_modules/@redux-devtools/ui/lib/esm/Tabs/Tabs.js b/node_modules/@redux-devtools/ui/lib/esm/Tabs/Tabs.js"
  },
  {
    "path": "patches/apollo-client-devtools+4.1.4.patch",
    "chars": 14013,
    "preview": "diff --git a/node_modules/apollo-client-devtools/build/background.js b/node_modules/apollo-client-devtools/build/backgro"
  },
  {
    "path": "patches/electron-gh-releases+2.0.4.patch",
    "chars": 670,
    "preview": "diff --git a/node_modules/electron-gh-releases/GhReleases.js b/node_modules/electron-gh-releases/GhReleases.js\nindex cab"
  },
  {
    "path": "patches/react-dev-utils+4.2.3.patch",
    "chars": 552,
    "preview": "diff --git a/node_modules/react-dev-utils/launchEditor.js b/node_modules/react-dev-utils/launchEditor.js\nindex 3bb1d55.."
  },
  {
    "path": "scripts/config.json",
    "chars": 200,
    "preview": "{\n  \"dest\": \"release/\",\n  \"icon\": \"electron/logo.ico\",\n  \"categories\": [\"Utility\"],\n  \"lintianOverrides\": [\"changelog-fi"
  },
  {
    "path": "scripts/mac/createDMG.js",
    "chars": 910,
    "preview": "const path = require('path')\nconst createDMG = require('electron-installer-dmg')\nconst pkg = require('../../package.json"
  },
  {
    "path": "scripts/mac/createUniversalApp.js",
    "chars": 1717,
    "preview": "const path = require('path')\nconst { version: electronVersion } = require('electron/package.json')\nconst { makeUniversal"
  },
  {
    "path": "scripts/mac/entitlements.plist",
    "chars": 472,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "scripts/package-linux.sh",
    "chars": 1072,
    "preview": "#!/bin/bash\n\nPACKAGE_VERSION=$(node -e \"console.log(require('./package.json').version)\")\n\necho \"[v$PACKAGE_VERSION] Pack"
  },
  {
    "path": "scripts/package-macos.sh",
    "chars": 1896,
    "preview": "#!/bin/bash\n\nPACKAGE_VERSION=$(node -e \"console.log(require('./package.json').version)\")\n\necho \"[v$PACKAGE_VERSION] Pack"
  },
  {
    "path": "scripts/package-windows.sh",
    "chars": 957,
    "preview": "#!/bin/bash\n\nPACKAGE_VERSION=$(node -e \"console.log(require('./package.json').version)\")\n\necho \"[v$PACKAGE_VERSION] Pack"
  },
  {
    "path": "scripts/patch-modules.js",
    "chars": 495,
    "preview": "const shell = require('shelljs')\nconst path = require('path')\n\nconsole.log('Patch react-devtools-core')\n\nconst rdStandal"
  },
  {
    "path": "scripts/postinstall.js",
    "chars": 501,
    "preview": "const shell = require('shelljs')\n\nasync function run() {\n  shell.cd('npm-package')\n  shell.exec('yarn')\n  shell.cd('-')\n"
  },
  {
    "path": "webpack/.eslintrc",
    "chars": 63,
    "preview": "{\n  \"rules\": {\n    \"import/no-extraneous-dependencies\": 0\n  }\n}"
  },
  {
    "path": "webpack/base.js",
    "chars": 1037,
    "preview": "const path = require('path')\nconst electronPkg = require('electron/package.json')\nconst babelConfig = require('../babel."
  },
  {
    "path": "webpack/main.prod.js",
    "chars": 805,
    "preview": "const path = require('path')\nconst webpack = require('webpack')\nconst TerserPlugin = require('terser-webpack-plugin')\nco"
  },
  {
    "path": "webpack/renderer.dev.js",
    "chars": 1060,
    "preview": "const webpack = require('webpack')\nconst baseConfig = require('./base')\n\nconst port = 3000\n\nconst baseDevConfig = {\n  .."
  },
  {
    "path": "webpack/renderer.prod.js",
    "chars": 1543,
    "preview": "const webpack = require('webpack')\nconst TerserPlugin = require('terser-webpack-plugin')\nconst { BundleAnalyzerPlugin } "
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the jhen0409/react-native-debugger GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 144 files (364.4 KB), approximately 98.3k tokens, and a symbol index with 96 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!