[
  {
    "path": ".changeset/config.json",
    "content": "{\n  \"$schema\": \"https://unpkg.com/@changesets/config@1.6.4/schema.json\",\n  \"changelog\": \"@changesets/cli/changelog\",\n  \"commit\": false,\n  \"linked\": [],\n  \"access\": \"public\",\n  \"baseBranch\": \"main\",\n  \"updateInternalDependencies\": \"patch\",\n  \"ignore\": [],\n  \"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH\": {\n    \"onlyUpdatePeerDependentsWhenOutOfRange\": true\n  }\n}\n"
  },
  {
    "path": ".eslintignore",
    "content": "*.log\n.idea\nlib\ndist\numd\nbuild\ncoverage\nnode_modules\n__snapshots__\nstorybook-static\n.vscode/*\n"
  },
  {
    "path": ".gitattributes",
    "content": "* text=auto eol=lf\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: Methuselah96\nopen_collective: redux-devtools-extension\n"
  },
  {
    "path": ".github/workflows/CI.yml",
    "content": "name: CI\n\non:\n  push:\n    branches: [main]\n  pull_request:\n    branches: [main]\n\njobs:\n  build:\n    runs-on: 'ubuntu-24.04'\n\n    steps:\n      - uses: actions/checkout@v6\n      - uses: pnpm/action-setup@v5\n      - uses: actions/setup-node@v6\n        with:\n          node-version: 'lts/*'\n          cache: 'pnpm'\n      - name: Install dependencies\n        run: pnpm install\n      - name: Check formatting\n        run: pnpm run format:check\n      - name: Build\n        run: pnpm run build:all\n      - name: Lint\n        run: pnpm run lint:all\n      - run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0\n      - name: Test\n        uses: coactions/setup-xvfb@v1\n        with:\n          run: pnpm run test:all\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\n\non:\n  push:\n    branches:\n      - main\n\npermissions: write-all\n\njobs:\n  release:\n    name: Release\n    runs-on: 'ubuntu-24.04'\n    steps:\n      - name: Checkout Repo\n        uses: actions/checkout@v6\n        with:\n          # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits\n          fetch-depth: 0\n\n      - uses: pnpm/action-setup@v5\n\n      - name: Setup Node.js\n        uses: actions/setup-node@v6\n        with:\n          node-version: 'lts/*'\n          cache: 'pnpm'\n\n      - name: Install Dependencies\n        run: pnpm install\n\n      - name: Create Release Pull Request or Publish to npm\n        id: changesets\n        uses: changesets/action@v1\n        with:\n          version: pnpm changeset version\n          publish: pnpm run release\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}\n\n      - name: Archive Chrome Extension\n        uses: actions/upload-artifact@v7\n        with:\n          name: chrome\n          path: extension/chrome/dist\n\n      - name: Archive Edge Extension\n        uses: actions/upload-artifact@v7\n        with:\n          name: edge\n          path: extension/edge/dist\n\n      - name: Archive Firefox Extension\n        uses: actions/upload-artifact@v7\n        with:\n          name: firefox\n          path: extension/firefox/dist\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\n*.log\n.DS_Store\nlib\ndist\numd\nbuild\ncoverage\n.idea\n.eslintcache\n!packages/redux-devtools-slider-monitor/examples/todomvc/dist/index.html\n.nx\n*.tsbuildinfo\n"
  },
  {
    "path": ".prettierignore",
    "content": "*.log\n.idea\nlib\ndist\numd\nbuild\ncoverage\nnode_modules\n__snapshots__\ndev\n**/demo/public/**\nstorybook-static\n.vscode/*\npnpm-lock.yaml\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"singleQuote\": true\n}\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Code of Conduct\n\nAs contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.\n\nWe are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.\n\nExamples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.\n\nThis Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)\n"
  },
  {
    "path": "LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015-present Dan Abramov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "![GitHub Workflow Status](https://img.shields.io/github/workflow/status/reduxjs/redux-devtools/CI)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=round-square)](https://github.com/reduxjs/redux-devtools/pulls)\n[![OpenCollective](https://opencollective.com/redux-devtools-extension/backers/badge.svg)](#backers)\n[![OpenCollective](https://opencollective.com/redux-devtools-extension/sponsors/badge.svg)](#sponsors)\n\n# Redux DevTools\n\nDeveloper Tools to power-up [Redux](https://redux.js.org/) development workflow or any other architecture which handles the state change (see [integrations](https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/Integrations.md)).\n\nIt can be used as a browser extension (for [Chrome](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd), [Edge](https://microsoftedge.microsoft.com/addons/detail/redux-devtools/nnkgneoiohoecpdiaponcejilbhhikei) and [Firefox](https://addons.mozilla.org/en-US/firefox/addon/reduxdevtools/)), as [a standalone app](https://github.com/reduxjs/redux-devtools/tree/main/packages/redux-devtools-app) or as [a React component](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools) integrated in the client app.\n\n![image](https://user-images.githubusercontent.com/7957859/48663602-3aac4900-ea9b-11e8-921f-97059cbb599c.png)\n\n## Documentation\n\n- [Browser Extension Installation and Configuration](https://github.com/reduxjs/redux-devtools/tree/main/extension#installation)\n- [Manual Integration as a React Component](./docs/Walkthrough.md#manual-integration)\n- [Extension Options (Arguments)](https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/API/Arguments.md)\n- [Extension Methods (Advanced API)](https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/API/Methods.md)\n- [Remote monitoring](./docs/Integrations/Remote.md)\n- [Troubleshooting](https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/Troubleshooting.md)\n- [Recipes](https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/Recipes.md)\n- [FAQ](https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/FAQ.md)\n\n## Development\n\nThis is a monorepo powered by [pnpm](https://pnpm.io/). [Install pnpm](https://pnpm.io/installation) and run `pnpm install` to get started. Each package's dependencies need to be built before the package itself can be built. You can either build all the packages (i.e., `pnpm run build:all`) or use pnpm workspace commands to build only the packages necessary for the packages you're working on (i.e., `pnpm --filter \"remotedev-redux-devtools-extension\" build`).\n\n## Backers\n\nSupport us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/redux-devtools-extension#backer)]\n\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/0/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/0/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/1/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/1/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/2/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/2/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/3/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/3/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/4/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/4/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/5/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/5/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/6/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/6/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/7/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/7/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/8/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/8/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/9/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/9/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/10/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/10/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/11/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/11/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/12/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/12/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/13/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/13/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/14/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/14/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/15/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/15/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/16/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/16/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/17/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/17/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/18/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/18/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/19/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/19/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/20/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/20/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/21/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/21/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/22/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/22/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/23/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/23/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/24/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/24/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/25/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/25/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/26/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/26/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/27/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/27/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/28/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/28/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/29/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/29/avatar.svg\"></a>\n\n## Sponsors\n\nBecome a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/redux-devtools-extension#sponsor)]\n\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/0/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/0/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/1/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/1/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/2/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/2/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/3/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/3/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/4/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/4/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/5/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/5/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/6/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/6/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/7/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/7/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/8/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/8/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/9/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/9/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/10/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/10/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/11/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/11/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/12/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/12/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/13/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/13/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/14/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/14/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/15/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/15/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/16/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/16/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/17/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/17/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/18/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/18/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/19/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/19/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/20/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/20/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/21/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/21/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/22/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/22/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/23/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/23/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/24/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/24/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/25/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/25/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/26/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/26/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/27/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/27/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/28/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/28/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/29/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/29/avatar.svg\"></a>\n\n### License\n\nMIT\n"
  },
  {
    "path": "docs/Integrations/Remote.md",
    "content": "## Remote monitoring\n\nBy installing [`@redux-devtools/cli`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-cli#usage), starting the server server and launching the Redux DevTools app (`redux-devtools --open`), you can connect any remote application, even not javascript. There are some integrations for javascript like [remote-redux-devtools](https://github.com/zalmoxisus/remote-redux-devtools) and [remotedev](https://github.com/zalmoxisus/remotedev), but the plan is to deprecate them and support it out of the box from the extension without a websocket server. It is more useful for non-js apps.\n\n### WebSocket Clients\n\nWe're using [SocketCluster](http://socketcluster.io/) for realtime communication, which provides a fast and scalable webSocket layer and a minimal pub/sub system. You need to include one of [its clients](https://github.com/SocketCluster/client-drivers) in your app to communicate with RemotedevServer. Currently there are clients for [JavaScript (NodeJS)](https://github.com/SocketCluster/socketcluster-client), [Java](https://github.com/sacOO7/socketcluster-client-java), [Python](https://github.com/sacOO7/socketcluster-client-python), [C](https://github.com/sacOO7/socketcluster-client-C), [Objective-C](https://github.com/abpopov/SocketCluster-ios-client) and [.NET/C#](https://github.com/sacOO7/SocketclusterClientDotNet).\n\nBy default, the websocket server is running on `ws://localhost:8000/socketcluster/`.\n\n### Messaging lifecycle\n\n#### 1. Connecting to the WebSocket server\n\nThe client driver provides a way to connect to the server via websockets (see the docs for the selected client).\n\n##### JavaScript\n\n```js\nvar socket = socketCluster.connect({\n  hostname: 'localhost',\n  port: 8000,\n});\n```\n\n##### Python\n\n```py\nsocket = Socketcluster.socket(\"ws://localhost:8000/socketcluster/\")\nsocket.connect()\n```\n\n> Note that JavaScript client composes the url from `hostname` and `port`, adding `/socketcluster/` path automatically. For other clients, you should specify that path. For example, for `ObjectiveC` it would be `self.client.initWithHost(\"localhost/socketcluster/\", onPort: 8000, securely: false)`.\n\n#### 2. Disconnecting and reconnecting\n\nSocketCluster client handles reconnecting for you, but you still might want to know when the connection is established, or when it failed to connect.\n\n##### JavaScript\n\n```js\nsocket.on('connect', (status) => {\n  // Here will come the next step\n});\nsocket.on('disconnect', (code) => {\n  console.warn('Socket disconnected with code', code);\n});\nsocket.on('error', (error) => {\n  console.warn('Socket error', error);\n});\n```\n\n##### Python\n\n```py\ndef onconnect(socket):\n  // Here will call the next step\n\ndef ondisconnect(socket):\n  logging.info(\"on disconnect got called\")\n\ndef onConnectError(socket, error):\n  logging.info(\"On connect error got called\")\n\nsocket.setBasicListener(onconnect, ondisconnect, onConnectError)\n```\n\n#### 3. Authorizing and subscribing to the channel of events\n\nWe're not providing an authorizing mechanism yet. All you have to do is to emit a `login` event, and you'll get a `channelName` you should subscribe for, and watch for messages and events. Make sure to pass the `master` event, otherwise it should be a monitor, not a client app.\n\n##### JavaScript\n\n```js\nsocket.emit('login', 'master', (error, channelName) => {\n  if (error) {\n    console.log(error);\n    return;\n  }\n  channel = socket.subscribe(channelName);\n  channel.watch(handleMessages);\n  socket.on(channelName, handleMessages);\n});\n\nfunction handleMessages(message) {\n  // 5. Listening for monitor events\n}\n```\n\n##### Python\n\n```py\nsocket.emitack(\"login\", \"master\", login)\n\ndef login(key, error, channelName):\n  socket.subscribe(channelName)\n  socket.onchannel(channelName, handleMessages)\n  socket.on(channelName, handleMessages)\n\ndef handleMessages(key, message):\n  // 5. Listening for monitor events\n```\n\nYou could just emit the `login` event, and omit subscribing (and point `5` bellow) if you want only to log data, not to interact with te app.\n\n#### 4. Sending the action and state to the monitor\n\nTo send your data to the monitor use `log` or `log-noid` channel. The latter will add the socket id to the message from the server side (useful when the message was sent before the connection was established).\n\nThe message object includes the following:\n\n- `type` - usually should be `ACTION`. If you want to indicate that we're starting a new log (clear all actions emitted before and add `@@INIT`), use `INIT`. In case you have a lifted state similar to one provided by [`redux-devtools-instrument`](https://github.com/zalmoxisus/redux-devtools-instrument), use `STATE`.\n- `action` - the action object. It is recommended to lift it in another object, and add `timestamp` to show when the action was fired off: `{ timestamp: Date.now(), action: { type: 'SOME_ACTION' } }`.\n- `payload` - usually the state or lifted state object.\n- `name` - name of the instance to be shown in the instances selector. If not provided, it will be equal to `instanceId`.\n- `instanceId` - an id to identify the instance. If not provided, it will be the same as `id`. However, it is useful when having several instances (or stores) in the same connection. Also if the user will specify a constant value, it would allow to persist the state on app reload.\n- `id` - socket connection id, which should be either `socket.id` or should not provided and use `log-noid` channel.\n\n##### JavaScript\n\n```js\nconst message = {\n  type: 'ACTION',\n  action: { action, timestamp: Date.now() },\n  payload: state,\n  id: socket.id,\n  instanceId: window.btoa(location.href),\n  name: document.title,\n};\nsocket.emit(socket.id ? 'log' : 'log-noid', message);\n```\n\n##### Python\n\n```py\nclass Message:\n  def __init__(self, action, state):\n    self.type = \"ACTION\"\n    self.action = action\n    self.payload = state\n    id: socket.id\nsocket.emit(socket.id if \"log\" else \"log-noid\", Message(action, state));\n```\n\n#### 5. Listening for monitor events\n\nWhen a monitor action is emitted, you'll get an event on the subscribed function. The argument object includes a `type` key, which can be:\n\n- `DISPATCH` - a monitor action dispatched on Redux DevTools monitor, like `{ type: 'DISPATCH', payload: { type: 'JUMP_TO_STATE', 'index': 2 }`. See [`redux-devtools-instrument`](https://github.com/zalmoxisus/redux-devtools-instrument/blob/master/src/instrument.js) for details. Additionally to that API, you'll get also a stringified `state` object when needed. So, for example, for time travelling (`JUMP_TO_STATE`) you can just parse and set the state (see the example). Usually implementing this type of actions would be enough.\n- `ACTION` - the user requested to dispatch an action remotely like `{ type: 'ACTION', action: '{ type: \\'INCREMENT_COUNTER\\' }' }`. The `action` can be either a stringified javascript object which should be evalled or a function which arguments should be evalled like [here](https://github.com/zalmoxisus/remotedev-utils/blob/master/src/index.js#L62-L70).\n- `START` - a monitor was opened. You could handle this event in order not to do extra tasks when the app is not monitored.\n- `STOP` - a monitor was closed. You can take this as no need to send data to the monitor. I there are several monitors and one was closed, all others will send `START` event to acknowledge that we still have to send data.\n\nSee [`mobx-remotedev`](https://github.com/zalmoxisus/mobx-remotedev/blob/master/src/monitorActions.js) for an example of implementation without [`redux-devtools-instrument`](https://github.com/zalmoxisus/redux-devtools-instrument/blob/master/src/instrument.js).\n\n##### JavaScript\n\n```js\nfunction handleMessages(message) {\n  if (message.type === 'DISPATCH' && message.payload.type === 'JUMP_TO_STATE') {\n    store.setState(JSON.parse(message.state));\n  }\n}\n```\n\n##### Python\n\n```py\ndef handleMessages(key, message):\n  if message.type === \"DISPATCH\" and message.payload.type === \"JUMP_TO_STATE\":\n    store.setState(json.loads(message.state));\n```\n"
  },
  {
    "path": "docs/Walkthrough.md",
    "content": "# Walkthrough\n\n## Browser Extension\n\nIf you don’t want to bother with installing Redux DevTools and integrating it into your project, consider using [Redux DevTools Extension](https://github.com/reduxjs/redux-devtools/tree/master/extension) for Chrome and Firefox. It provides access to the most popular monitors, is easy to configure to filter actions, and doesn’t require installing any packages.\n\n## Manual Integration\n\nIf you want to have full control over where DevTools are displayed, or are developing a custom monitor, you will probably want to integrate them manually.\nIt’s more steps, but you will have full control over monitors and their configuration.\n\n### Installation\n\n```\nnpm install --save-dev @redux-devtools/core\n```\n\nYou’ll also likely want to install some monitors:\n\n```\nnpm install --save-dev @redux-devtools/log-monitor\nnpm install --save-dev @redux-devtools/dock-monitor\n```\n\n### Usage\n\n#### Create a `DevTools` Component\n\nSomewhere in your project, create a `DevTools` component by passing a `monitor` element to `createDevTools`. In the following example our `monitor` consists of [`LogMonitor`](https://github.com/gaearon/redux-devtools-log-monitor) docked within [`DockMonitor`](https://github.com/gaearon/redux-devtools-dock-monitor):\n\n##### `containers/DevTools.js`\n\n```js\nimport React from 'react';\n\n// Exported from redux-devtools\nimport { createDevTools } from '@redux-devtools/core';\n\n// Monitors are separate packages, and you can make a custom one\nimport LogMonitor from '@redux-devtools/log-monitor';\nimport DockMonitor from '@redux-devtools/dock-monitor';\n\n// createDevTools takes a monitor and produces a DevTools component\nconst DevTools = createDevTools(\n  // Monitors are individually adjustable with props.\n  // Consult their repositories to learn about those props.\n  // Here, we put LogMonitor inside a DockMonitor.\n  // Note: DockMonitor is visible by default.\n  <DockMonitor\n    toggleVisibilityKey=\"ctrl-h\"\n    changePositionKey=\"ctrl-q\"\n    defaultIsVisible={true}\n  >\n    <LogMonitor theme=\"tomorrow\" />\n  </DockMonitor>,\n);\n\nexport default DevTools;\n```\n\nNote that you can use `LogMonitor` directly without wrapping it in `DockMonitor` if you’d like to display the DevTools UI somewhere right inside your application:\n\n```js\n// If you'd rather not use docking UI, use <LogMonitor> directly\nconst DevTools = createDevTools(<LogMonitor theme=\"solarized\" />);\n```\n\n#### Use `DevTools.instrument()` Store Enhancer\n\nThe `DevTools` component you created with `createDevTools()` has a special static method called `instrument()`. It returns a [store enhancer](http://redux.js.org/docs/Glossary.html#store-enhancer) that you need to use in development.\n\nA store enhancer is a function that enhances the behavior of `createStore()`. You can pass store enhancer as the last optional argument to `createStore()`. You probably already used another store enhancer—[`applyMiddleware()`](http://redux.js.org/docs/api/applyMiddleware.html). Unlike `applyMiddleware()`, you will need to be careful to only use `DevTools.instrument()` in development environment, and never in production.\n\nThe easiest way to apply several store enhancers in a row is to use the [`compose()`](http://redux.js.org/docs/api/compose.html) utility function that ships with Redux. It is the same `compose()` that you can find in Underscore and Lodash. In our case, we would use it to compose several store enhancers into one: `compose(applyMiddleware(m1, m2, m3), DevTools.instrument())`.\n\nYou can add additional options to it: `DevTools.instrument({ maxAge: 50, shouldCatchErrors: true })`. See [`redux-devtools-instrument`'s API](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-instrument#api) for more details.\n\nIt’s important that you should add `DevTools.instrument()` _after_ `applyMiddleware` in your `compose()` function arguments. This is because `applyMiddleware` is potentially asynchronous, but `DevTools.instrument()` expects all actions to be plain objects rather than actions interpreted by asynchronous middleware such as [redux-promise](https://github.com/acdlite/redux-promise) or [redux-thunk](https://github.com/gaearon/redux-thunk). So make sure `applyMiddleware()` goes first in the `compose()` call, and `DevTools.instrument()` goes after it.\n\n##### `store/configureStore.js`\n\n```js\nimport { createStore, applyMiddleware, compose } from 'redux';\nimport rootReducer from '../reducers';\nimport DevTools from '../containers/DevTools';\n\nconst enhancer = compose(\n  // Middleware you want to use in development:\n  applyMiddleware(d1, d2, d3),\n  // Required! Enable Redux DevTools with the monitors you chose\n  DevTools.instrument(),\n);\n\nexport default function configureStore(initialState) {\n  // Note: only Redux >= 3.1.0 supports passing enhancer as third argument.\n  // See https://github.com/reactjs/redux/releases/tag/v3.1.0\n  const store = createStore(rootReducer, initialState, enhancer);\n\n  // Hot reload reducers (requires Webpack or Browserify HMR to be enabled)\n  if (module.hot) {\n    module.hot.accept('../reducers', () =>\n      store.replaceReducer(\n        require('../reducers') /*.default if you use Babel 6+ */,\n      ),\n    );\n  }\n\n  return store;\n}\n```\n\nIf you’d like, you may add another store enhancer called `persistState()`. It ships with this package, and it lets you serialize whole sessions (including all dispatched actions and the state of the monitors) by a URL key. So if you visit `http://localhost:3000/?debug_session=reproducing_weird_bug`, do something in the app, then open `http://localhost:3000/?debug_session=some_other_feature`, and then go back to `http://localhost:3000/?debug_session=reproducing_weird_bug`, the state will be restored. The implementation of `persistState()` is fairly naïve but you can take it as an inspiration and build a proper UI for it if you feel like it!\n\n```js\n// ...\nimport { persistState } from '@redux-devtools/core';\n\nconst enhancer = compose(\n  // Middleware you want to use in development:\n  applyMiddleware(d1, d2, d3),\n  // Required! Enable Redux DevTools with the monitors you chose\n  DevTools.instrument(),\n  // Optional. Lets you write ?debug_session=<key> in address bar to persist debug sessions\n  persistState(getDebugSessionKey()),\n);\n\nfunction getDebugSessionKey() {\n  // You can write custom logic here!\n  // By default we try to read the key from ?debug_session=<key> in the address bar\n  const matches = window.location.href.match(/[?&]debug_session=([^&#]+)\\b/);\n  return matches && matches.length > 0 ? matches[1] : null;\n}\n\nexport default function configureStore(initialState) {\n  // ...\n}\n```\n\n#### Exclude DevTools from Production Builds\n\nFinally, to make sure we’re not pulling any DevTools-related code in the production builds, we will envify our code. You can use [`DefinePlugin`](https://github.com/webpack/docs/wiki/list-of-plugins#defineplugin) with Webpack, or [`envify`](https://github.com/zertosh/loose-envify) for Browserify.\n\nThe trick is to replace all occurrences of a constant like `process.env.NODE_ENV` into a string depending on the environment, and import and render `redux-devtools` only when `process.env.NODE_ENV` is not `'production'`. Then, if you have an Uglify step before production, Uglify will eliminate dead `if (false)` branches with `redux-devtools` imports.\n\nWith Webpack, you'll need two config files, one for development and one for production. Here's a snippet from an example production config:\n\n##### `webpack.config.prod.js`\n\n```js\n// ...\nplugins: [\n  new webpack.DefinePlugin({\n    'process.env.NODE_ENV': JSON.stringify('production')\n  })\n],\n// ...\n```\n\nIf you are using ES6 modules with Webpack 1.x and Babel, you might try putting your `import` statement inside an `if (process.env.NODE_ENV !== 'production)` to exclude the DevTools package from your production bundle. However this ES6 specification forbids it, so this won’t compile. Instead, you can use a conditional CommonJS `require`. Babel will let it compile, and Uglify will eliminate the dead branches before Webpack creates a bundle. This is why we recommend creating a `configureStore.js` file that either directs you to `configureStore.dev.js` or `configureStore.prod.js` depending on the configuration. While it is a little bit more maintenance, the upside is that you can be sure you won’t pull any development dependencies into the production builds, and that you can easily enable different middleware (e.g. crash reporting, logging) in the production environment.\n\n##### `store/configureStore.js`\n\n```js\n// Use DefinePlugin (Webpack) or loose-envify (Browserify)\n// together with Uglify to strip the dev branch in prod build.\nif (process.env.NODE_ENV === 'production') {\n  module.exports = require('./configureStore.prod');\n} else {\n  module.exports = require('./configureStore.dev');\n}\n```\n\n##### `store/configureStore.prod.js`\n\n```js\nimport { createStore, applyMiddleware, compose } from 'redux';\nimport rootReducer from '../reducers';\n\n// Middleware you want to use in production:\nconst enhancer = applyMiddleware(p1, p2, p3);\n\nexport default function configureStore(initialState) {\n  // Note: only Redux >= 3.1.0 supports passing enhancer as third argument.\n  // See https://github.com/rackt/redux/releases/tag/v3.1.0\n  return createStore(rootReducer, initialState, enhancer);\n}\n```\n\n##### `store/configureStore.dev.js`\n\n```js\nimport { createStore, applyMiddleware, compose } from 'redux';\nimport { persistState } from '@redux-devtools/core';\nimport rootReducer from '../reducers';\nimport DevTools from '../containers/DevTools';\n\nconst enhancer = compose(\n  // Middleware you want to use in development:\n  applyMiddleware(d1, d2, d3),\n  // Required! Enable Redux DevTools with the monitors you chose\n  DevTools.instrument(),\n  // Optional. Lets you write ?debug_session=<key> in address bar to persist debug sessions\n  persistState(getDebugSessionKey()),\n);\n\nfunction getDebugSessionKey() {\n  // You can write custom logic here!\n  // By default we try to read the key from ?debug_session=<key> in the address bar\n  const matches = window.location.href.match(/[?&]debug_session=([^&]+)\\b/);\n  return matches && matches.length > 0 ? matches[1] : null;\n}\n\nexport default function configureStore(initialState) {\n  // Note: only Redux >= 3.1.0 supports passing enhancer as third argument.\n  // See https://github.com/rackt/redux/releases/tag/v3.1.0\n  const store = createStore(rootReducer, initialState, enhancer);\n\n  // Hot reload reducers (requires Webpack or Browserify HMR to be enabled)\n  if (module.hot) {\n    module.hot.accept('../reducers', () =>\n      store.replaceReducer(\n        require('../reducers') /*.default if you use Babel 6+ */,\n      ),\n    );\n  }\n\n  return store;\n}\n```\n\n#### Render `<DevTools>` in Your App...\n\nFinally, include the `DevTools` component in your page.  \nA naïve way to do this would be to render it right in your `index.js`:\n\n##### `index.js`\n\n```js\nimport React from 'react';\nimport { render } from 'react-dom';\nimport { Provider } from 'react-redux';\nimport configureStore from './store/configureStore';\nimport TodoApp from './containers/TodoApp';\n\n// Don't do this! You’re bringing DevTools into the production bundle.\nimport DevTools from './containers/DevTools';\n\nconst store = configureStore();\n\nrender(\n  <Provider store={store}>\n    <div>\n      <TodoApp />\n      <DevTools />\n    </div>\n  </Provider>\n  document.getElementById('app')\n);\n```\n\nWe recommend a different approach. Create a `Root.js` component that renders the root of your application (usually some component surrounded by a `<Provider>`). Then use the same trick with conditional `require` statements to have two versions of it, one for development, and one for production:\n\n##### `containers/Root.js`\n\n```js\nif (process.env.NODE_ENV === 'production') {\n  module.exports = require('./Root.prod');\n} else {\n  module.exports = require('./Root.dev');\n}\n```\n\n##### `containers/Root.dev.js`\n\n```js\nimport React, { Component } from 'react';\nimport { Provider } from 'react-redux';\nimport TodoApp from './TodoApp';\nimport DevTools from './DevTools';\n\nexport default class Root extends Component {\n  render() {\n    const { store } = this.props;\n    return (\n      <Provider store={store}>\n        <div>\n          <TodoApp />\n          <DevTools />\n        </div>\n      </Provider>\n    );\n  }\n}\n```\n\n##### `containers/Root.prod.js`\n\n```js\nimport React, { Component } from 'react';\nimport { Provider } from 'react-redux';\nimport TodoApp from './TodoApp';\n\nexport default class Root extends Component {\n  render() {\n    const { store } = this.props;\n    return (\n      <Provider store={store}>\n        <TodoApp />\n      </Provider>\n    );\n  }\n}\n```\n\n#### ...Or Open Them in a New Window\n\nWhen you use [`DockMonitor`](https://github.com/gaearon/redux-devtools-dock-monitor), you usually want to render `<DevTools>` at the root of your app. It will appear in a docked container above it. However, you can also render it anywhere else in your React component tree. To do this, you can remove `DockMonitor` and instead render `<DevTools>` inside some component of your app. Don’t forget to create two versions of this component to exclude `DevTools` in production!\n\nHowever you don’t even have to render `<DevTools>` in the same window. For example, you may prefer to display it in a popup. In this case, you can remove `DockMonitor` from `DevTools.js` and just use the `LogMonitor`, and have some code like this:\n\n##### `index.js`\n\n```js\nimport React from 'react';\nimport { Provider } from 'react-redux';\nimport { render } from 'react-dom';\nimport configureStore from './store/configureStore';\nimport App from './containers/App';\n\nconst store = configureStore();\n\nrender(\n  <Provider store={store}>\n    <App />\n  </Provider>,\n  document.getElementById('root'),\n);\n\nif (process.env.NODE_ENV !== 'production') {\n  const showDevTools = require('./showDevTools');\n  showDevTools(store);\n}\n```\n\n##### `showDevTools.js`\n\n```js\nimport React from 'react';\nimport { render } from 'react-dom';\nimport DevTools from './containers/DevTools';\n\nexport default function showDevTools(store) {\n  const popup = window.open(\n    null,\n    'Redux DevTools',\n    'menubar=no,location=no,resizable=yes,scrollbars=no,status=no',\n  );\n  // Reload in case it already exists\n  popup.location.reload();\n\n  setTimeout(() => {\n    popup.document.write('<div id=\"react-devtools-root\"></div>');\n    render(\n      <DevTools store={store} />,\n      popup.document.getElementById('react-devtools-root'),\n    );\n  }, 10);\n}\n```\n\nPersonal preferences vary, and whether to put the DevTools in a separate window, in a dock, or right inside you app’s user interface, is up to you. Make sure to check the documentation for the monitors you use and learn about the different props they support for customizing the appearance and the behavior.\n\nNote that there are no useful props you can pass to the `DevTools` component other than the `store`. The `store` prop is needed if you don’t wrap `<DevTools>` in a `<Provider>`—just like with any connected component. To adjust the monitors, you need to pass props to them inside `DevTools.js` itself inside the `createDevTools()` call when they are used.\n\n### Gotchas\n\n- **Your reducers have to be pure and free of side effects to work correctly with DevTools.** For example, even generating a random ID in reducer makes it impure and non-deterministic. Instead, do this in action creators.\n\n- **Make sure to only apply `DevTools.instrument()` and render `<DevTools>` in development!** In production, this will be terribly slow because actions just accumulate forever. As described above, you need to use conditional `require`s and use `DefinePlugin` (Webpack) or `loose-envify` (Browserify) together with Uglify to remove the dead code. Here is [an example](https://github.com/erikras/react-redux-universal-hot-example/) that adds Redux DevTools handling the production case correctly.\n\n- **It is important that `DevTools.instrument()` store enhancer should be added to your middleware stack _after_ `applyMiddleware` in the `compose`d functions, as `applyMiddleware` is potentially asynchronous.** Otherwise, DevTools won’t see the raw actions emitted by asynchronous middleware such as [redux-promise](https://github.com/acdlite/redux-promise) or [redux-thunk](https://github.com/gaearon/redux-thunk).\n\n### What Next?\n\nNow that you see the DevTools, you might want to learn what those buttons mean and how to use them. This usually depends on the monitor. You can begin by exploring the [LogMonitor](https://github.com/gaearon/redux-devtools-log-monitor) and [DockMonitor](https://github.com/gaearon/redux-devtools-dock-monitor) documentation, as they are the default monitors we suggest to use together. When you’re comfortable using them, you may want to create your own monitor for more exotic purposes, such as a [chart](https://github.com/romseguy/redux-devtools-chart-monitor) or a [diff](https://github.com/whetstone/redux-devtools-diff-monitor) monitor. Don’t forget to send a PR to feature your monitor at the front page!\n"
  },
  {
    "path": "eslint.js.config.base.mjs",
    "content": "import { defineConfig } from 'eslint/config';\nimport eslint from '@eslint/js';\nimport eslintConfigPrettier from 'eslint-config-prettier';\n\nexport default defineConfig([eslint.configs.recommended, eslintConfigPrettier]);\n"
  },
  {
    "path": "eslint.js.react.jest.config.base.mjs",
    "content": "import { defineConfig } from 'eslint/config';\nimport eslint from '@eslint/js';\nimport react from 'eslint-plugin-react';\nimport reactHooks from 'eslint-plugin-react-hooks';\nimport jest from 'eslint-plugin-jest';\nimport eslintConfigPrettier from 'eslint-config-prettier';\n\nexport default defineConfig([\n  {\n    files: ['test/**/*.js', 'test/**/*.jsx'],\n    ...eslint.configs.recommended,\n  },\n  {\n    files: ['test/**/*.js', 'test/**/*.jsx'],\n    ...react.configs.flat.recommended,\n  },\n  {\n    files: ['test/**/*.js', 'test/**/*.jsx'],\n    settings: {\n      react: {\n        version: 'detect',\n      },\n    },\n  },\n  {\n    files: ['test/**/*.js', 'test/**/*.jsx'],\n    ...reactHooks.configs.flat.recommended,\n  },\n  {\n    files: ['test/**/*.js', 'test/**/*.jsx'],\n    ...jest.configs['flat/recommended'],\n  },\n  {\n    files: ['test/**/*.js', 'test/**/*.jsx'],\n    ...jest.configs['jest/style'],\n  },\n  {\n    files: ['test/**/*.js', 'test/**/*.jsx'],\n    ...eslintConfigPrettier,\n  },\n]);\n"
  },
  {
    "path": "eslint.ts.config.base.mjs",
    "content": "import { defineConfig } from 'eslint/config';\nimport eslint from '@eslint/js';\nimport tseslint from 'typescript-eslint';\nimport eslintConfigPrettier from 'eslint-config-prettier';\n\nexport default (tsconfigRootDir, files = ['**/*.ts'], project = true) =>\n  defineConfig([\n    {\n      files,\n      ...eslint.configs.recommended,\n    },\n    ...tseslint.configs.recommendedTypeChecked.map((config) => ({\n      files,\n      ...config,\n    })),\n    ...tseslint.configs.stylisticTypeChecked.map((config) => ({\n      files,\n      ...config,\n    })),\n    {\n      files,\n      languageOptions: {\n        parserOptions: {\n          project,\n          tsconfigRootDir,\n        },\n      },\n    },\n    {\n      files,\n      ...eslintConfigPrettier,\n    },\n    {\n      files,\n      rules: {\n        '@typescript-eslint/no-unsafe-return': 'off',\n        '@typescript-eslint/no-unsafe-assignment': 'off',\n        '@typescript-eslint/no-unsafe-call': 'off',\n        '@typescript-eslint/no-unsafe-member-access': 'off',\n        '@typescript-eslint/prefer-optional-chain': 'off',\n        '@typescript-eslint/no-base-to-string': 'off',\n        '@typescript-eslint/consistent-indexed-object-style': 'off',\n        '@typescript-eslint/prefer-nullish-coalescing': 'off',\n        '@typescript-eslint/consistent-type-definitions': 'off',\n        '@typescript-eslint/no-unused-vars': 'off',\n        '@typescript-eslint/no-explicit-any': 'off',\n        '@typescript-eslint/prefer-for-of': 'off',\n        '@typescript-eslint/non-nullable-type-assertion-style': 'off',\n        '@typescript-eslint/class-literal-property-style': 'off',\n        '@typescript-eslint/no-redundant-type-constituents': 'off',\n        '@typescript-eslint/prefer-string-starts-ends-with': 'off',\n        '@typescript-eslint/no-duplicate-type-constituents': 'off',\n        '@typescript-eslint/array-type': 'off',\n        '@typescript-eslint/prefer-function-type': 'off',\n      },\n    },\n  ]);\n"
  },
  {
    "path": "eslint.ts.jest.config.base.mjs",
    "content": "import { defineConfig } from 'eslint/config';\nimport eslint from '@eslint/js';\nimport tseslint from 'typescript-eslint';\nimport jest from 'eslint-plugin-jest';\nimport eslintConfigPrettier from 'eslint-config-prettier';\n\nexport default (tsconfigRootDir) =>\n  defineConfig([\n    {\n      files: ['test/**/*.ts'],\n      ...eslint.configs.recommended,\n    },\n    ...tseslint.configs.recommendedTypeChecked.map((config) => ({\n      files: ['test/**/*.ts'],\n      ...config,\n    })),\n    ...tseslint.configs.stylisticTypeChecked.map((config) => ({\n      files: ['test/**/*.ts'],\n      ...config,\n    })),\n    {\n      files: ['test/**/*.ts'],\n      languageOptions: {\n        parserOptions: {\n          project: ['./tsconfig.test.json'],\n          tsconfigRootDir,\n        },\n      },\n    },\n    {\n      files: ['test/**/*.ts'],\n      ...jest.configs['flat/recommended'],\n    },\n    {\n      files: ['test/**/*.ts'],\n      ...jest.configs['jest/style'],\n    },\n    {\n      files: ['test/**/*.ts'],\n      ...eslintConfigPrettier,\n    },\n    {\n      files: ['test/**/*.ts'],\n      rules: {\n        '@typescript-eslint/no-unsafe-return': 'off',\n        '@typescript-eslint/no-unsafe-assignment': 'off',\n        '@typescript-eslint/no-unsafe-call': 'off',\n        '@typescript-eslint/no-unsafe-member-access': 'off',\n        '@typescript-eslint/prefer-optional-chain': 'off',\n        '@typescript-eslint/no-base-to-string': 'off',\n        '@typescript-eslint/consistent-indexed-object-style': 'off',\n        '@typescript-eslint/prefer-nullish-coalescing': 'off',\n        '@typescript-eslint/consistent-type-definitions': 'off',\n        '@typescript-eslint/no-unused-vars': 'off',\n        '@typescript-eslint/no-explicit-any': 'off',\n        '@typescript-eslint/prefer-for-of': 'off',\n        '@typescript-eslint/non-nullable-type-assertion-style': 'off',\n        '@typescript-eslint/class-literal-property-style': 'off',\n        '@typescript-eslint/no-redundant-type-constituents': 'off',\n        '@typescript-eslint/prefer-string-starts-ends-with': 'off',\n        '@typescript-eslint/no-duplicate-type-constituents': 'off',\n        '@typescript-eslint/array-type': 'off',\n        '@typescript-eslint/prefer-function-type': 'off',\n      },\n    },\n  ]);\n"
  },
  {
    "path": "eslint.ts.react.config.base.mjs",
    "content": "import { defineConfig } from 'eslint/config';\nimport eslint from '@eslint/js';\nimport tseslint from 'typescript-eslint';\nimport react from 'eslint-plugin-react';\nimport reactHooks from 'eslint-plugin-react-hooks';\nimport eslintConfigPrettier from 'eslint-config-prettier';\n\nexport default (\n  tsconfigRootDir,\n  files = ['**/*.ts', '**/*.tsx'],\n  project = true,\n) =>\n  defineConfig([\n    {\n      files,\n      ...eslint.configs.recommended,\n    },\n    ...tseslint.configs.recommendedTypeChecked.map((config) => ({\n      files,\n      ...config,\n    })),\n    ...tseslint.configs.stylisticTypeChecked.map((config) => ({\n      files,\n      ...config,\n    })),\n    {\n      files,\n      languageOptions: {\n        parserOptions: {\n          project,\n          tsconfigRootDir,\n        },\n      },\n    },\n    {\n      files,\n      ...react.configs.flat.recommended,\n    },\n    {\n      files,\n      settings: {\n        react: {\n          version: 'detect',\n        },\n      },\n    },\n    {\n      files,\n      ...reactHooks.configs.flat.recommended,\n    },\n    {\n      files,\n      ...eslintConfigPrettier,\n    },\n    {\n      files,\n      rules: {\n        '@typescript-eslint/no-unsafe-return': 'off',\n        '@typescript-eslint/no-unsafe-assignment': 'off',\n        '@typescript-eslint/no-unsafe-call': 'off',\n        '@typescript-eslint/no-unsafe-member-access': 'off',\n        '@typescript-eslint/no-misused-promises': [\n          'error',\n          {\n            checksVoidReturn: {\n              attributes: false,\n            },\n          },\n        ],\n        '@typescript-eslint/prefer-optional-chain': 'off',\n        '@typescript-eslint/no-base-to-string': 'off',\n        '@typescript-eslint/consistent-indexed-object-style': 'off',\n        '@typescript-eslint/prefer-nullish-coalescing': 'off',\n        '@typescript-eslint/consistent-type-definitions': 'off',\n        '@typescript-eslint/no-unused-vars': 'off',\n        '@typescript-eslint/no-explicit-any': 'off',\n        '@typescript-eslint/prefer-for-of': 'off',\n        '@typescript-eslint/non-nullable-type-assertion-style': 'off',\n        '@typescript-eslint/class-literal-property-style': 'off',\n        '@typescript-eslint/no-redundant-type-constituents': 'off',\n        '@typescript-eslint/prefer-string-starts-ends-with': 'off',\n        '@typescript-eslint/no-duplicate-type-constituents': 'off',\n        '@typescript-eslint/array-type': 'off',\n        '@typescript-eslint/prefer-function-type': 'off',\n        'react/prop-types': 'off',\n      },\n    },\n  ]);\n"
  },
  {
    "path": "eslint.ts.react.jest.config.base.mjs",
    "content": "import { defineConfig } from 'eslint/config';\nimport eslint from '@eslint/js';\nimport tseslint from 'typescript-eslint';\nimport react from 'eslint-plugin-react';\nimport reactHooks from 'eslint-plugin-react-hooks';\nimport jest from 'eslint-plugin-jest';\nimport eslintConfigPrettier from 'eslint-config-prettier';\n\nexport default (tsconfigRootDir) =>\n  defineConfig([\n    {\n      files: ['test/**/*.ts', 'test/**/*.tsx'],\n      ...eslint.configs.recommended,\n    },\n    ...tseslint.configs.recommendedTypeChecked.map((config) => ({\n      files: ['test/**/*.ts', 'test/**/*.tsx'],\n      ...config,\n    })),\n    ...tseslint.configs.stylisticTypeChecked.map((config) => ({\n      files: ['test/**/*.ts', 'test/**/*.tsx'],\n      ...config,\n    })),\n    {\n      files: ['test/**/*.ts', 'test/**/*.tsx'],\n      languageOptions: {\n        parserOptions: {\n          project: ['./tsconfig.test.json'],\n          tsconfigRootDir,\n        },\n      },\n    },\n    {\n      files: ['test/**/*.ts', 'test/**/*.tsx'],\n      ...react.configs.flat.recommended,\n    },\n    {\n      files: ['test/**/*.ts', 'test/**/*.tsx'],\n      settings: {\n        react: {\n          version: 'detect',\n        },\n      },\n    },\n    {\n      files: ['test/**/*.ts', 'test/**/*.tsx'],\n      ...reactHooks.configs.flat.recommended,\n    },\n    {\n      files: ['test/**/*.ts', 'test/**/*.tsx'],\n      ...jest.configs['flat/recommended'],\n    },\n    {\n      files: ['test/**/*.ts', 'test/**/*.tsx'],\n      ...jest.configs['jest/style'],\n    },\n    {\n      files: ['test/**/*.ts', 'test/**/*.tsx'],\n      ...eslintConfigPrettier,\n    },\n    {\n      files: ['test/**/*.ts', 'test/**/*.tsx'],\n      rules: {\n        '@typescript-eslint/no-unsafe-return': 'off',\n        '@typescript-eslint/no-unsafe-assignment': 'off',\n        '@typescript-eslint/no-unsafe-call': 'off',\n        '@typescript-eslint/no-unsafe-member-access': 'off',\n        '@typescript-eslint/prefer-optional-chain': 'off',\n        '@typescript-eslint/no-base-to-string': 'off',\n        '@typescript-eslint/consistent-indexed-object-style': 'off',\n        '@typescript-eslint/prefer-nullish-coalescing': 'off',\n        '@typescript-eslint/consistent-type-definitions': 'off',\n        '@typescript-eslint/no-unused-vars': 'off',\n        '@typescript-eslint/no-explicit-any': 'off',\n        '@typescript-eslint/prefer-for-of': 'off',\n        '@typescript-eslint/non-nullable-type-assertion-style': 'off',\n        '@typescript-eslint/class-literal-property-style': 'off',\n        '@typescript-eslint/no-redundant-type-constituents': 'off',\n        '@typescript-eslint/prefer-string-starts-ends-with': 'off',\n        '@typescript-eslint/no-duplicate-type-constituents': 'off',\n        '@typescript-eslint/array-type': 'off',\n        '@typescript-eslint/prefer-function-type': 'off',\n      },\n    },\n  ]);\n"
  },
  {
    "path": "extension/.gitignore",
    "content": "node_modules\ndist\n"
  },
  {
    "path": "extension/CHANGELOG.md",
    "content": "# remotedev-redux-devtools-extension\n\n## 3.2.12\n\n### Patch Changes\n\n- Updated dependencies [3f90241]\n- Updated dependencies [d61d31a]\n- Updated dependencies [804e729]\n- Updated dependencies [12849a4]\n- Updated dependencies [804d6bd]\n- Updated dependencies [6481386]\n  - @redux-devtools/instrument@3.0.0\n  - @redux-devtools/ui@3.0.0\n  - @redux-devtools/slider-monitor@7.0.0\n  - @redux-devtools/core@5.0.0\n  - @redux-devtools/app@8.0.0\n  - @redux-devtools/serialize@1.0.0\n  - @redux-devtools/utils@4.0.0\n\n## 3.2.11\n\n### Patch Changes\n\n- Updated dependencies [6163276]\n  - @redux-devtools/app@7.0.0\n  - @redux-devtools/slider-monitor@6.0.0\n  - @redux-devtools/ui@2.0.0\n\n## 3.2.10\n\n### Patch Changes\n\n- @redux-devtools/app@6.2.2\n\n## 3.2.9\n\n### Patch Changes\n\n- Updated dependencies [91f21b2]\n  - @redux-devtools/core@4.1.1\n  - @redux-devtools/slider-monitor@5.1.1\n  - @redux-devtools/utils@3.1.1\n  - @redux-devtools/app@6.2.1\n\n## 3.2.8\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - react-json-tree@0.20.0\n  - @redux-devtools/app@6.2.0\n  - @redux-devtools/slider-monitor@6.0.0\n  - @redux-devtools/ui@1.4.0\n  - @redux-devtools/core@4.1.0\n  - @redux-devtools/utils@4.0.0\n\n## 3.2.7\n\n### Patch Changes\n\n- b25bf13: Send state from background when monitor connects\n\n## 3.2.6\n\n### Patch Changes\n\n- 50d7682: Fix DevTools from losing connection\n\n## 3.2.5\n\n### Patch Changes\n\n- eb3ac09: Add logging to background service worker\n\n## 3.2.4\n\n### Patch Changes\n\n- f1d6158: Fix mocking Chrome API for Electron\n\n## 3.2.3\n\n### Patch Changes\n\n- fd9f950: Fix monitoring on opening panel\n- e49708d: Fix manifest.json for Edge\n\n## 3.2.1\n\n### Patch Changes\n\n- abd03a7: Fix: only send data to extension if DevTools are open\n\n## 3.2.0\n\n### Minor Changes\n\n- 83b2c19: Upgrade to Manifest V3\n\n## 3.1.11\n\n### Patch Changes\n\n- 73688e1: Fix releasing Firefox extension\n\n## 3.1.10\n\n### Patch Changes\n\n- 2163bc3: Split large messages sent from background page to devpanel\n\n## 3.1.9\n\n### Patch Changes\n\n- Updated dependencies [bbb1a40]\n  - react-json-tree@0.19.0\n  - @redux-devtools/slider-monitor@5.0.1\n  - @redux-devtools/ui@1.3.2\n\n## 3.1.8\n\n### Patch Changes\n\n- 191d419: Convert d3 packages to ESM\n- Updated dependencies [191d419]\n  - @redux-devtools/app@6.0.1\n\n## 3.1.7\n\n### Patch Changes\n\n- Updated dependencies [5cfe3e5]\n- Updated dependencies [decc035]\n  - @redux-devtools/app@6.0.0\n  - @redux-devtools/slider-monitor@5.0.0\n  - @redux-devtools/core@4.0.0\n  - @redux-devtools/utils@3.0.0\n\n## 3.1.6\n\n### Patch Changes\n\n- Updated dependencies [158ba2c]\n  - @redux-devtools/app@5.0.0\n\n## 3.1.5\n\n### Patch Changes\n\n- 65205f90: Replace Action<unknown> with Action<string>\n- Updated dependencies [65205f90]\n  - @redux-devtools/app@4.0.1\n  - @redux-devtools/core@3.13.2\n\n## 3.1.4\n\n### Patch Changes\n\n- Updated dependencies [e57bcb39]\n  - @redux-devtools/app@4.0.0\n\n## 3.1.3\n\n### Patch Changes\n\n- bca76009: Fix missing CSS for code editor\n\n## 3.1.2\n\n### Patch Changes\n\n- 64ed81b0: Fix extension in Firefox and Chrome Incognito\n\n## 3.1.1\n\n### Patch Changes\n\n- d18525b5: Increase min-width of popup\n- Updated dependencies [57751ff9]\n  - @redux-devtools/app@3.0.0\n\n## 3.1.0\n\n### Minor Changes\n\n- d54adb76: Option to sort State Tree keys alphabetically\n  Option to disable collapsing of object keys\n\n### Patch Changes\n\n- @redux-devtools/app@2.2.2\n\n## 3.0.19\n\n### Patch Changes\n\n- 450cde6e: Fix responsive layout\n\n## 3.0.18\n\n### Patch Changes\n\n- Updated dependencies [81926f32]\n  - react-json-tree@0.18.0\n  - @redux-devtools/app@2.2.1\n\n## 3.0.17\n\n### Patch Changes\n\n- 1aa6c4f7: Fix remounting root for devpanel\n\n## 3.0.16\n\n### Patch Changes\n\n- 20ebf725: Remove source map from page wrap bundle\n\n## 3.0.14\n\n### Patch Changes\n\n- 24f60a7a: bump min popup window width to 760px #1126 #1129\n\n## 3.0.13\n\n### Patch Changes\n\n- Updated dependencies [8a7eae4]\n  - react-json-tree@0.17.0\n  - @redux-devtools/app@2.2.0\n  - @redux-devtools/slider-monitor@4.0.0\n  - @redux-devtools/ui@1.3.0\n  - @redux-devtools/core@3.13.0\n  - @redux-devtools/utils@2.0.0\n\n## 3.0.12\n\n### Patch Changes\n\n- Updated dependencies [4891bf6]\n  - @redux-devtools/core@3.12.0\n  - @redux-devtools/slider-monitor@3.1.2\n  - @redux-devtools/utils@1.2.1\n  - @redux-devtools/app@2.1.4\n\n## 3.0.11\n\n### Patch Changes\n\n- ab3c0e2: Avoid persisting the selected action index between sessions\n- Updated dependencies [ab3c0e2]\n- Updated dependencies [4c9a890]\n  - @redux-devtools/app@2.1.3\n  - react-json-tree@0.16.2\n\n## 3.0.10\n\n### Patch Changes\n\n- 55cc37e: Fix filter to show state-controlled search value\n- Updated dependencies [55cc37e]\n  - @redux-devtools/app@2.1.2\n"
  },
  {
    "path": "extension/CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n- Using welcoming and inclusive language\n- Being respectful of differing viewpoints and experiences\n- Gracefully accepting constructive criticism\n- Focusing on what is best for the community\n- Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n- The use of sexualized language or imagery and unwelcome sexual attention or\n  advances\n- Trolling, insulting/derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n- Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": "extension/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015-present Mihail Diordiev\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "extension/README.md",
    "content": "# Redux DevTools Extension\n\n[![Join the chat at https://gitter.im/zalmoxisus/redux-devtools-extension](https://badges.gitter.im/zalmoxisus/redux-devtools-extension.svg)](https://gitter.im/zalmoxisus/redux-devtools-extension?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=round-square)](http://makeapullrequest.com)\n[![OpenCollective](https://opencollective.com/redux-devtools-extension/backers/badge.svg)](#backers)\n[![OpenCollective](https://opencollective.com/redux-devtools-extension/sponsors/badge.svg)](#sponsors)\n\n![Demo](https://cloud.githubusercontent.com/assets/7957859/18002950/aacb82fc-6b93-11e6-9ae9-609862c18302.png)\n\n## Installation\n\n### 1. For Chrome\n\n- from [Chrome Web Store](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd);\n- or download `extension.zip` from [last releases](https://github.com/zalmoxisus/redux-devtools-extension/releases), unzip, open `chrome://extensions` url and turn on developer mode from top left and then click; on `Load Unpacked` and select the extracted folder for use\n- or build it with `npm i && npm run build:extension` and [load the extension's folder](https://developer.chrome.com/docs/extensions/get-started/tutorial/hello-world#load-unpacked) `./build/extension`;\n- or run it in dev mode with `npm i && npm start` and [load the extension's folder](https://developer.chrome.com/docs/extensions/get-started/tutorial/hello-world#load-unpacked) `./dev`.\n\n### 2. For Firefox\n\n- from [Mozilla Add-ons](https://addons.mozilla.org/en-US/firefox/addon/reduxdevtools/);\n- or build it with `npm i && npm run build:firefox` and [load the extension's folder](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Temporary_Installation_in_Firefox) `./build/firefox` (just select a file from inside the dir).\n\n### 3. For Electron\n\n- just specify `REDUX_DEVTOOLS` in [`electron-devtools-installer`](https://github.com/GPMDP/electron-devtools-installer).\n\n### 4. For other browsers and non-browser environment\n\n- use [`remote-redux-devtools`](https://github.com/zalmoxisus/remote-redux-devtools).\n\n## Usage\n\n> Note that starting from v2.7, `window.devToolsExtension` was renamed to `window.__REDUX_DEVTOOLS_EXTENSION__` / `window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__`.\n\n## 1. With Redux\n\n### 1.1 Basic store\n\nFor a basic [Redux store](https://redux.js.org/api/createstore#createstorereducer-preloadedstate-enhancer) simply add:\n\n```diff\n const store = createStore(\n   reducer, /* preloadedState, */\n+  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()\n );\n```\n\nNote that [`preloadedState`](https://redux.js.org/api/createstore#createstorereducer-preloadedstate-enhancer) argument is optional in Redux's [`createStore`](https://redux.js.org/api/createstore#createstorereducer-preloadedstate-enhancer).\n\n> For universal (\"isomorphic\") apps, prefix it with `typeof window !== 'undefined' &&`.\n\n```js\nconst composeEnhancers =\n  (typeof window !== 'undefined' &&\n    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) ||\n  compose;\n```\n\n> For TypeScript use [`redux-devtools-extension` npm package](#13-use-redux-devtoolsextension-package-from-npm), which contains all the definitions, or just use `(window as any)` (see [Recipes](docs/Recipes.md#using-in-a-typescript-project) for an example).\n\n```js\nconst composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;\n```\n\nIn case ESLint is configured to not allow using the underscore dangle, wrap it like so:\n\n```diff\n+ /* eslint-disable no-underscore-dangle */\n  const store = createStore(\n   reducer, /* preloadedState, */\n   window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()\n  );\n+ /* eslint-enable */\n```\n\n> **Note**: Passing enhancer as last argument requires **redux@>=3.1.0**. For older versions apply it like [here](https://github.com/zalmoxisus/redux-devtools-extension/blob/v0.4.2/examples/todomvc/store/configureStore.js) or [here](https://github.com/zalmoxisus/redux-devtools-extension/blob/v0.4.2/examples/counter/store/configureStore.js#L7-L12). Don't mix the old Redux API with the new one.\n\n> You don't need to npm install [`redux-devtools`](https://github.com/gaearon/redux-devtools) when using the extension (that's a different lib).\n\n### 1.2 Advanced store setup\n\nIf you setup your store with [middleware and enhancers](http://redux.js.org/docs/api/applyMiddleware.html), change:\n\n```diff\n  import { createStore, applyMiddleware, compose } from 'redux';\n\n+ const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;\n+ const store = createStore(reducer, /* preloadedState, */ composeEnhancers(\n- const store = createStore(reducer, /* preloadedState, */ compose(\n    applyMiddleware(...middleware)\n  ));\n```\n\n> Note that when the extension is not installed, we’re using Redux compose here.\n\nTo specify [extension’s options](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md), use it like so:\n\n```js\nconst composeEnhancers =\n  typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__\n    ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({\n        // Specify extension’s options like name, actionsDenylist, actionsCreators, serialize...\n      })\n    : compose;\n\nconst enhancer = composeEnhancers(\n  applyMiddleware(...middleware),\n  // other store enhancers if any\n);\nconst store = createStore(reducer, enhancer);\n```\n\n> [See the post for more details](https://medium.com/@zalmoxis/improve-your-development-workflow-with-redux-devtools-extension-f0379227ff83).\n\n### 1.3 Use `@redux-devtools/extension` package from npm\n\nTo make things easier, there's an npm package to install:\n\n```\nnpm install --save @redux-devtools/extension\n```\n\nand to use like so:\n\n```js\nimport { createStore, applyMiddleware } from 'redux';\nimport { composeWithDevTools } from '@redux-devtools/extension';\n\nconst store = createStore(\n  reducer,\n  composeWithDevTools(\n    applyMiddleware(...middleware),\n    // other store enhancers if any\n  ),\n);\n```\n\nTo specify [extension’s options](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md#windowdevtoolsextensionconfig):\n\n```js\nimport { createStore, applyMiddleware } from 'redux';\nimport { composeWithDevTools } from '@redux-devtools/extension';\n\nconst composeEnhancers = composeWithDevTools({\n  // Specify name here, actionsDenylist, actionsCreators and other options if needed\n});\nconst store = createStore(\n  reducer,\n  /* preloadedState, */ composeEnhancers(\n    applyMiddleware(...middleware),\n    // other store enhancers if any\n  ),\n);\n```\n\n> There are just a [few lines of code](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/npm-package/index.js) added to your bundle.\n\nIn case you don't include other enhancers and middlewares, just use `devToolsEnhancer`:\n\n```js\nimport { createStore } from 'redux';\nimport { devToolsEnhancer } from '@redux-devtools/extension';\n\nconst store = createStore(\n  reducer,\n  /* preloadedState, */ devToolsEnhancer(),\n  // Specify name here, actionsDenylist, actionsCreators and other options if needed\n);\n```\n\n### 1.4 Using in production\n\nIt's useful to include the extension in production as well. Usually you [can use it for development](https://medium.com/@zalmoxis/using-redux-devtools-in-production-4c5b56c5600f).\n\nIf you want to restrict it there, use `composeWithDevToolsLogOnlyInProduction` or `devToolsEnhancerLogOnlyInProduction`:\n\n```js\nimport { createStore } from 'redux';\nimport { devToolsEnhancerLogOnlyInProduction } from '@redux-devtools/extension';\n\nconst store = createStore(\n  reducer,\n  /* preloadedState, */ devToolsEnhancerLogOnlyInProduction(),\n  // options like actionSanitizer, stateSanitizer\n);\n```\n\nor with middlewares and enhancers:\n\n```js\nimport { createStore, applyMiddleware } from 'redux';\nimport { composeWithDevToolsLogOnlyInProduction } from '@redux-devtools/extension';\n\nconst composeEnhancers = composeWithDevToolsLogOnlyInProduction({\n  // options like actionSanitizer, stateSanitizer\n});\nconst store = createStore(\n  reducer,\n  /* preloadedState, */ composeEnhancers(\n    applyMiddleware(...middleware),\n    // other store enhancers if any\n  ),\n);\n```\n\n> You'll have to add `'process.env.NODE_ENV': JSON.stringify('production')` in your Webpack config for the production bundle ([to envify](https://github.com/gaearon/redux-devtools/blob/master/docs/Walkthrough.md#exclude-devtools-from-production-builds)). If you use `create-react-app`, [it already does it for you.](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/config/webpack.config.prod.js#L253-L257)\n\nIf you're already checking `process.env.NODE_ENV` when creating the store, import `composeWithDevToolsLogOnly` or `devToolsEnhancerLogOnly` for production environment.\n\nIf you don’t want to allow the extension in production, just use `composeWithDevToolsDevelopmentOnly` or `devToolsEnhancerDevelopmentOnly`.\n\n> See [the article](https://medium.com/@zalmoxis/using-redux-devtools-in-production-4c5b56c5600f) for more details.\n\n### 1.5 For React Native, hybrid, desktop and server side Redux apps\n\nFor React Native we can use [`react-native-debugger`](https://github.com/jhen0409/react-native-debugger), which already included [the same API](https://github.com/jhen0409/react-native-debugger/blob/master/docs/redux-devtools-integration.md) with Redux DevTools Extension.\n\nFor most platforms, include [`Remote Redux DevTools`](https://github.com/zalmoxisus/remote-redux-devtools)'s store enhancer, and from the extension's context menu choose 'Open Remote DevTools' for remote monitoring.\n\n## 2. Without Redux\n\nSee [integrations](docs/Integrations.md) and [the blog post](https://medium.com/@zalmoxis/redux-devtools-without-redux-or-how-to-have-a-predictable-state-with-any-architecture-61c5f5a7716f) for more details on how to use the extension with any architecture.\n\n## Docs\n\n- [Options (arguments)](docs/API/Arguments.md)\n- [Methods (advanced API)](docs/API/Methods.md)\n- [FAQ](docs/FAQ.md)\n- Features\n  - [Trace actions calls](docs/Features/Trace.md)\n- [Troubleshooting](docs/Troubleshooting.md)\n- [Articles](docs/Articles.md)\n- [Videos](docs/Videos.md)\n- [Feedback](docs/Feedback.md)\n\n## Demo\n\nLive demos to use the extension with:\n\n- [Counter](http://zalmoxisus.github.io/examples/counter/)\n- [TodoMVC](http://zalmoxisus.github.io/examples/todomvc/)\n- [Redux Form](http://redux-form.com/6.5.0/examples/simple/)\n- [React Tetris](https://chvin.github.io/react-tetris/?lan=en)\n- [Book Collection (Angular ngrx store)](https://ngrx.github.io/platform/example-app/)\n\nAlso see [`./examples` folder](https://github.com/zalmoxisus/redux-devtools-extension/tree/master/examples).\n\n## Backers\n\nSupport us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/redux-devtools-extension#backer)]\n\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/0/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/0/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/1/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/1/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/2/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/2/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/3/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/3/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/4/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/4/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/5/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/5/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/6/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/6/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/7/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/7/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/8/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/8/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/9/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/9/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/10/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/10/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/11/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/11/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/12/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/12/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/13/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/13/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/14/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/14/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/15/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/15/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/16/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/16/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/17/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/17/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/18/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/18/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/19/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/19/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/20/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/20/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/21/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/21/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/22/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/22/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/23/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/23/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/24/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/24/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/25/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/25/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/26/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/26/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/27/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/27/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/28/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/28/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/backer/29/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/backer/29/avatar.svg\"></a>\n\n## Sponsors\n\nBecome a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/redux-devtools-extension#sponsor)]\n\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/0/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/0/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/1/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/1/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/2/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/2/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/3/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/3/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/4/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/4/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/5/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/5/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/6/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/6/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/7/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/7/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/8/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/8/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/9/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/9/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/10/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/10/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/11/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/11/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/12/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/12/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/13/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/13/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/14/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/14/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/15/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/15/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/16/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/16/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/17/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/17/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/18/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/18/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/19/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/19/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/20/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/20/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/21/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/21/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/22/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/22/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/23/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/23/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/24/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/24/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/25/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/25/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/26/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/26/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/27/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/27/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/28/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/28/avatar.svg\"></a>\n<a href=\"https://opencollective.com/redux-devtools-extension/sponsor/29/website\" target=\"_blank\"><img src=\"https://opencollective.com/redux-devtools-extension/sponsor/29/avatar.svg\"></a>\n\n## License\n\nMIT\n\n## Created By\n\nIf you like this, follow [@mdiordiev](https://twitter.com/mdiordiev) on twitter.\n"
  },
  {
    "path": "extension/babel.config.json",
    "content": "{\n  \"presets\": [\n    [\"@babel/preset-env\", { \"targets\": \"defaults\" }],\n    \"@babel/preset-react\",\n    \"@babel/preset-typescript\"\n  ]\n}\n"
  },
  {
    "path": "extension/build.mjs",
    "content": "import * as fs from 'node:fs';\nimport * as esbuild from 'esbuild';\nimport pug from 'pug';\n\nconst args = process.argv.slice(2);\nconst prod = !args.includes('--dev');\n\nawait esbuild.build({\n  bundle: true,\n  logLevel: 'info',\n  outdir: 'dist',\n  minify: prod,\n  sourcemap: !prod,\n  define: {\n    'process.env.NODE_ENV': prod ? '\"production\"' : '\"development\"',\n    'process.env.BABEL_ENV': prod ? '\"production\"' : '\"development\"',\n  },\n  entryPoints: [\n    { out: 'background.bundle', in: 'src/background/index.ts' },\n    { out: 'options.bundle', in: 'src/options/index.tsx' },\n    { out: 'remote.bundle', in: 'src/remote/index.tsx' },\n    { out: 'devpanel.bundle', in: 'src/devpanel/index.tsx' },\n    { out: 'devtools.bundle', in: 'src/devtools/index.ts' },\n    { out: 'content.bundle', in: 'src/contentScript/index.ts' },\n    { out: 'page.bundle', in: 'src/pageScript/index.ts' },\n  ],\n  loader: {\n    '.woff2': 'file',\n  },\n});\n\nconsole.log();\n\nconsole.log('Creating HTML files...');\nconst htmlFiles = ['devpanel', 'devtools', 'options', 'remote'];\nfor (const htmlFile of htmlFiles) {\n  fs.writeFileSync(\n    `dist/${htmlFile}.html`,\n    pug.renderFile(`src/${htmlFile}/${htmlFile}.pug`),\n  );\n}\n\nconsole.log('Copying manifest.json...');\nfs.copyFileSync('chrome/manifest.json', 'dist/manifest.json');\n\nconsole.log('Copying assets...');\nfs.cpSync('src/assets', 'dist', { recursive: true });\n\nconsole.log('Copying dist for each browser...');\nfs.cpSync('dist', 'chrome/dist', { recursive: true });\nfs.copyFileSync('chrome/manifest.json', 'chrome/dist/manifest.json');\nfs.cpSync('dist', 'edge/dist', { recursive: true });\nfs.copyFileSync('edge/manifest.json', 'edge/dist/manifest.json');\nfs.cpSync('dist', 'firefox/dist', { recursive: true });\nfs.copyFileSync('firefox/manifest.json', 'firefox/dist/manifest.json');\n"
  },
  {
    "path": "extension/chrome/manifest.json",
    "content": "{\n  \"version\": \"3.2.10\",\n  \"name\": \"Redux DevTools\",\n  \"description\": \"Redux DevTools for debugging application's state changes.\",\n  \"homepage_url\": \"https://github.com/reduxjs/redux-devtools\",\n  \"manifest_version\": 3,\n  \"action\": {\n    \"default_icon\": \"img/logo/gray.png\",\n    \"default_title\": \"Redux DevTools\",\n    \"default_popup\": \"devpanel.html#popup\"\n  },\n  \"commands\": {\n    \"devtools-window\": {\n      \"description\": \"DevTools window\"\n    },\n    \"devtools-remote\": {\n      \"description\": \"Remote DevTools\"\n    },\n    \"_execute_action\": {\n      \"suggested_key\": {\n        \"default\": \"Ctrl+Shift+E\"\n      }\n    }\n  },\n  \"icons\": {\n    \"16\": \"img/logo/16x16.png\",\n    \"48\": \"img/logo/48x48.png\",\n    \"128\": \"img/logo/128x128.png\"\n  },\n  \"options_ui\": {\n    \"page\": \"options.html\"\n  },\n  \"background\": {\n    \"service_worker\": \"background.bundle.js\"\n  },\n  \"content_scripts\": [\n    {\n      \"matches\": [\"<all_urls>\"],\n      \"exclude_globs\": [\"https://www.google*\"],\n      \"js\": [\"content.bundle.js\"],\n      \"run_at\": \"document_start\",\n      \"all_frames\": true\n    },\n    {\n      \"matches\": [\"<all_urls>\"],\n      \"exclude_globs\": [\"https://www.google*\"],\n      \"js\": [\"page.bundle.js\"],\n      \"run_at\": \"document_start\",\n      \"all_frames\": true,\n      \"world\": \"MAIN\"\n    }\n  ],\n  \"devtools_page\": \"devtools.html\",\n  \"externally_connectable\": {\n    \"ids\": [\"*\"]\n  },\n  \"permissions\": [\"notifications\", \"contextMenus\", \"storage\"],\n  \"host_permissions\": [\"file:///*\", \"http://*/*\", \"https://*/*\"],\n  \"content_security_policy\": {\n    \"extension_pages\": \"script-src 'self'; object-src 'self'; style-src * 'unsafe-inline'; img-src 'self' data:;\"\n  },\n  \"update_url\": \"https://clients2.google.com/service/update2/crx\",\n  \"key\": \"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsdJEPwY92xUACA9CcDBDBmbdbp8Ap3cKQ0DJTUuVQvqb4FQAv8RtKY3iUjGvdwuAcSJQIZwHXcP2aNDH3TiFik/NhRK2GRW8X3OZyTdkuDueABGP2KEX8q1WQDgjX/rPIinGYztUrvoICw/UerMPwNW62jwGoVU3YhAGf+15CgX2Y6a4tppnf/+1mPedKPidh0RsM+aJY98rX+r1SPAHPcGzMjocLkqcT75DZBXer8VQN14tOOzRCd6T6oy7qm7eWru8lJwcY66qMQvhk0osqEod2G3nA7aTWpmqPFS66VEiecP9PgZlp8gQdgZ3dFhA62exydlD55JuRhiMIR63yQIDAQAB\"\n}\n"
  },
  {
    "path": "extension/docs/API/Arguments.md",
    "content": "# Options\n\nUse with\n\n- `window.__REDUX_DEVTOOLS_EXTENSION__([options])`\n- `window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__([options])()`\n- `window.__REDUX_DEVTOOLS_EXTENSION__.connect([options])`\n- `@redux-devtools/extension` npm package:\n\n```js\nimport { composeWithDevTools } from '@redux-devtools/extension';\n\nconst composeEnhancers = composeWithDevTools(options);\nconst store = createStore(\n  reducer,\n  /* preloadedState, */ composeEnhancers(\n    applyMiddleware(...middleware),\n    // other store enhancers if any\n  ),\n);\n```\n\nThe `options` object is optional, and can include any of the following.\n\n### `name`\n\n_string_ - the instance name to be shown on the monitor page. Default value is `document.title`. If not specified and there's no document title, it will consist of `tabId` and `instanceId`.\n\n### `actionCreators`\n\n_array_ or _object_ - action creators functions to be available in the Dispatcher. See [the example](https://github.com/zalmoxisus/redux-devtools-extension/commit/477e69d8649dfcdc9bf84dd45605dab7d9775c03).\n\n### `latency`\n\n_number (in ms)_ - if more than one action is dispatched in the indicated interval, all new actions will be collected and sent at once. It is the joint between performance and speed. When set to `0`, all actions will be sent instantly. Set it to a higher value when experiencing perf issues (also `maxAge` to a lower value). Default is `500 ms`.\n\n### `maxAge`\n\n_number_ (>1) - maximum allowed actions to be stored in the history tree. The oldest actions are removed once maxAge is reached. It's critical for performance. Default is `50`.\n\n### `trace`\n\n_boolean_ or _function_ - if set to `true`, will include stack trace for every dispatched action, so you can see it in trace tab jumping directly to that part of code ([more details](../Features/Trace.md)). You can use a function (with action object as argument) which should return `new Error().stack` string, getting the stack outside of reducers. Default to `false`.\n\n### `traceLimit`\n\n_number_ - maximum stack trace frames to be stored (in case `trace` option was provided as `true`). By default it's `10`. Note that, because extension's calls are excluded, the resulted frames could be 1 less. If `trace` option is a function, `traceLimit` will have no effect, as it's supposed to be handled there.\n\n### `serialize`\n\n_boolean_ or _object_ which contains:\n\n- **options** `object or boolean`:\n  - `undefined` - will use regular `JSON.stringify` to send data (it's the fast mode).\n  - `false` - will handle also circular references.\n  - `true` - will handle also date, regex, undefined, primitives, error objects, symbols, maps, sets and functions.\n  - object, which contains `date`, `regex`, `undefined`, `nan`, `infinity`, `error`, `symbol`, `map`, `set` and `function` keys. For each of them you can indicate if to include (by setting as `true`). For `function` key you can also specify a custom function which handles serialization. See [`jsan`](https://github.com/kolodny/jsan) for more details. Example:\n\n    ```js\n    const store = Redux.createStore(\n      reducer,\n      window.__REDUX_DEVTOOLS_EXTENSION__ &&\n        window.__REDUX_DEVTOOLS_EXTENSION__({\n          serialize: {\n            options: {\n              undefined: true,\n              function: function (fn) {\n                return fn.toString();\n              },\n            },\n          },\n        }),\n    );\n    ```\n\n- **replacer** `function(key, value)` - [JSON `replacer` function](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The_replacer_parameter) used for both actions and states stringify.\n\n  Example of usage with [mori data structures](https://github.com/swannodette/mori):\n\n  ```js\n  const store = Redux.createStore(\n    reducer,\n    window.__REDUX_DEVTOOLS_EXTENSION__ &&\n      window.__REDUX_DEVTOOLS_EXTENSION__({\n        serialize: {\n          replacer: (key, value) =>\n            value && mori.isMap(value) ? mori.toJs(value) : value,\n        },\n      }),\n  );\n  ```\n\n  In addition, you can specify a data type by adding a [`__serializedType__`](https://github.com/zalmoxisus/remotedev-serialize/blob/master/helpers/index.js#L4) key. So you can deserialize it back while importing or persisting data. Moreover, it will also [show a nice preview showing the provided custom type](https://cloud.githubusercontent.com/assets/7957859/21814330/a17d556a-d761-11e6-85ef-159dd12f36c5.png):\n\n  ```js\n  const store = Redux.createStore(\n    reducer,\n    window.__REDUX_DEVTOOLS_EXTENSION__ &&\n      window.__REDUX_DEVTOOLS_EXTENSION__({\n        serialize: {\n          replacer: (key, value) => {\n            if (Immutable.List.isList(value)) {\n              // use your custom data type checker\n              return {\n                data: value.toArray(), // ImmutableJS custom method to get JS data as array\n                __serializedType__: 'ImmutableList', // mark you custom data type to show and retrieve back\n              };\n            }\n          },\n        },\n      }),\n  );\n  ```\n\n- **reviver** `function(key, value)` - [JSON `reviver` function](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Using_the_reviver_parameter) used for parsing the imported actions and states. See [`remotedev-serialize`](https://github.com/zalmoxisus/remotedev-serialize/blob/master/immutable/serialize.js#L8-L41) as an example on how to serialize special data types and get them back:\n\n  ```js\n  const store = Redux.createStore(\n    reducer,\n    window.__REDUX_DEVTOOLS_EXTENSION__ &&\n      window.__REDUX_DEVTOOLS_EXTENSION__({\n        serialize: {\n          reviver: (key, value) => {\n            if (\n              typeof value === 'object' &&\n              value !== null &&\n              '__serializedType__' in value\n            ) {\n              switch (value.__serializedType__) {\n                case 'ImmutableList':\n                  return Immutable.List(value.data);\n              }\n            }\n          },\n        },\n      }),\n  );\n  ```\n\n- **immutable** `object` - automatically serialize/deserialize immutablejs via [remotedev-serialize](https://github.com/zalmoxisus/remotedev-serialize). Just pass the Immutable library like so:\n\n  ```js\n  import Immutable from 'immutable'; // https://facebook.github.io/immutable-js/\n  // ...\n  // Like above, only showing off compose this time. Reminder you might not want this in prod.\n  const composeEnhancers =\n    typeof window === 'object' &&\n    typeof window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ !== 'undefined'\n      ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({\n          serialize: {\n            immutable: Immutable,\n          },\n        })\n      : compose;\n  ```\n\n  It will support all ImmutableJS structures. You can even export them into a file and get them back. The only exception is `Record` class, for which you should pass in addition the references to your classes in `refs`.\n\n- **refs** `array` - ImmutableJS `Record` classes used to make possible restore its instances back when importing, persisting... Example of usage:\n\n  ```js\n  import Immutable from 'immutable';\n  // ...\n\n  const ABRecord = Immutable.Record({ a: 1, b: 2 });\n  const myRecord = new ABRecord({ b: 3 }); // used in the reducers\n\n  const store = createStore(\n    rootReducer,\n    window.__REDUX_DEVTOOLS_EXTENSION__ &&\n      window.__REDUX_DEVTOOLS_EXTENSION__({\n        serialize: {\n          immutable: Immutable,\n          refs: [ABRecord],\n        },\n      }),\n  );\n  ```\n\nAlso you can specify alternative values right in the state object (in the initial state of the reducer) by adding `toJSON` function:\n\nIn the example bellow it will always send `{ component: '[React]' }`, regardless of the state's `component` value (useful when you don't want to send lots of unnecessary data):\n\n```js\nfunction component(\n  state = { component: null, toJSON: () => ({ component: '[React]' }) },\n  action,\n) {\n  switch (action.type) {\n    case 'ADD_COMPONENT':\n      return { component: action.component };\n    default:\n      return state;\n  }\n}\n```\n\nYou could also alter the value. For example when state is `{ count: 1 }`, we'll send `{ counter: 10 }` (notice we don't have an arrow function this time to use the object's `this`):\n\n```js\nfunction counter(\n  state = {\n    count: 0,\n    toJSON: function () {\n      return { conter: this.count * 10 };\n    },\n  },\n  action,\n) {\n  switch (action.type) {\n    case 'INCREMENT':\n      return { count: state.count + 1 };\n    default:\n      return state;\n  }\n}\n```\n\n### `actionSanitizer` / `stateSanitizer`\n\n- **actionSanitizer** (_function_) - function which takes `action` object and id number as arguments, and should return `action` object back. See the example bellow.\n- **stateSanitizer** (_function_) - function which takes `state` object and index as arguments, and should return `state` object back.\n\nExample of usage:\n\n```js\nconst actionSanitizer = (action) =>\n  action.type === 'FILE_DOWNLOAD_SUCCESS' && action.data\n    ? { ...action, data: '<<LONG_BLOB>>' }\n    : action;\nconst store = createStore(\n  rootReducer,\n  window.__REDUX_DEVTOOLS_EXTENSION__ &&\n    window.__REDUX_DEVTOOLS_EXTENSION__({\n      actionSanitizer,\n      stateSanitizer: (state) =>\n        state.data ? { ...state, data: '<<LONG_BLOB>>' } : state,\n    }),\n);\n```\n\n### `actionsDenylist` / `actionsAllowlist`\n\n_string or array of strings as regex_ - actions types to be hidden / shown in the monitors (while passed to the reducers). If `actionsAllowlist` specified, `actionsDenylist` is ignored.\n\nExample:\n\n```js\ncreateStore(\n  reducer,\n  remotedev({\n    sendTo: 'http://localhost:8000',\n    actionsDenylist: 'SOME_ACTION',\n    // or actionsDenylist: ['SOME_ACTION', 'SOME_OTHER_ACTION']\n    // or just actionsDenylist: 'SOME_' to omit both\n  }),\n);\n```\n\n### `predicate`\n\n_function_ - called for every action before sending, takes `state` and `action` object, and returns `true` in case it allows sending the current data to the monitor. Use it as a more advanced version of `actionsDenylist`/`actionsAllowlist` parameters.\nExample of usage:\n\n```js\nconst store = createStore(\n  rootReducer,\n  window.__REDUX_DEVTOOLS_EXTENSION__ &&\n    window.__REDUX_DEVTOOLS_EXTENSION__({\n      predicate: (state, action) =>\n        state.dev.logLevel === VERBOSE && !action.forwarded,\n    }),\n);\n```\n\n### `shouldRecordChanges`\n\n_boolean_ - if specified as `false`, it will not record the changes till clicking on `Start recording` button. Default is `true`. Available only for Redux enhancer, for others use `autoPause`.\n\n### `pauseActionType`\n\n_string_ - if specified, whenever clicking on `Pause recording` button and there are actions in the history log, will add this action type. If not specified, will commit when paused. Available only for Redux enhancer. Default is `@@PAUSED`.\n\n### `autoPause`\n\n_boolean_ - auto pauses when the extension’s window is not opened, and so has zero impact on your app when not in use. Not available for Redux enhancer (as it already does it but storing the data to be sent). Default is `false`.\n\n### `shouldStartLocked`\n\n_boolean_ - if specified as `true`, it will not allow any non-monitor actions to be dispatched till clicking on `Unlock changes` button. Available only for Redux enhancer. Default is `false`.\n\n### `shouldHotReload`\n\n_boolean_ - if set to `false`, will not recompute the states on hot reloading (or on replacing the reducers). Available only for Redux enhancer. Default to `true`.\n\n### `shouldCatchErrors`\n\n_boolean_ - if specified as `true`, whenever there's an exception in reducers, the monitors will show the error message, and next actions will not be dispatched.\n\n### `features`\n\nIf you want to restrict the extension, just specify the features you allow:\n\n```js\nconst composeEnhancers = composeWithDevTools({\n  features: {\n    pause: true, // start/pause recording of dispatched actions\n    lock: true, // lock/unlock dispatching actions and side effects\n    persist: true, // persist states on page reloading\n    export: true, // export history of actions in a file\n    import: 'custom', // import history of actions from a file\n    jump: true, // jump back and forth (time travelling)\n    skip: true, // skip (cancel) actions\n    reorder: true, // drag and drop actions in the history list\n    dispatch: true, // dispatch custom actions or action creators\n    test: true, // generate tests for the selected actions\n  },\n  // other options like actionSanitizer, stateSanitizer\n});\n```\n\nIf not specified, all of the features are enabled. When set as an object, only those included as `true` will be allowed.\nNote that except `true`/`false`, `import` and `export` can be set as `custom` (which is by default for Redux enhancer), meaning that the importing/exporting occurs on the client side. Otherwise, you'll get/set the data right from the monitor part.\n"
  },
  {
    "path": "extension/docs/API/Methods.md",
    "content": "## Communicate with the extension directly\n\n> Note this is advanced API, which you usually don't need to use with Redux enhancer.\n\nUse the following methods of `window.__REDUX_DEVTOOLS_EXTENSION__`:\n\n- [connect](#connect)\n- [disconnect](#disconnect)\n- [send](#send)\n- [listen](#listen)\n- [open](#open)\n- [notifyErrors](#notifyerrors)\n\n<a id=\"connect\"></a>\n\n### connect([options])\n\n##### Arguments\n\n- [`options`] _Object_ - [see the available options](Arguments.md).\n\n##### Returns\n\n_Object_ containing the following methods:\n\n- `subscribe(listener)` - adds a change listener. It will be called any time an action is dispatched from the monitor. Returns a function to unsubscribe the current listener.\n- `unsubscribe()` - unsubscribes all listeners.\n- `send(action, state)` - sends a new action and state manually to be shown on the monitor. If action is `null` then we suppose we send `liftedState`.\n- `init(state)` - sends the initial state to the monitor.\n- `error(message)` - sends the error message to be shown in the extension's monitor.\n\nExample of usage:\n\n```js\nconst devTools = window.__REDUX_DEVTOOLS_EXTENSION__.connect(config);\ndevTools.subscribe((message) => {\n  if (message.type === 'DISPATCH' && message.state) {\n    console.log('DevTools requested to change the state to', message.state);\n  }\n});\ndevTools.init({ value: 'initial state' });\ndevTools.send('change state', { value: 'state changed' });\n```\n\nSee [redux enhancer's example](https://github.com/reduxjs/redux-devtools/blob/main/packages/redux-devtools-extension/src/logOnly.ts), [react example](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/examples/react-counter-messaging/components/Counter.js) and [blog post](https://medium.com/@zalmoxis/redux-devtools-without-redux-or-how-to-have-a-predictable-state-with-any-architecture-61c5f5a7716f) for more details.\n\n### disconnect()\n\nRemove extensions listener and disconnect extensions background script connection. Usually just unsubscribing the listener inside the `connect` is enough.\n\n<a id=\"send\"></a>\n\n### send(action, state, [options, instanceId])\n\nSend a new action and state manually to be shown on the monitor. It's recommended to use [`connect`](connect), unless you want to hook into an already created instance.\n\n##### Arguments\n\n- `action` _String_ (action type) or _Object_ with required `type` key.\n- `state` _any_ - usually object to expand.\n- [`options`] _Object_ - [see the available options](Arguments.md).\n- [`instanceId`] _String_ - instance id for which to include the log. If not specified and not present in the `options` object, will be the first available instance.\n\n<a id=\"listen\"></a>\n\n### listen(onMessage, instanceId)\n\nListen for messages dispatched for specific `instanceId`. For most cases it's better to use `subcribe` inside the [`connect`](connect).\n\n##### Arguments\n\n- `onMessage` _Function_ to call when there's an action from the monitor.\n- `instanceId` _String_ - instance id for which to handle actions.\n\n<a id=\"open\"></a>\n\n### open([position])\n\nOpen the extension's window. This should be conditional (usually you don't need to open extension's window automatically).\n\n##### Arguments\n\n- [`position`] _String_ - window position: `left`, `right`, `bottom`. Also can be `panel` to [open it in a Chrome panel](../FAQ.md#how-to-keep-devtools-window-focused-all-the-time-in-a-chrome-panel). Or `remote` to [open remote monitor](../FAQ.md#how-to-get-it-work-with-webworkers-react-native-hybrid-desktop-and-server-side-apps). By default is `left`.\n\n<a id=\"notifyErrors\"></a>\n\n### notifyErrors([onError])\n\nWhen called, the extension will listen for uncaught exceptions on the page, and, if any, will show native notifications. Optionally, you can provide a function to be called when an exception occurs.\n\n##### Arguments\n\n- [`onError`] _Function_ to call when there's an exceptions.\n"
  },
  {
    "path": "extension/docs/API/README.md",
    "content": "# API Reference\n\n- [Parameters](Arguments.md)\n- [Methods](Methods.md)\n"
  },
  {
    "path": "extension/docs/Architecture.md",
    "content": "# Architecture Notes\n\nThis document exists to keep track of how the different parts of the Redux DevTools interact, since it's easy to forget how it all works together. This is intended for internal purposes and is just a collection of notes to myself.\n\n## Entry Points\n\n### Window\n\nThis is the default view that is shown in the Redux DevTools popup, the Chrome DevTools tab (if direct access to the background page is available), and new popup windows that are created. It has direct access to the background page via `chrome.runtime.getBackgroundPage`.\n\n### DevPanel\n\nThis is the view that is shown in the Chrome DevTools tab if direct access to the background page is not available.\n\nInitially this was the view that was always used for the Chrome DevTools tab, but when support to directly access the background page from the DevTools tab was added, [the Window View became the preferred view](https://github.com/zalmoxisus/redux-devtools-extension/pull/580).\n\n### Remote\n\nThis does not interact with the other parts of the extension at all, it just renders the `App` component from `@redux-devtools/app`.\n\nIt can be triggered by hitting the \"Remote\" button in any of the other views, which calls `chrome.windows.create` and creates a new window.\n\n### DevTools\n\nThis is the script that adds the Redux panel in the Chrome DevTools using `chrome.devtools.panels.create`.\n\nIt creates a Window View if it has direct access to the background page, otherwise it creates a DevPanel View.\n\nNote that this used to always show the DevPanel View, but [started using the Window View by default](https://github.com/zalmoxisus/redux-devtools-extension/pull/580) once direct access to the background page was added to Chrome DevTools tabs.\n\n### Content Script\n\nPasses messages between the injected page script and the background page.\n\nIt listens for messages from the injected page script using `window.addEventListener('message', ...)`. It knows the message is from the injected page script if `message.source` is `'@devtools-page'`. See the Chrome DevTools docs where this approach [is documented](https://developer.chrome.com/docs/extensions/how-to/devtools/extend-devtools#evaluated-scripts-to-devtools).\n\nIt creates a connection to the background page using `chrome.runtime.connect` with the name `'tab'` when it receives the first message from the injected page script.\n"
  },
  {
    "path": "extension/docs/Articles.md",
    "content": "# Articles\n\n- [Improve your development workflow with Redux DevTools Extension](https://medium.com/@zalmoxis/improve-your-development-workflow-with-redux-devtools-extension-f0379227ff83)\n- [Using Redux DevTools in production](https://medium.com/@zalmoxis/using-redux-devtools-in-production-4c5b56c5600f)\n- [Redux DevTools without Redux](https://medium.com/@zalmoxis/redux-devtools-without-redux-or-how-to-have-a-predictable-state-with-any-architecture-61c5f5a7716f)\n"
  },
  {
    "path": "extension/docs/Credits.md",
    "content": "# Credits\n\n- Built using [Crossbuilder](https://github.com/zalmoxisus/crossbuilder) boilerplate.\n- Includes [Dan Abramov](https://github.com/gaearon)'s [redux-devtools](https://github.com/gaearon/redux-devtools) and the following monitors:\n  - [Log Monitor](https://github.com/gaearon/redux-devtools-log-monitor)\n  - [Inspector](https://github.com/alexkuz/redux-devtools-inspector)\n  - [Dispatch](https://github.com/YoruNoHikage/redux-devtools-dispatch)\n  - [Slider](https://github.com/calesce/redux-slider-monitor)\n  - [Chart](https://github.com/romseguy/redux-devtools-chart-monitor)\n- [The logo icon](https://github.com/reactjs/redux/issues/151) made by [Keith Yong](https://github.com/keithyong) .\n- Examples from [Redux](https://github.com/rackt/redux/tree/master/examples).\n"
  },
  {
    "path": "extension/docs/FAQ.md",
    "content": "# Redux DevTools Extension FAQ\n\n## Table of Contents\n\n- [How to get it work](#how-to-get-it-work)\n- [How to disable/enable it in production](#how-to-disable-it-in-production)\n- [How to persist debug sessions across page reloads](#how-to-persist-debug-sessions-across-page-reloads)\n- [How to open DevTools programmatically](#how-to-open-devtools-programmatically)\n- [How to enable/disable errors notifying](#how-to-enabledisable-errors-notifying)\n- [How to get it work with WebWorkers, React Native, hybrid, desktop and server side apps](#how-to-get-it-work-with-webworkers-react-native-hybrid-desktop-and-server-side-apps)\n- [Keyboard shortcuts](#keyboard-shortcuts)\n\n#### How to get it work\n\n- Check the extension with [Counter](http://zalmoxisus.github.io/examples/counter/) or [TodoMVC](http://zalmoxisus.github.io/examples/todomvc/) demo.\n- Reload the extension on the extensions page (`chrome://extensions/`).\n- If something goes wrong, [open an issue](https://github.com/zalmoxisus/redux-devtools-extension/issues) or tweet me: [@mdiordiev](https://twitter.com/mdiordiev).\n\n#### How to disable it in production\n\nUsually you don't have to. See [the article for details on how to include it in production](https://medium.com/@zalmoxis/using-redux-devtools-in-production-4c5b56c5600f).\n\n#### How to persist debug sessions across page reloads\n\nJust click the `Persist` button or add `?debug_session=<session_name>` to the url.\n\n#### How to open DevTools programmatically\n\n```js\nwindow.__REDUX_DEVTOOLS_EXTENSION__.open();\n```\n\nMake sure to have it conditionally. Auto opening windows is a bad DX. See the [API](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Methods.md#open) for details.\n\n#### How to enable/disable errors notifying\n\nJust find `Redux DevTools` on the extensions page (`chrome://extensions/`) and click the `Options` link to customize everything. The errors notifying is disabled by default. If enabled, it works only when the store enhancer is called (in order not to show notifications for any sites you visit). In case you want notifications for a non-redux app, init it explicitly by calling `window.__REDUX_DEVTOOLS_EXTENSION__.notifyErrors()` (probably you'll check if `window.__REDUX_DEVTOOLS_EXTENSION__` exists before calling it).\n\n#### How to get it work with WebWorkers, React Native, hybrid, desktop and server side apps\n\nIt is not possible to inject extension's script there and to communicate directly. To solve this, use [Remote Redux DevTools](https://github.com/zalmoxisus/remote-redux-devtools). After including it inside the app, click `Remote` button for remote monitoring.\n\n#### Keyboard shortcuts\n\nTo set/change the keyboard shortcuts, click \"Keyboard shortcuts\" button on the bottom of the extensions page (`chrome://extensions/`). By default only `Cmd` (`Ctrl`) + `Shift` + `E` is available, which will open the extension popup (only when the Redux store is available in the current page).\n"
  },
  {
    "path": "extension/docs/Features/Trace.md",
    "content": "## Trace actions calls\n\n![trace-demo](https://user-images.githubusercontent.com/7957859/50161148-a1639300-02e3-11e9-80e7-18d3215a0bf8.gif)\n\nOne of the features of Redux DevTools is to select an action in the history and see the callstack that triggered it. It aims to solve the problem of finding the source of events in the event list.\n\nBy default it's disabled as, depending of the use case, generating and serializing stack traces for every action can impact the performance. To enable it, set `trace` option to `true` as in [examples](https://github.com/zalmoxisus/redux-devtools-extension/commit/64717bb9b3534ff616d9db56c2be680627c7b09d). See [the API](../API/Arguments.md#trace) for more details.\n\nFor some edge cases where stack trace cannot be obtained with just `Error().stack`, you can pass a function as `trace` with your implementation. It's useful for cases where the stack is broken, like, for example, [when calling `setTimeout`](https://github.com/zalmoxisus/redux-devtools-instrument/blob/e7c05c98e7e9654cb7db92a2f56c6b5f3ff2452b/test/instrument.spec.js#L735-L737). It takes `action` object as argument and should return `stack` string. This way it can be also used to provide stack conditionally only for certain actions.\n\nThere's also an optional `traceLimit` parameter, which is `10` by default, to prevent consuming too much memory and serializing large stacks and also allows you to get larger stacks than limited by the browser (it will overpass default limit of `10` imposed by Chrome in `Error.stackTraceLimit`). If `trace` option is a function, `traceLimit` will have no effect, that should be handled there like so: `trace: () => new Error().stack.split('\\n').slice(0, limit+1).join('\\n')` (`+1` is needed for Chrome where's an extra 1st frame for `Error\\n`).\n\nApart from opening resources in Chrome DevTools, as seen in the demo above, it can open the file (and jump to the line-column) right in your editor. Pretty useful for debugging, and also as an alternative when it's not possible to use openResource (for Firefox or when using the extension from window or for remote debugging). You can click Settings button and enable that, also adding the path to your project root directory to use. It works out of the box for VSCode, Atom, Webstorm/Phpstorm/IntelliJ, Sublime, Emacs, MacVim, Textmate on Mac and Windows. For Linux you can use [`atom-url-handler`](https://github.com/eclemens/atom-url-handler).\n"
  },
  {
    "path": "extension/docs/Feedback.md",
    "content": "# Feedback wanted\n\n[File an issue](https://github.com/zalmoxisus/redux-devtools-extension/issues) or [submit a PR](https://github.com/zalmoxisus/redux-devtools-extension/pulls) if you have suggestions, rate us and leave a review on [Chrome Store](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd/reviews), post feature requests and bug reports on [Product Pains](https://productpains.com/product/redux-devtools-extension), or ping me on Twitter as [@mdiordiev](https://twitter.com/mdiordiev).\n\n<iframe width=\"100%\" height=\"400px\" scrolling=\"no\" style=\"border:0\" src=\"https://productpains.com/widget.html?token=fc7887ce-f3f9-105a-e5cb-43b9eeb668d5\"></iframe><script type=\"text/javascript\" src=\"https://productpains.com/js/lib/iframeResizer.min.js\"></script>\n"
  },
  {
    "path": "extension/docs/Integrations.md",
    "content": "# Integrations for js and non-js frameworks\n\nMostly functional:\n\n- [React](#react)\n- [Angular](#angular)\n- [Cycle](#cycle)\n- [Ember](#ember)\n- [Fable](#fable)\n- [Freezer](#freezer)\n- [Mobx](#mobx)\n- [PureScript](#purescript)\n- [Reductive](#reductive)\n- [Aurelia](#aurelia)\n\nIn progress:\n\n- [ClojureScript](#clojurescript)\n- [Horizon](#horizon)\n- [Python](#python)\n- [Swift](#swift)\n\n### [React](https://github.com/facebook/react)\n\n#### Inspect React props\n\n##### [`react-inspect-props`](https://github.com/lucasconstantino/react-inspect-props)\n\n```js\nimport { compose, withState } from 'recompose';\nimport { inspectProps } from 'react-inspect-props';\n\ncompose(\n  withState('count', 'setCount', 0),\n  inspectProps('Counter inspector'),\n)(Counter);\n```\n\n#### Inspect React states\n\n##### [`remotedev-react-state`](https://github.com/jhen0409/remotedev-react-state)\n\n```js\nimport connectToDevTools from 'remotedev-react-state'\n\ncomponentWillMount() {\n    // Connect to devtools after setup initial state\n    connectToDevTools(this/*, options */)\n  }\n```\n\n#### Inspect React hooks (useState and useReducer)\n\n##### [`reinspect`](https://github.com/troch/reinspect)\n\n```js\nimport { useState } from 'reinspect';\n\nexport function CounterWithUseState({ id }) {\n  const [count, setCount] = useState(0, id);\n  // ...\n}\n```\n\n### [Mobx](https://github.com/mobxjs/mobx)\n\n#### [`mobx-remotedev`](https://github.com/zalmoxisus/mobx-remotedev)\n\n```js\nimport remotedev from 'mobx-remotedev';\n// or import remotedev from 'mobx-remotedev/lib/dev'\n// in case you want to use it in production or don't have process.env.NODE_ENV === 'development'\n\nconst appStore = observable({\n  // ...\n});\n\n// Or\nclass appStore {\n  // ...\n}\n\nexport default remotedev(appStore);\n```\n\n### [Angular](https://github.com/angular/angular)\n\n#### [ng2-redux](https://github.com/angular-redux/ng2-redux)\n\n```js\nimport { NgReduxModule, NgRedux, DevToolsExtension } from 'ng2-redux';\n\n@NgModule({\n  /* ... */\n  imports: [ /* ... */, NgReduxModule ]\n})export class AppModule {\n  constructor(\n    private ngRedux: NgRedux,\n    private devTools: DevToolsExtension) {\n\n    let enhancers = [];\n    // ... add whatever other enhancers you want.\n\n    // You probably only want to expose this tool in devMode.\n    if (__DEVMODE__ && devTools.isEnabled()) {\n      enhancers = [ ...enhancers, devTools.enhancer() ];\n    }\n\n    this.ngRedux.configureStore(\n      rootReducer,\n      initialState,\n      [],\n      enhancers);\n  }\n}\n```\n\nFor Angular 1 see [ng-redux](https://github.com/angular-redux/ng-redux).\n\n#### [Angular @ngrx/store](https://ngrx.io/) + [`@ngrx/store-devtools`](https://ngrx.io/guide/store-devtools)\n\n```js\nimport { StoreDevtoolsModule } from '@ngrx/store-devtools';\n\n@NgModule({\n  imports: [\n    StoreModule.forRoot(rootReducer),\n    // Instrumentation must be imported after importing StoreModule (config is optional)\n    StoreDevtoolsModule.instrument({\n      maxAge: 5,\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n[`Example of integration`](https://github.com/ngrx/platform/tree/master/projects/example-app/) ([live demo](https://ngrx.github.io/platform/example-app/)).\n\n### [Ember](http://emberjs.com/)\n\n#### [`ember-redux`](https://github.com/ember-redux/ember-redux)\n\n```js\n//app/enhancers/index.js\nimport { compose } from 'redux';\nvar devtools = window.__REDUX_DEVTOOLS_EXTENSION__\n  ? window.__REDUX_DEVTOOLS_EXTENSION__()\n  : (f) => f;\nexport default compose(devtools);\n```\n\n### [Cycle](https://github.com/cyclejs/cyclejs)\n\n#### [`@culli/store`](https://github.com/milankinen/culli/tree/master/packages/store)\n\n```js\nimport { run } from '@cycle/most-run';\nimport { makeDOMDriver as DOM } from '@cycle/dom';\nimport Store, { ReduxDevtools } from '@culli/store';\nimport App, { newId } from './App';\n\nrun(App, {\n  DOM: DOM('#app'),\n  Store: Store(\n    ReduxDevtools({\n      items: [\n        { id: newId(), num: 0 },\n        { id: newId(), num: 0 },\n      ],\n    }),\n  ),\n});\n```\n\n### [Freezer](https://github.com/arqex/freezer)\n\n#### [`freezer-redux-devtools`](https://github.com/arqex/freezer-redux-devtools)\n\n```js\nimport React, { Component } from 'react';\nimport { supportChromeExtension } from 'freezer-redux-devtools/freezer-redux-middleware';\nimport Freezer from 'freezer-js';\n\n// Our state is a freezer object\nvar State = new Freezer({ hello: 'world' });\n\n// Enable the extension\nsupportChromeExtension(State);\n```\n\n### [Horizon](https://github.com/rethinkdb/horizon)\n\n#### [`horizon-remotedev`](https://github.com/zalmoxisus/horizon-remotedev)\n\n```js\n// import hzRemotedev from 'horizon-remotedev';\n// or import hzRemotedev from 'horizon-remotedev/lib/dev'\n// in case you want to use it in production or don't have process.env.NODE_ENV === 'development'\n\n//Setup Horizon connection\nconst horizon = Horizon();\n\n// ...\n// Specify the horizon instance to monitor\nhzRemotedev(horizon('react_messages'));\n```\n\n### [Fable](https://github.com/fable-compiler/Fable)\n\n#### [`fable-elmish/debugger`](https://github.com/fable-elmish/debugger)\n\n```fsharp\nopen Elmish.Debug\n\nProgram.mkProgram init update view\n|> Program.withDebugger // connect to a devtools monitor via Chrome extension if available\n|> Program.run\n\n```\n\nor\n\n```fsharp\nopen Elmish.Debug\n\nProgram.mkProgram init update view\n|> Program.withDebuggerAt (Remote(\"localhost\",8000)) // connect to a server running on localhost:8000\n|> Program.run\n```\n\n### [PureScript](https://github.com/purescript/purescript)\n\n#### [`purescript-react-redux`](https://github.com/ethul/purescript-react-redux)\n\n[`Example of integration`](https://github.com/ethul/purescript-react-redux-example).\n\n### [ClojureScript](https://github.com/clojure/clojurescript)\n\n[`Example of integration`](http://gitlab.xet.ru:9999/publicpr/clojurescript-redux/tree/master#dev-setup)\n\n### [Python](https://www.python.org/)\n\n#### [`pyredux`](https://github.com/peterpeter5/pyredux)\n\n[WIP](https://github.com/zalmoxisus/remotedev-server/issues/34)\n\n### [Swift](https://github.com/apple/swift)\n\n#### [`katanaMonitor`](https://github.com/bolismauro/katanaMonitor-lib-swift) for [`katana-swift`](https://github.com/BendingSpoons/katana-swift)\n\n```swift\nimport KatanaMonitor\n\nvar middleware: [StoreMiddleware] = [\n// other middleware\n]\n\n#if DEBUG\nmiddleware.append(MonitorMiddleware.create(using: .defaultConfiguration))\n#endif\n```\n\n### [Reductive](https://github.com/reasonml-community/reductive)\n\n#### [`reductive-dev-tools`](https://github.com/ambientlight/reductive-dev-tools)\n\n```reason\nlet storeEnhancer =\n  ReductiveDevTools.(\n    Connectors.reductiveEnhancer(\n      Extension.enhancerOptions(~name=\"MyApp\", ()),\n    )\n  );\n\nlet storeCreator = storeEnhancer @@ Reductive.Store.create;\n```\n\n### [Aurelia](http://aurelia.io)\n\n#### [`aurelia-store`](https://aurelia.io/docs/plugins/store)\n\n```ts\nimport {Aurelia} from 'aurelia-framework';\nimport {initialState} from './state';\n\nexport function configure(aurelia: Aurelia) {\n  aurelia.use\n    .standardConfiguration()\n    .feature('resources');\n\n    ...\n\n  aurelia.use.plugin('aurelia-store', {\n    initialState,\n    devToolsOptions: { // optional\n      ... // see https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md\n    },\n  });\n\n  aurelia.start().then(() => aurelia.setRoot());\n}\n```\n"
  },
  {
    "path": "extension/docs/README.md",
    "content": "# Documentation\n\n- [Extension](/README.md)\n  - [Installation](/README.md#installation)\n  - [Usage](/README.md#usage)\n  - [Demo](/README.md#demo)\n- [API Reference](/docs/API/README.md)\n  - [Options (arguments)](/docs/API/Arguments.md)\n  - [Methods (advanced API)](/docs/API/Methods.md)\n- Features\n  - [Trace actions calls](/docs/Features/Trace.md)\n- [Integrations](/docs/Integrations.md)\n- [FAQ](/docs/FAQ.md)\n- [Troubleshooting](/docs/Troubleshooting.md)\n- [Recipes](/docs/Recipes.md)\n- [Articles](/docs/Articles.md)\n- [Videos](/docs/Videos.md)\n- [Credits](/docs/Credits.md)\n- [Support us](/README.md#backers)\n- [Feedback](/docs/Feedback.md)\n- [Change Log](https://github.com/zalmoxisus/redux-devtools-extension/releases)\n"
  },
  {
    "path": "extension/docs/Recipes.md",
    "content": "# Recipes\n\n### Using in a typescript project\n\nThe recommended way is to use [`@redux-devtools/extension` npm package](/README.md#13-use-redux-devtools-extension-package-from-npm), which contains all typescript definitions. Or you can just use `window as any`:\n\n```js\nconst store = createStore(\n  rootReducer,\n  initialState,\n  (window as any).__REDUX_DEVTOOLS_EXTENSION__ &&\n    (window as any).__REDUX_DEVTOOLS_EXTENSION__()\n);\n```\n\nNote that you many need to set `no-any` to false in your `tslint.json` file.\n\nAlternatively you can use type-guard in order to avoid\ncasting to any.\n\n```typescript\nimport { createStore, StoreEnhancer } from 'redux';\n\n// ...\n\ntype WindowWithDevTools = Window & {\n  __REDUX_DEVTOOLS_EXTENSION__: () => StoreEnhancer<unknown, {}>;\n};\n\nconst isReduxDevtoolsExtenstionExist = (\n  arg: Window | WindowWithDevTools,\n): arg is WindowWithDevTools => {\n  return '__REDUX_DEVTOOLS_EXTENSION__' in arg;\n};\n\n// ...\n\nconst store = createStore(\n  rootReducer,\n  initialState,\n  isReduxDevtoolsExtenstionExist(window)\n    ? window.__REDUX_DEVTOOLS_EXTENSION__()\n    : undefined,\n);\n```\n\n### Export from browser console or from application\n\n```js\nstore.liftedStore.getState();\n```\n\nThe extension is not sharing `store` object, so you should take care of that.\n\n### Applying multiple times with different sets of options\n\nWe're [not allowing that from instrumentation part](https://github.com/reduxjs/redux-devtools/blob/main/packages/redux-devtools-extension/src/logOnly.ts), which can be used it like so:\n\n```js\nimport { createStore, compose } from 'redux';\nimport { devToolsEnhancerLogOnly } from '@redux-devtools/extension';\n\nconst store = createStore(\n  reducer,\n  /* preloadedState, */ compose(\n    devToolsEnhancerLogOnly({\n      instaceID: 1,\n      name: 'Denylisted',\n      actionsDenylist: '...',\n    }),\n    devToolsEnhancerLogOnly({\n      instaceID: 2,\n      name: 'Allowlisted',\n      actionsAllowlist: '...',\n    }),\n  ),\n);\n```\n"
  },
  {
    "path": "extension/docs/Troubleshooting.md",
    "content": "# Troubleshooting\n\n### I just see empty log or \"No store found\"\n\nMake sure you [applied the enhancer](https://github.com/zalmoxisus/redux-devtools-extension#2-use-with-redux). Note that passing enhancer as last argument requires redux@>=3.1.0. For older versions apply it like [here](https://github.com/zalmoxisus/redux-devtools-extension/blob/v0.4.2/examples/todomvc/store/configureStore.js) or [here](https://github.com/zalmoxisus/redux-devtools-extension/blob/v0.4.2/examples/counter/store/configureStore.js#L7-L12).\n\nDon't mix the old Redux API with the new one. Pass enhancers and applyMiddleware as last createStore argument.\n\n### Access file url (`file:///`)\n\nIf you develop on your local filesystem, make sure to allow Redux DevTools access to `file:///` URLs in the settings of this extension:\n\n<img width=\"746\" alt=\"extensions\" src=\"https://cloud.githubusercontent.com/assets/7957859/19075220/a0fad99e-8a4c-11e6-8b87-757f2dc179cb.png\">\n\n### It shows only the `@@INIT` action or moving back and forth doesn't update the state\n\nMost likely you mutate the state. Check it by [adding `redux-immutable-state-invariant` middleware](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/examples/counter/store/configureStore.js#L3).\n\nAnother cause could be that you are creating multiple stores, which means that the devtools get attached to one but the application uses another. See [https://github.com/reduxjs/redux-toolkit/issues/2753](this issue).\n\n### @@INIT or REPLACE action resets the state of the app or last actions RE-APPLIED\n\n`@@redux/REPLACE` (or `@@INIT`) is used internally when the application is hot reloaded. When you use `store.replaceReducer` the effect will be the same as for hot-reloading, where the extension is recomputing all the history again. To avoid that set [`shouldHotReload`](/docs/API/Arguments.md#shouldhotreload) parameter to `false`.\n\n### It doesn't work with other store enhancers\n\nUsually the extension's store enhancer should be last in the compose. When you're using [`window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__`](/README.md#12-advanced-store-setup) or [`composeWithDevTools`](/README.md#13-use-redux-devtools-extension-package-from-npm) helper you don't have to worry about the enhancers order. However some enhancers ([like `redux-batched-subscribe`](https://github.com/zalmoxisus/redux-devtools-extension/issues/261)) also have this requirement to be the last in the compose. In this case you can use it like so:\n\n```js\nconst store = createStore(\n  reducer,\n  preloadedState,\n  compose(\n    // applyMiddleware(thunk),\n    window.__REDUX_DEVTOOLS_EXTENSION__\n      ? window.__REDUX_DEVTOOLS_EXTENSION__()\n      : (noop) => noop,\n    batchedSubscribe(/* ... */),\n  ),\n);\n```\n\nWhere `batchedSubscribe` is `redux-batched-subscribe` store enhancer.\n\n### Excessive use of memory and CPU\n\nThat is happening due to serialization of some huge objects included in the state or action. The solution is to [sanitize them](/docs/API/Arguments.md#actionsanitizer--statesanitizer).\n\nYou can do that by including/omitting data containing specific values, having specific types... In the example below we're omitting parts of action and state objects with the key `data` (in case of action only when was dispatched action `FILE_DOWNLOAD_SUCCESS`):\n\n```js\nconst actionSanitizer = (action) =>\n  action.type === 'FILE_DOWNLOAD_SUCCESS' && action.data\n    ? { ...action, data: '<<LONG_BLOB>>' }\n    : action;\nconst store = createStore(\n  rootReducer,\n  window.__REDUX_DEVTOOLS_EXTENSION__ &&\n    window.__REDUX_DEVTOOLS_EXTENSION__({\n      actionSanitizer,\n      stateSanitizer: (state) =>\n        state.data ? { ...state, data: '<<LONG_BLOB>>' } : state,\n    }),\n);\n```\n\nThere's a more advanced [example on how to implement that for `ui-router`](https://github.com/zalmoxisus/redux-devtools-extension/issues/455#issuecomment-404538385).\n\nThe extension is in different process and cannot access the store object directly, unlike vanilla [`redux-devtools`](https://github.com/reduxjs/redux-devtools) which doesn't have this issue. In case sanitizing doesn't fit your use case, you might consider including it directly as a react component, so there will be no need to serialize the data, but it would add some complexity.\n\n### It fails to serialize data when [passing synthetic events](https://github.com/zalmoxisus/redux-devtools-extension/issues/275) or [calling an action directly with `redux-actions`](https://github.com/zalmoxisus/redux-devtools-extension/issues/287)\n\nReact synthetic event cannot be reused for performance reason. So, it's not possible to serialize event objects you pass to action payloads.\n\n1. The best solution is **not to pass the whole event object to reducers, but the data you need**:\n\n```diff\nfunction click(event) {\n  return {\n    type: ELEMENT_CLICKED,\n-    event: event\n+    value: event.target.value\n  };\n}\n```\n\n2. If you cannot pick data from the event object or, for some reason, you need the whole object, use `event.persist()` as suggested in [React Docs](https://facebook.github.io/react/docs/events.html#event-pooling), but it will consume RAM while not needed.\n\n   ```diff\n   function increment(event) {\n   + event.persist();\n     return {\n       type: ELEMENT_CLICKED,\n       event: event,\n     };\n   }\n   ```\n\n3. A workaround, to pass the whole object and at the same time not to persist it, is to override this key of the stringified payload in your action creator. Add a custom `toJSON` function right in the action object (which will be called by the extension before accessing the object):\n\n   ```diff\n   function increment(event) {\n     return {\n       type: ELEMENT_CLICKED,\n       event: event,\n   +   toJSON: function (){\n   +     return { ...this, event: '[Event]' };\n   +   }\n     };\n   }\n   ```\n\n   Note that it shouldn't be arrow function as we want to have access to the function's `this`.\n\n   As we don't have access to the original object, skipping and recomputing actions during hot reloading will not work in this case. We recommend to use the first solution whenever possible.\n\n### Symbols or other unserializable data not shown\n\nTo get data which cannot be serialized by `JSON.stringify`, set [`serialize` parameter](/docs/API/Arguments.md#serialize):\n\n```js\nconst store = Redux.createStore(\n  reducer,\n  window.__REDUX_DEVTOOLS_EXTENSION__ &&\n    window.__REDUX_DEVTOOLS_EXTENSION__({\n      serialize: true,\n    }),\n);\n```\n\nIt will handle also date, regex, undefined, error objects, symbols, maps, sets and functions.\n"
  },
  {
    "path": "extension/docs/Videos.md",
    "content": "# Videos\n\n- [Debugging flux applications in production at React Europe 2016](https://youtu.be/YU8jQ2HtqH4)\n- [Hot Reloading with Time Travel at React Europe 2015](https://youtu.be/xsSnOQynTHs)\n- [Getting Started with Redux DevTools Extension](https://egghead.io/lessons/javascript-getting-started-with-redux-dev-tools)\n- [React & Redux With ExpressJS](https://www.youtube.com/watch?v=6ygcbRpZFR4)\n"
  },
  {
    "path": "extension/edge/manifest.json",
    "content": "{\n  \"version\": \"3.2.10\",\n  \"name\": \"Redux DevTools\",\n  \"description\": \"Redux DevTools for debugging application's state changes.\",\n  \"homepage_url\": \"https://github.com/reduxjs/redux-devtools\",\n  \"manifest_version\": 3,\n  \"action\": {\n    \"default_icon\": \"img/logo/gray.png\",\n    \"default_title\": \"Redux DevTools\",\n    \"default_popup\": \"devpanel.html#popup\"\n  },\n  \"commands\": {\n    \"devtools-window\": {\n      \"description\": \"DevTools window\"\n    },\n    \"devtools-remote\": {\n      \"description\": \"Remote DevTools\"\n    },\n    \"_execute_action\": {\n      \"suggested_key\": {\n        \"default\": \"Ctrl+Shift+E\"\n      }\n    }\n  },\n  \"icons\": {\n    \"16\": \"img/logo/16x16.png\",\n    \"48\": \"img/logo/48x48.png\",\n    \"128\": \"img/logo/128x128.png\"\n  },\n  \"options_ui\": {\n    \"page\": \"options.html\"\n  },\n  \"background\": {\n    \"service_worker\": \"background.bundle.js\"\n  },\n  \"content_scripts\": [\n    {\n      \"matches\": [\"<all_urls>\"],\n      \"exclude_globs\": [\"https://www.google*\"],\n      \"js\": [\"content.bundle.js\"],\n      \"run_at\": \"document_start\",\n      \"all_frames\": true\n    },\n    {\n      \"matches\": [\"<all_urls>\"],\n      \"exclude_globs\": [\"https://www.google*\"],\n      \"js\": [\"page.bundle.js\"],\n      \"run_at\": \"document_start\",\n      \"all_frames\": true,\n      \"world\": \"MAIN\"\n    }\n  ],\n  \"devtools_page\": \"devtools.html\",\n  \"externally_connectable\": {\n    \"ids\": [\"*\"]\n  },\n  \"permissions\": [\"notifications\", \"contextMenus\", \"storage\"],\n  \"host_permissions\": [\"file:///*\", \"http://*/*\", \"https://*/*\"],\n  \"content_security_policy\": {\n    \"extension_pages\": \"script-src 'self'; object-src 'self'; style-src * 'unsafe-inline'; img-src 'self' data:;\"\n  }\n}\n"
  },
  {
    "path": "extension/eslint.config.mjs",
    "content": "import globals from 'globals';\nimport eslintJs from '../eslint.js.config.base.mjs';\nimport eslintTsReact from '../eslint.ts.react.config.base.mjs';\nimport eslintJsReactJest from '../eslint.js.react.jest.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTsReact(import.meta.dirname),\n  ...eslintJsReactJest,\n  {\n    ignores: [\n      'chrome',\n      'dist',\n      'edge',\n      'examples',\n      'firefox',\n      'jest.config.ts',\n      'test/electron/fixture/dist',\n    ],\n  },\n  {\n    files: ['build.mjs'],\n    languageOptions: {\n      globals: {\n        ...globals.nodeBuiltin,\n      },\n    },\n  },\n  {\n    files: ['test/**/*.js', 'test/**/*.jsx'],\n    languageOptions: {\n      globals: {\n        ...globals.browser,\n        ...globals.node,\n        EUI: true,\n      },\n    },\n  },\n];\n"
  },
  {
    "path": "extension/firefox/manifest.json",
    "content": "{\n  \"version\": \"3.2.10\",\n  \"name\": \"Redux DevTools\",\n  \"manifest_version\": 3,\n  \"description\": \"Redux Developer Tools for debugging application state changes.\",\n  \"homepage_url\": \"https://github.com/reduxjs/redux-devtools\",\n  \"browser_specific_settings\": {\n    \"gecko\": {\n      \"id\": \"extension@redux.devtools\"\n    }\n  },\n  \"action\": {\n    \"default_icon\": \"img/logo/38x38.png\",\n    \"default_title\": \"Redux DevTools\",\n    \"default_popup\": \"devpanel.html#popup\"\n  },\n  \"commands\": {\n    \"devtools-window\": {\n      \"description\": \"DevTools window\"\n    },\n    \"devtools-remote\": {\n      \"description\": \"Remote DevTools\"\n    }\n  },\n  \"icons\": {\n    \"16\": \"img/logo/16x16.png\",\n    \"48\": \"img/logo/48x48.png\",\n    \"128\": \"img/logo/128x128.png\"\n  },\n  \"options_ui\": {\n    \"page\": \"options.html\"\n  },\n  \"background\": {\n    \"scripts\": [\"background.bundle.js\"]\n  },\n  \"content_scripts\": [\n    {\n      \"matches\": [\"<all_urls>\"],\n      \"js\": [\"content.bundle.js\"],\n      \"run_at\": \"document_start\",\n      \"all_frames\": true\n    },\n    {\n      \"matches\": [\"<all_urls>\"],\n      \"js\": [\"page.bundle.js\"],\n      \"run_at\": \"document_start\",\n      \"all_frames\": true,\n      \"world\": \"MAIN\"\n    }\n  ],\n  \"devtools_page\": \"devtools.html\",\n  \"permissions\": [\"notifications\", \"contextMenus\", \"tabs\", \"storage\"],\n  \"host_permissions\": [\"file:///*\", \"http://*/*\", \"https://*/*\"],\n  \"content_security_policy\": {\n    \"extension_pages\": \"script-src 'self'; object-src 'self'; img-src 'self' data:;\"\n  }\n}\n"
  },
  {
    "path": "extension/jest.config.ts",
    "content": "import { createJsWithTsEsmPreset, type JestConfigWithTsJest } from 'ts-jest';\n\nconst presetConfig = createJsWithTsEsmPreset({\n  tsconfig: 'tsconfig.json',\n});\n\nconst jestConfig: JestConfigWithTsJest = {\n  ...presetConfig,\n  setupFilesAfterEnv: ['<rootDir>/test/setup.js'],\n  testPathIgnorePatterns: ['<rootDir>/examples'],\n  testEnvironment: 'jsdom',\n  moduleNameMapper: {\n    '^(\\\\.{1,2}/.*)\\\\.js$': '$1',\n    '\\\\.css$': '<rootDir>/test/__mocks__/styleMock.js',\n  },\n};\n\nexport default jestConfig;\n"
  },
  {
    "path": "extension/package.json",
    "content": "{\n  \"private\": true,\n  \"name\": \"remotedev-redux-devtools-extension\",\n  \"version\": \"3.2.12\",\n  \"description\": \"Redux Developer Tools for debugging application state changes.\",\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/extension\",\n  \"license\": \"MIT\",\n  \"author\": \"Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)\",\n  \"type\": \"module\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"build\": \"pnpm run build:extension && pnpm run type-check\",\n    \"build:extension\": \"node build.mjs\",\n    \"clean\": \"rimraf dist && rimraf chrome/dist && rimraf edge/dist && rimraf firefox/dist\",\n    \"test:app\": \"cross-env BABEL_ENV=test node --experimental-vm-modules node_modules/jest/bin/jest.js test/app\",\n    \"test:chrome\": \"cross-env SE_FORCE_BROWSER_DOWNLOAD=true node --experimental-vm-modules node_modules/jest/bin/jest.js test/chrome\",\n    \"build:test:electron:fixture\": \"webpack --config test/electron/fixture/webpack.config.js\",\n    \"test:electron\": \"pnpm run build:test:electron:fixture && node --experimental-vm-modules node_modules/jest/bin/jest.js test/electron\",\n    \"test\": \"pnpm run test:app && pnpm run test:chrome && pnpm run test:electron\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\"\n  },\n  \"dependencies\": {\n    \"@emotion/react\": \"^11.14.0\",\n    \"@emotion/styled\": \"^11.14.1\",\n    \"@redux-devtools/app\": \"workspace:^\",\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@redux-devtools/instrument\": \"workspace:^\",\n    \"@redux-devtools/serialize\": \"workspace:^\",\n    \"@redux-devtools/slider-monitor\": \"workspace:^\",\n    \"@redux-devtools/ui\": \"workspace:^\",\n    \"@redux-devtools/utils\": \"workspace:^\",\n    \"@reduxjs/toolkit\": \"^2.11.2\",\n    \"@types/jsan\": \"^3.1.5\",\n    \"jsan\": \"^3.1.14\",\n    \"localforage\": \"^1.10.0\",\n    \"lodash-es\": \"^4.17.23\",\n    \"react\": \"^19.2.4\",\n    \"react-dom\": \"^19.2.4\",\n    \"react-icons\": \"^5.6.0\",\n    \"react-is\": \"^19.2.4\",\n    \"react-json-tree\": \"workspace:^\",\n    \"react-redux\": \"^9.2.0\",\n    \"redux\": \"^5.0.1\",\n    \"redux-persist\": \"^6.0.0\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.29.0\",\n    \"@babel/preset-env\": \"^7.29.0\",\n    \"@babel/preset-react\": \"^7.28.5\",\n    \"@babel/preset-typescript\": \"^7.28.5\",\n    \"@babel/register\": \"^7.28.6\",\n    \"@jest/globals\": \"^30.3.0\",\n    \"@testing-library/dom\": \"^10.4.1\",\n    \"@testing-library/jest-dom\": \"^6.9.1\",\n    \"@testing-library/react\": \"^16.3.2\",\n    \"@types/chrome\": \"^0.1.37\",\n    \"@types/lodash-es\": \"^4.17.12\",\n    \"@types/react\": \"^19.2.14\",\n    \"@types/react-dom\": \"^19.2.3\",\n    \"chromedriver\": \"^146.0.3\",\n    \"cross-env\": \"^10.1.0\",\n    \"electron\": \"^41.0.2\",\n    \"esbuild\": \"^0.27.4\",\n    \"globals\": \"^17.4.0\",\n    \"immutable\": \"^5.1.5\",\n    \"jest\": \"^30.3.0\",\n    \"jest-environment-jsdom\": \"^30.3.0\",\n    \"pug\": \"^3.0.4\",\n    \"rimraf\": \"^6.1.3\",\n    \"selenium-webdriver\": \"^4.41.0\",\n    \"sinon-chrome\": \"^3.0.1\",\n    \"ts-jest\": \"^29.4.6\",\n    \"typescript\": \"~5.9.3\",\n    \"webpack\": \"^5.105.4\",\n    \"webpack-cli\": \"^7.0.0\"\n  }\n}\n"
  },
  {
    "path": "extension/src/app/Actions.tsx",
    "content": "import React, { Component } from 'react';\nimport { connect, ResolveThunks } from 'react-redux';\nimport { Button, Container, Divider, Toolbar } from '@redux-devtools/ui';\nimport {\n  DevTools,\n  Dispatcher,\n  DispatcherButton,\n  ExportButton,\n  getActiveInstance,\n  getReport,\n  ImportButton,\n  liftedDispatch,\n  MonitorSelector,\n  PrintButton,\n  SliderButton,\n  SliderMonitor,\n  StoreState,\n  TopButtons,\n} from '@redux-devtools/app';\nimport { GoBroadcast } from 'react-icons/go';\nimport { MdOutlineWindow } from 'react-icons/md';\nimport type { Position } from '../pageScript/api/openWindow.js';\nimport type { SingleMessage } from '../background/store/apiMiddleware.js';\n\ntype StateProps = ReturnType<typeof mapStateToProps>;\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ninterface OwnProps {\n  readonly position: string;\n}\ntype Props = StateProps & DispatchProps & OwnProps;\n\nconst isElectron = navigator.userAgent.includes('Electron');\n\nasync function sendMessage(message: SingleMessage) {\n  await chrome.runtime.sendMessage(message);\n}\n\nclass Actions extends Component<Props> {\n  openWindow = async (position: Position) => {\n    await sendMessage({ type: 'OPEN', position });\n  };\n  openOptionsPage = async () => {\n    if (navigator.userAgent.includes('Firefox')) {\n      await sendMessage({ type: 'OPEN_OPTIONS' });\n    } else {\n      await chrome.runtime.openOptionsPage();\n    }\n  };\n\n  render() {\n    const {\n      monitor,\n      dispatcherIsOpen,\n      sliderIsOpen,\n      options,\n      liftedState,\n      liftedDispatch,\n      position,\n      stateTreeSettings,\n    } = this.props;\n    const { features } = options;\n    return (\n      <Container>\n        <TopButtons\n          dispatch={liftedDispatch}\n          liftedState={liftedState}\n          options={options}\n        />\n        <DevTools\n          monitor={monitor}\n          liftedState={liftedState}\n          monitorState={this.props.monitorState}\n          dispatch={liftedDispatch}\n          features={options.features}\n          stateTreeSettings={stateTreeSettings}\n        />\n        {sliderIsOpen && options.connectionId && options.features.jump && (\n          <SliderMonitor liftedState={liftedState} dispatch={liftedDispatch} />\n        )}\n        {dispatcherIsOpen &&\n          options.connectionId &&\n          options.features.dispatch && <Dispatcher options={options} />}\n        <Toolbar borderPosition=\"top\">\n          {features.export && <ExportButton />}\n          {features.import && <ImportButton />}\n          {position &&\n            (position !== '#popup' ||\n              navigator.userAgent.includes('Firefox')) && <PrintButton />}\n          <Divider />\n          <MonitorSelector />\n          <Divider />\n          {features.jump && <SliderButton isOpen={this.props.sliderIsOpen} />}\n          {features.dispatch && (\n            <DispatcherButton dispatcherIsOpen={this.props.dispatcherIsOpen} />\n          )}\n          <Divider />\n          {!isElectron && (\n            <Button\n              onClick={async () => {\n                await this.openWindow('window');\n              }}\n            >\n              <MdOutlineWindow />\n            </Button>\n          )}\n          {!isElectron && (\n            <Button\n              onClick={async () => {\n                await this.openWindow('remote');\n              }}\n            >\n              <GoBroadcast />\n            </Button>\n          )}\n        </Toolbar>\n      </Container>\n    );\n  }\n}\n\nconst mapStateToProps = (state: StoreState) => {\n  const instances = state.instances;\n  const id = getActiveInstance(instances);\n  return {\n    liftedState: instances.states[id],\n    monitorState: state.monitor.monitorState,\n    options: instances.options[id],\n    monitor: state.monitor.selected,\n    dispatcherIsOpen: state.monitor.dispatcherIsOpen,\n    sliderIsOpen: state.monitor.sliderIsOpen,\n    reports: state.reports.data,\n    stateTreeSettings: state.stateTreeSettings,\n  };\n};\n\nconst actionCreators = {\n  liftedDispatch,\n  getReport,\n};\n\nexport default connect(mapStateToProps, actionCreators)(Actions);\n"
  },
  {
    "path": "extension/src/app/App.tsx",
    "content": "import React, { Component } from 'react';\nimport { connect, ResolveThunks } from 'react-redux';\nimport { Container, Notification } from '@redux-devtools/ui';\nimport {\n  clearNotification,\n  getActiveInstance,\n  Header,\n  Settings,\n  StoreState,\n} from '@redux-devtools/app';\nimport Actions from './Actions.js';\n\ntype StateProps = ReturnType<typeof mapStateToProps>;\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ninterface OwnProps {\n  readonly position: string;\n}\ntype Props = StateProps & DispatchProps & OwnProps;\n\nclass App extends Component<Props> {\n  render() {\n    const { position, options, section, theme, notification } = this.props;\n    if (!position && (!options || !options.features)) {\n      return (\n        <div style={{ padding: '20px', width: '100%', textAlign: 'center' }}>\n          No store found. Make sure to follow{' '}\n          <a\n            href=\"https://github.com/zalmoxisus/redux-devtools-extension#usage\"\n            target=\"_blank\"\n            rel=\"noreferrer\"\n          >\n            the instructions\n          </a>\n          .\n        </div>\n      );\n    }\n\n    let body;\n    switch (section) {\n      case 'Settings':\n        body = <Settings />;\n        break;\n      default:\n        body = <Actions position={position} />;\n    }\n\n    return (\n      <Container themeData={theme}>\n        <Header section={section} />\n        {body}\n        {notification && (\n          <Notification\n            type={notification.type}\n            onClose={this.props.clearNotification}\n          >\n            {notification.message}\n          </Notification>\n        )}\n      </Container>\n    );\n  }\n}\n\nfunction mapStateToProps(state: StoreState) {\n  const instances = state.instances;\n  const id = getActiveInstance(instances);\n  return {\n    options: instances.options[id],\n    section: state.section,\n    theme: state.theme,\n    notification: state.notification,\n  };\n}\n\nconst actionCreators = {\n  clearNotification,\n};\n\nexport default connect(mapStateToProps, actionCreators)(App);\n"
  },
  {
    "path": "extension/src/background/contextMenus.ts",
    "content": "import openDevToolsWindow, { DevToolsPosition } from './openWindow.js';\n\nexport function createMenu() {\n  const menus = [\n    { id: 'devtools-window', title: 'Open in a window' },\n    { id: 'devtools-remote', title: 'Open Remote DevTools' },\n  ];\n\n  const shortcuts: { [commandName: string]: string | undefined } = {};\n  chrome.commands.getAll((commands) => {\n    for (const { name, shortcut } of commands) {\n      shortcuts[name!] = shortcut;\n    }\n\n    for (const { id, title } of menus) {\n      chrome.contextMenus.create({\n        id: id,\n        title: title + (shortcuts[id] ? ' (' + shortcuts[id] + ')' : ''),\n        contexts: ['all'],\n      });\n    }\n  });\n}\n\nexport async function removeMenu() {\n  await chrome.contextMenus.removeAll();\n}\n\nchrome.contextMenus.onClicked.addListener(({ menuItemId }) => {\n  openDevToolsWindow(menuItemId as DevToolsPosition);\n});\n"
  },
  {
    "path": "extension/src/background/index.ts",
    "content": "import '../chromeApiMock.js';\nimport configureStore from './store/backgroundStore.js';\nimport openDevToolsWindow, { DevToolsPosition } from './openWindow.js';\nimport { createMenu, removeMenu } from './contextMenus.js';\nimport { getOptions } from '../options/syncOptions.js';\n\n// Expose the extension's store globally to access it from the windows\n// via chrome.runtime.getBackgroundPage\nexport const store = configureStore();\n\n// Listen for keyboard shortcuts\nchrome.commands.onCommand.addListener((shortcut) => {\n  openDevToolsWindow(shortcut as DevToolsPosition);\n});\n\n// Disable the action by default and create the context menu when installed\nchrome.runtime.onInstalled.addListener(() => {\n  void chrome.action.disable();\n\n  getOptions((option) => {\n    if (option.showContextMenus) createMenu();\n  });\n});\n\n// Create or Remove context menu when config changed\nchrome.storage.onChanged.addListener((changes) => {\n  if (changes.showContextMenus) {\n    if (changes.showContextMenus.newValue) createMenu();\n    else void removeMenu();\n  }\n});\n\n// https://developer.chrome.com/docs/extensions/develop/migrate/to-service-workers#keep_a_service_worker_alive_continuously\nsetInterval(\n  () =>\n    void chrome.storage.local.set({ 'last-heartbeat': new Date().getTime() }),\n  20000,\n);\n"
  },
  {
    "path": "extension/src/background/logging.ts",
    "content": "import { LIFTED_ACTION } from '@redux-devtools/app';\nimport { store } from './index.js';\n\nexport function getReport(\n  reportId: string,\n  tabId: string | number,\n  instanceId: number,\n) {\n  chrome.storage.local.get<{\n    's:hostname': string | undefined;\n    's:port': string | undefined;\n    's:secure': string | undefined;\n  }>(['s:hostname', 's:port', 's:secure'], (options) => {\n    if (!options['s:hostname'] || !options['s:port']) return;\n    const url = `${options['s:secure'] ? 'https' : 'http'}://${\n      options['s:hostname']\n    }:${options['s:port']}`;\n\n    fetch(url, {\n      method: 'POST',\n      headers: {\n        'content-type': 'application/json',\n      },\n      body: JSON.stringify({ op: 'get', id: reportId }),\n    })\n      .then((response) => {\n        return response.json();\n      })\n      .then((json) => {\n        const { payload, preloadedState } = json;\n        if (!payload) return;\n        store.dispatch({\n          type: LIFTED_ACTION,\n          message: 'IMPORT',\n          state: JSON.stringify({ payload, preloadedState }),\n          id: tabId,\n          instanceId: `${tabId}/${instanceId}`,\n        });\n      })\n      .catch(function (err) {\n        /* eslint-disable no-console */\n        console.warn(err);\n        /* eslint-enable no-console */\n      });\n  });\n}\n"
  },
  {
    "path": "extension/src/background/openWindow.ts",
    "content": "export type DevToolsPosition = 'devtools-window' | 'devtools-remote';\n\nconst windows: { [K in DevToolsPosition]?: number } = {};\n\nexport default function openDevToolsWindow(position: DevToolsPosition) {\n  if (!windows[position]) {\n    createWindow(position);\n  } else {\n    chrome.windows.update(windows[position], { focused: true }, () => {\n      if (chrome.runtime.lastError) createWindow(position);\n    });\n  }\n}\n\nfunction createWindow(position: DevToolsPosition) {\n  const url = chrome.runtime.getURL(getPath(position));\n  chrome.windows.create({ type: 'popup', url }, (win) => {\n    windows[position] = win!.id;\n    if (navigator.userAgent.includes('Firefox')) {\n      void chrome.windows.update(win!.id!, { focused: true });\n    }\n  });\n}\n\nfunction getPath(position: DevToolsPosition) {\n  switch (position) {\n    case 'devtools-window':\n      return 'devpanel.html';\n    case 'devtools-remote':\n      return 'remote.html';\n    default:\n      throw new Error('Unrecognized position');\n  }\n}\n"
  },
  {
    "path": "extension/src/background/store/apiMiddleware.ts",
    "content": "import {\n  CustomAction,\n  DispatchAction as AppDispatchAction,\n  LibConfig,\n  LIFTED_ACTION,\n  nonReduxDispatch,\n  REMOVE_INSTANCE,\n  SET_PERSIST,\n  SetPersistAction,\n  stringifyJSON,\n  TOGGLE_PERSIST,\n  UPDATE_STATE,\n} from '@redux-devtools/app';\nimport type { Options, OptionsMessage } from '../../options/syncOptions.js';\nimport openDevToolsWindow, { DevToolsPosition } from '../openWindow.js';\nimport { getReport } from '../logging.js';\nimport { Action, Dispatch, Middleware } from 'redux';\nimport type {\n  ContentScriptToBackgroundMessage,\n  SplitMessage,\n} from '../../contentScript/index.js';\nimport type {\n  ErrorMessage,\n  PageScriptToContentScriptMessageForwardedToMonitors,\n  PageScriptToContentScriptMessageWithoutDisconnectOrInitInstance,\n} from '../../pageScript/api/index.js';\nimport { LiftedState } from '@redux-devtools/instrument';\nimport type {\n  BackgroundAction,\n  LiftedActionAction,\n} from './backgroundStore.js';\nimport type { Position } from '../../pageScript/api/openWindow.js';\nimport type { BackgroundState } from './backgroundReducer.js';\nimport { store } from '../index.js';\n\ninterface TabMessageBase {\n  readonly type: string;\n  readonly state?: string | undefined;\n  readonly id?: string;\n}\n\ninterface StartAction extends TabMessageBase {\n  readonly type: 'START';\n  readonly state?: never;\n  readonly id?: never;\n}\n\ninterface StopAction extends TabMessageBase {\n  readonly type: 'STOP';\n  readonly state?: never;\n  readonly id?: never;\n}\n\ninterface OptionsAction {\n  readonly type: 'OPTIONS';\n  readonly options: Options;\n}\n\ninterface DispatchAction extends TabMessageBase {\n  readonly type: 'DISPATCH';\n  readonly action: AppDispatchAction;\n  readonly state: string | undefined;\n  readonly id: string;\n}\n\ninterface ImportAction extends TabMessageBase {\n  readonly type: 'IMPORT';\n  readonly action: undefined;\n  readonly state: string | undefined;\n  readonly id: string;\n}\n\ninterface ActionAction extends TabMessageBase {\n  readonly type: 'ACTION';\n  readonly action: string | CustomAction;\n  readonly state: string | undefined;\n  readonly id: string;\n}\n\ninterface ExportAction extends TabMessageBase {\n  readonly type: 'EXPORT';\n  readonly action: undefined;\n  readonly state: string | undefined;\n  readonly id: string;\n}\n\nexport interface NAAction {\n  readonly type: 'NA';\n  readonly id: string | number;\n}\n\ninterface InitMessage<S, A extends Action<string>> {\n  readonly type: 'INIT';\n  readonly payload: string;\n  instanceId: string;\n  readonly source: '@devtools-page';\n  action?: string;\n  name?: string | undefined;\n  liftedState?: LiftedState<S, A, unknown>;\n  libConfig?: LibConfig;\n}\n\ninterface LiftedMessage {\n  type: 'LIFTED';\n  liftedState: { isPaused: boolean | undefined };\n  instanceId: number;\n  source: '@devtools-page';\n}\n\ninterface SerializedPartialLiftedState {\n  readonly stagedActionIds: readonly number[];\n  readonly currentStateIndex: number;\n  readonly nextActionId: number;\n}\n\ninterface SerializedPartialStateMessage {\n  readonly type: 'PARTIAL_STATE';\n  readonly payload: SerializedPartialLiftedState;\n  readonly source: '@devtools-page';\n  instanceId: number;\n  readonly maxAge: number;\n  readonly actionsById: string;\n  readonly computedStates: string;\n  readonly committedState: boolean;\n}\n\ninterface SerializedExportMessage {\n  readonly type: 'EXPORT';\n  readonly payload: string;\n  readonly committedState: string | undefined;\n  readonly source: '@devtools-page';\n  instanceId: number;\n}\n\ninterface SerializedActionMessage {\n  readonly type: 'ACTION';\n  readonly payload: string;\n  readonly source: '@devtools-page';\n  instanceId: number;\n  readonly action: string;\n  readonly maxAge: number;\n  readonly nextActionId: number;\n}\n\ninterface SerializedStateMessage<S, A extends Action<string>> {\n  readonly type: 'STATE';\n  readonly payload: Omit<\n    LiftedState<S, A, unknown>,\n    'actionsById' | 'computedStates' | 'committedState'\n  >;\n  readonly source: '@devtools-page';\n  instanceId: string;\n  readonly libConfig?: LibConfig;\n  readonly actionsById: string;\n  readonly computedStates: string;\n  readonly committedState: boolean;\n}\n\nexport type UpdateStateRequest<S, A extends Action<string>> =\n  | InitMessage<S, A>\n  | LiftedMessage\n  | SerializedPartialStateMessage\n  | SerializedExportMessage\n  | SerializedActionMessage\n  | SerializedStateMessage<S, A>;\n\ninterface UpdateStateAction<S, A extends Action<string>> {\n  readonly type: typeof UPDATE_STATE;\n  request: UpdateStateRequest<S, A>;\n  readonly id: string | number;\n}\n\ntype SplitUpdateStateRequestStart<S, A extends Action<string>> = {\n  split: 'start';\n} & Partial<UpdateStateRequest<S, A>>;\n\ninterface SplitUpdateStateRequestChunk {\n  readonly split: 'chunk';\n  readonly chunk: [string, string];\n}\n\ninterface SplitUpdateStateRequestEnd {\n  readonly split: 'end';\n}\n\nexport type SplitUpdateStateRequest<S, A extends Action<string>> =\n  | SplitUpdateStateRequestStart<S, A>\n  | SplitUpdateStateRequestChunk\n  | SplitUpdateStateRequestEnd;\n\ninterface SplitUpdateStateAction<S, A extends Action<string>> {\n  readonly type: typeof UPDATE_STATE;\n  request: SplitUpdateStateRequest<S, A>;\n  readonly id: string | number;\n}\n\nexport type TabMessage =\n  | StartAction\n  | StopAction\n  | OptionsAction\n  | DispatchAction\n  | ImportAction\n  | ActionAction\n  | ExportAction;\nexport type PanelMessageWithoutNA<S, A extends Action<string>> =\n  | ErrorMessage\n  | UpdateStateAction<S, A>\n  | SetPersistAction;\nexport type PanelMessage<S, A extends Action<string>> =\n  | PanelMessageWithoutNA<S, A>\n  | NAAction;\nexport type PanelMessageWithSplitAction<S, A extends Action<string>> =\n  | PanelMessage<S, A>\n  | SplitUpdateStateAction<S, A>;\n\ntype TabPort = Omit<chrome.runtime.Port, 'postMessage'> & {\n  postMessage: (message: TabMessage) => void;\n};\ntype PanelPort = Omit<chrome.runtime.Port, 'postMessage'> & {\n  postMessage: <S, A extends Action<string>>(\n    message: PanelMessageWithSplitAction<S, A>,\n  ) => void;\n};\n\nexport const CONNECTED = 'socket/CONNECTED';\nexport const DISCONNECTED = 'socket/DISCONNECTED';\nconst connections: {\n  readonly tab: { [K in number | string]: TabPort };\n  readonly panel: { [K in number | string]: PanelPort };\n} = {\n  tab: {},\n  panel: {},\n};\nconst chunks: {\n  [instanceId: string]: PageScriptToContentScriptMessageForwardedToMonitors<\n    unknown,\n    Action<string>\n  >;\n} = {};\nlet monitors = 0;\n\nconst getId = (sender: chrome.runtime.MessageSender, name?: string) =>\n  sender.tab ? sender.tab.id! : name || sender.id!;\n\ntype MonitorAction<S, A extends Action<string>> =\n  | NAAction\n  | ErrorMessage\n  | UpdateStateAction<S, A>\n  | SetPersistAction;\n\n// Chrome message limit is 64 MB, but we're using 32 MB to include other object's parts\nconst maxChromeMsgSize = 32 * 1024 * 1024;\n\nfunction toMonitors<S, A extends Action<string>>(action: MonitorAction<S, A>) {\n  console.log(`Message to monitors: ${action.type}`);\n\n  for (const port of Object.values(connections.panel)) {\n    try {\n      port.postMessage(action);\n    } catch (err) {\n      if (\n        action.type !== UPDATE_STATE ||\n        err == null ||\n        (err as Error).message !==\n          'Message length exceeded maximum allowed length.'\n      ) {\n        throw err;\n      }\n\n      const splitMessageStart: SplitUpdateStateRequestStart<S, A> = {\n        split: 'start',\n      };\n      const toSplit: [string, string][] = [];\n      let size = 0;\n      for (const [key, value] of Object.entries(\n        action.request as unknown as Record<string, unknown>,\n      )) {\n        if (typeof value === 'string') {\n          size += value.length;\n          if (size > maxChromeMsgSize) {\n            toSplit.push([key, value]);\n            continue;\n          }\n        }\n\n        (splitMessageStart as any)[key as keyof typeof splitMessageStart] =\n          value;\n      }\n\n      port.postMessage({ ...action, request: splitMessageStart });\n\n      for (let i = 0; i < toSplit.length; i++) {\n        for (let j = 0; j < toSplit[i][1].length; j += maxChromeMsgSize) {\n          port.postMessage({\n            ...action,\n            request: {\n              split: 'chunk',\n              chunk: [\n                toSplit[i][0],\n                toSplit[i][1].substring(j, j + maxChromeMsgSize),\n              ],\n            },\n          });\n        }\n      }\n\n      port.postMessage({ ...action, request: { split: 'end' } });\n    }\n  }\n}\n\ninterface ImportMessage {\n  readonly message: 'IMPORT';\n  readonly id: string | number;\n  readonly instanceId: string;\n  readonly state: string;\n  readonly action?: never;\n}\n\ntype ToContentScriptMessage = ImportMessage | LiftedActionAction;\n\nfunction toContentScript(messageBody: ToContentScriptMessage) {\n  console.log(`Message to tab ${messageBody.id}: ${messageBody.message}`);\n\n  if (messageBody.message === 'DISPATCH') {\n    const { message, action, id, instanceId, state } = messageBody;\n    connections.tab[id!].postMessage({\n      type: message,\n      action,\n      state: nonReduxDispatch(store, message, instanceId, action, state),\n      id: instanceId.toString().replace(/^[^/]+\\//, ''),\n    });\n  } else if (messageBody.message === 'IMPORT') {\n    const { message, action, id, instanceId, state } = messageBody;\n    connections.tab[id!].postMessage({\n      type: message,\n      action,\n      state: nonReduxDispatch(\n        store,\n        message,\n        instanceId,\n        action as unknown as AppDispatchAction,\n        state,\n      ),\n      id: instanceId.toString().replace(/^[^/]+\\//, ''),\n    });\n  } else if (messageBody.message === 'ACTION') {\n    const { message, action, id, instanceId, state } = messageBody;\n    connections.tab[id!].postMessage({\n      type: message,\n      action,\n      state: nonReduxDispatch(\n        store,\n        message,\n        instanceId,\n        action as unknown as AppDispatchAction,\n        state,\n      ),\n      id: instanceId.toString().replace(/^[^/]+\\//, ''),\n    });\n  } else if (messageBody.message === 'EXPORT') {\n    const { message, action, id, instanceId, state } = messageBody;\n    connections.tab[id!].postMessage({\n      type: message,\n      action,\n      state: nonReduxDispatch(\n        store,\n        message,\n        instanceId,\n        action as unknown as AppDispatchAction,\n        state,\n      ),\n      id: instanceId.toString().replace(/^[^/]+\\//, ''),\n    });\n  } else {\n    const { message, action, id, instanceId, state } = messageBody;\n    connections.tab[id].postMessage({\n      type: message,\n      action,\n      state: nonReduxDispatch(\n        store,\n        message,\n        instanceId,\n        action as AppDispatchAction,\n        state,\n      ),\n      id: (instanceId as number).toString().replace(/^[^/]+\\//, ''),\n    });\n  }\n}\n\nfunction toAllTabs(msg: TabMessage) {\n  console.log(`Message to all tabs: ${msg.type}`);\n\n  for (const tabPort of Object.values(connections.tab)) {\n    tabPort.postMessage(msg);\n  }\n}\n\nfunction getReducerError() {\n  const instancesState = store.getState().instances;\n  const payload = instancesState.states[instancesState.current];\n  const computedState = payload.computedStates[payload.currentStateIndex];\n  if (!computedState) return false;\n  return computedState.error;\n}\n\nfunction togglePersist() {\n  const state = store.getState();\n  if (state.instances.persisted) {\n    for (const id of Object.keys(state.instances.connections)) {\n      if (connections.tab[id]) return;\n      store.dispatch({ type: REMOVE_INSTANCE, id });\n      toMonitors({ type: 'NA', id });\n    }\n  }\n}\n\ninterface OpenMessage {\n  readonly type: 'OPEN';\n  readonly position: Position;\n}\n\ninterface OpenOptionsMessage {\n  readonly type: 'OPEN_OPTIONS';\n}\n\nexport type SingleMessage = OpenMessage | OpenOptionsMessage | OptionsMessage;\n\ntype BackgroundStoreMessage<S, A extends Action<string>> =\n  | PageScriptToContentScriptMessageWithoutDisconnectOrInitInstance<S, A>\n  | SplitMessage\n  | SingleMessage;\n\n// Receive messages from content scripts\nfunction messaging<S, A extends Action<string>>(\n  request: BackgroundStoreMessage<S, A>,\n  sender: chrome.runtime.MessageSender,\n) {\n  let tabId = getId(sender);\n  console.log(`Message from tab ${tabId}: ${request.type ?? request.split}`);\n  if (!tabId) return;\n  if (sender.frameId) tabId = `${tabId}-${sender.frameId}`;\n\n  if (request.type === 'STOP') {\n    if (!Object.keys(store.getState().instances.connections).length) {\n      store.dispatch({ type: DISCONNECTED });\n    }\n    return;\n  }\n  if (request.type === 'OPEN_OPTIONS') {\n    void chrome.runtime.openOptionsPage();\n    return;\n  }\n  if (request.type === 'OPTIONS') {\n    toAllTabs({ type: 'OPTIONS', options: request.options });\n    return;\n  }\n  if (request.type === 'GET_REPORT') {\n    getReport(request.payload, tabId, request.instanceId);\n    return;\n  }\n  if (request.type === 'OPEN') {\n    let position: DevToolsPosition = 'devtools-window';\n    if (['remote', 'window'].includes(request.position)) {\n      position = ('devtools-' + request.position) as DevToolsPosition;\n    }\n    openDevToolsWindow(position);\n    return;\n  }\n  if (request.type === 'ERROR') {\n    if (request.payload) {\n      toMonitors(request);\n      return;\n    }\n    if (!request.message) return;\n    const reducerError = getReducerError();\n    void chrome.notifications.create('app-error', {\n      type: 'basic',\n      title: reducerError\n        ? 'An error occurred in the reducer'\n        : 'An error occurred in the app',\n      message: reducerError || request.message,\n      iconUrl: 'img/logo/48x48.png',\n      isClickable: !!reducerError,\n    });\n    return;\n  }\n\n  const action: UpdateStateAction<S, A> = {\n    type: UPDATE_STATE,\n    request,\n    id: tabId,\n  } as UpdateStateAction<S, A>;\n  const instanceId = `${tabId}/${request.instanceId}`;\n  if ('split' in request) {\n    if (request.split === 'start') {\n      chunks[instanceId] = request as any;\n      return;\n    }\n    if (request.split === 'chunk') {\n      (chunks[instanceId] as any)[request.chunk[0]] =\n        ((chunks[instanceId] as any)[request.chunk[0]] || '') +\n        request.chunk[1];\n      return;\n    }\n    action.request = chunks[instanceId] as any;\n    delete chunks[instanceId];\n  }\n  if (request.instanceId) {\n    action.request.instanceId = instanceId;\n  }\n  store.dispatch(action);\n\n  toMonitors(action);\n}\n\nfunction disconnect(\n  type: 'tab' | 'panel',\n  id: number | string,\n  listener: (message: any, port: chrome.runtime.Port) => void,\n) {\n  return function disconnectListener() {\n    console.log(`Disconnected from ${type} ${id}`);\n\n    const p = connections[type][id];\n    if (listener && p) p.onMessage.removeListener(listener);\n    if (p) p.onDisconnect.removeListener(disconnectListener);\n    delete connections[type][id];\n    if (type === 'tab') {\n      if (!store.getState().instances.persisted) {\n        store.dispatch({ type: REMOVE_INSTANCE, id });\n        toMonitors({ type: 'NA', id });\n      }\n    } else {\n      monitors--;\n      if (monitors === 0) toAllTabs({ type: 'STOP' });\n    }\n  };\n}\n\nfunction onConnect<S, A extends Action<string>>(port: chrome.runtime.Port) {\n  let id: number | string;\n  let listener;\n\n  store.dispatch({ type: CONNECTED, port });\n\n  if (port.name === 'tab') {\n    id = getId(port.sender!);\n    console.log(`Connected to tab ${id}`);\n    if (port.sender!.frameId) id = `${id}-${port.sender!.frameId}`;\n    connections.tab[id] = port;\n    listener = (msg: ContentScriptToBackgroundMessage<S, A>) => {\n      console.log(`Message from tab ${id}: ${msg.name}`);\n      if (msg.name === 'INIT_INSTANCE') {\n        if (typeof id === 'number') {\n          void chrome.action.enable(id);\n          void chrome.action.setIcon({ tabId: id, path: 'img/logo/38x38.png' });\n        }\n        if (monitors > 0) port.postMessage({ type: 'START' });\n\n        const state = store.getState();\n        if (state.instances.persisted) {\n          const instanceId = `${id}/${msg.instanceId}`;\n          const persistedState = state.instances.states[instanceId];\n          if (!persistedState) return;\n          toContentScript({\n            message: 'IMPORT',\n            id,\n            instanceId,\n            state: stringifyJSON(\n              persistedState,\n              state.instances.options[instanceId].serialize,\n            ),\n          });\n        }\n        return;\n      }\n      if (msg.name === 'RELAY') {\n        messaging(msg.message, port.sender!);\n      }\n    };\n    port.onMessage.addListener(listener);\n    port.onDisconnect.addListener(disconnect('tab', id, listener));\n  } else if (port.name && port.name.indexOf('monitor') === 0) {\n    // devpanel\n    id = getId(port.sender!, port.name);\n    console.log(`Connected to monitor ${id}`);\n    connections.panel[id] = port;\n    monitors++;\n    toAllTabs({ type: 'START' });\n    listener = (msg: BackgroundAction) => {\n      console.log(`Message from monitor ${id}: ${msg.type}`);\n      store.dispatch(msg);\n    };\n    port.onMessage.addListener(listener);\n    port.onDisconnect.addListener(disconnect('panel', id, listener));\n\n    const { current } = store.getState().instances;\n    if (current !== 'default') {\n      const connectionId = Object.entries(\n        store.getState().instances.connections,\n      ).find(([, instanceIds]) => instanceIds.includes(current))?.[0];\n      const options = store.getState().instances.options[current];\n      const state = store.getState().instances.states[current];\n      const { actionsById, computedStates, committedState, ...rest } = state;\n      toMonitors({\n        type: UPDATE_STATE,\n        request: {\n          type: 'STATE',\n          payload: rest as Omit<\n            LiftedState<S, A, unknown>,\n            'actionsById' | 'computedStates' | 'committedState'\n          >,\n          source: '@devtools-page',\n          instanceId:\n            typeof current === 'number' ? current.toString() : current,\n          actionsById: stringifyJSON(actionsById, options.serialize),\n          computedStates: stringifyJSON(computedStates, options.serialize),\n          committedState: typeof committedState !== 'undefined',\n        },\n        id: connectionId ?? current,\n      });\n    }\n  }\n}\n\nchrome.runtime.onConnect.addListener(onConnect);\nchrome.runtime.onConnectExternal.addListener(onConnect);\nchrome.runtime.onMessage.addListener(messaging);\nchrome.runtime.onMessageExternal.addListener(messaging);\n\nchrome.notifications.onClicked.addListener((id) => {\n  void chrome.notifications.clear(id);\n  openDevToolsWindow('devtools-window');\n});\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nconst api: Middleware<{}, BackgroundState, Dispatch<BackgroundAction>> =\n  (store) => (next) => (untypedAction) => {\n    const action = untypedAction as BackgroundAction;\n\n    if (action.type === LIFTED_ACTION) toContentScript(action);\n    else if (action.type === TOGGLE_PERSIST) {\n      togglePersist();\n      toMonitors({\n        type: SET_PERSIST,\n        payload: !store.getState().instances.persisted,\n      });\n    }\n    return next(action);\n  };\n\nexport default api;\n"
  },
  {
    "path": "extension/src/background/store/backgroundReducer.ts",
    "content": "import { combineReducers, Reducer } from 'redux';\nimport { instances, InstancesState } from '@redux-devtools/app';\nimport { BackgroundAction } from './backgroundStore.js';\n\nexport interface BackgroundState {\n  readonly instances: InstancesState;\n}\n\nconst rootReducer: Reducer<\n  BackgroundState,\n  BackgroundAction,\n  Partial<BackgroundState>\n> = combineReducers({\n  instances,\n}) as any;\n\nexport default rootReducer;\n"
  },
  {
    "path": "extension/src/background/store/backgroundStore.ts",
    "content": "import { createStore, applyMiddleware } from 'redux';\nimport {\n  CustomAction,\n  DispatchAction,\n  LIFTED_ACTION,\n  StoreActionWithoutLiftedAction,\n} from '@redux-devtools/app';\nimport rootReducer, { BackgroundState } from './backgroundReducer.js';\nimport api, { CONNECTED, DISCONNECTED } from './apiMiddleware.js';\n\ninterface LiftedActionActionBase {\n  action?: DispatchAction | string | CustomAction;\n  state?: string;\n  toAll?: boolean;\n  readonly instanceId: string | number;\n  readonly id: string | number | undefined;\n}\ninterface LiftedActionDispatchAction extends LiftedActionActionBase {\n  type: typeof LIFTED_ACTION;\n  message: 'DISPATCH';\n  action: DispatchAction;\n  toAll?: boolean;\n}\ninterface LiftedActionImportAction extends LiftedActionActionBase {\n  type: typeof LIFTED_ACTION;\n  message: 'IMPORT';\n  state: string;\n  preloadedState?: unknown | undefined;\n  action?: never;\n}\ninterface LiftedActionActionAction extends LiftedActionActionBase {\n  type: typeof LIFTED_ACTION;\n  message: 'ACTION';\n  action: string | CustomAction;\n}\ninterface LiftedActionExportAction extends LiftedActionActionBase {\n  type: typeof LIFTED_ACTION;\n  message: 'EXPORT';\n  toExport: boolean;\n  action?: never;\n}\nexport type LiftedActionAction =\n  | LiftedActionDispatchAction\n  | LiftedActionImportAction\n  | LiftedActionActionAction\n  | LiftedActionExportAction;\n\ninterface ConnectedAction {\n  readonly type: typeof CONNECTED;\n}\n\ninterface DisconnectedAction {\n  readonly type: typeof DISCONNECTED;\n}\n\nexport type BackgroundAction =\n  | StoreActionWithoutLiftedAction\n  | LiftedActionAction\n  | ConnectedAction\n  | DisconnectedAction;\n\nexport default function configureStore(\n  preloadedState?: Partial<BackgroundState>,\n) {\n  return createStore(rootReducer, preloadedState, applyMiddleware(api));\n  /*\n  let enhancer;\n  if (process.env.NODE_ENV === 'production') {\n    enhancer = applyMiddleware(api);\n  } else {\n    const logger = require('redux-logger');\n    enhancer = applyMiddleware(api, logger());\n  }\n\n  return createStore(rootReducer, preloadedState, enhancer);\n*/\n}\n"
  },
  {
    "path": "extension/src/chromeApiMock.ts",
    "content": "// Mock not supported chrome.* API for Firefox and Electron\n\nconst isElectron = navigator.userAgent.includes('Electron');\nconst isFirefox = navigator.userAgent.includes('Firefox');\n\n// Background page only\nif (\n  (isElectron && location.pathname === '/background.bundle.js') ||\n  isFirefox\n) {\n  (chrome.runtime as any).onConnectExternal = {\n    addListener() {\n      // do nothing.\n    },\n  };\n  (chrome.runtime as any).onMessageExternal = {\n    addListener() {\n      // do nothing.\n    },\n  };\n\n  if (isElectron) {\n    (chrome.notifications as any) = {\n      onClicked: {\n        addListener() {\n          // do nothing.\n        },\n      },\n      create() {\n        // do nothing.\n      },\n      clear() {\n        // do nothing.\n      },\n    };\n    (chrome.contextMenus as any) = {\n      onClicked: {\n        addListener() {\n          // do nothing.\n        },\n      },\n    };\n    (chrome.commands as any) = {\n      onCommand: {\n        addListener() {\n          // do nothing.\n        },\n      },\n    };\n  } else {\n    (chrome.storage as any).sync = chrome.storage.local;\n    (chrome.runtime as any).onInstalled = {\n      addListener: (cb: any) => cb(),\n    };\n  }\n}\n\nif (isElectron) {\n  if (!chrome.storage.local || !chrome.storage.local.remove) {\n    (chrome.storage as any).local = {\n      set(items: { [key: string]: string }, callback: () => void) {\n        for (const [key, value] of Object.entries(items)) {\n          localStorage.setItem(key, value);\n        }\n        if (callback) {\n          callback();\n        }\n      },\n      get(\n        keys: { [key: string]: any },\n        callback: (items: { [key: string]: any }) => void,\n      ) {\n        const result = Object.fromEntries(\n          Object.entries(keys).map(([key, value]) => [\n            key,\n            localStorage.getItem(key) ?? value,\n          ]),\n        );\n        if (callback) {\n          callback(result);\n        }\n      },\n      // Electron ~ 1.4.6\n      remove(keys: string | string[], callback: () => void) {\n        if (Array.isArray(keys)) {\n          for (const key of keys) {\n            localStorage.removeItem(key);\n          }\n        } else {\n          localStorage.removeItem(keys);\n        }\n        if (callback) {\n          callback();\n        }\n      },\n    };\n  }\n  // Avoid error: chrome.runtime.sendMessage is not supported responseCallback\n  const originSendMessage = (chrome.runtime as any).sendMessage;\n  (chrome.runtime as any).sendMessage = function (...args: unknown[]) {\n    if (process.env.NODE_ENV === 'development') {\n      return originSendMessage(...args);\n    }\n    if (typeof args[arguments.length - 1] === 'function') {\n      Array.prototype.pop.call(args);\n    }\n    return originSendMessage(...args);\n  };\n}\n\nif (isFirefox || isElectron) {\n  (chrome.storage as any).sync = chrome.storage.local;\n}\n"
  },
  {
    "path": "extension/src/contentScript/index.ts",
    "content": "import '../chromeApiMock.js';\nimport {\n  getOptions,\n  isAllowed,\n  Options,\n  prefetchOptions,\n  prepareOptionsForPage,\n} from '../options/syncOptions.js';\nimport type { TabMessage } from '../background/store/apiMiddleware.js';\nimport type {\n  PageScriptToContentScriptMessage,\n  PageScriptToContentScriptMessageWithoutDisconnect,\n  PageScriptToContentScriptMessageWithoutDisconnectOrInitInstance,\n} from '../pageScript/api/index.js';\nimport { Action } from 'redux';\nimport {\n  CustomAction,\n  DispatchAction as AppDispatchAction,\n} from '@redux-devtools/app';\nimport { LiftedState } from '@redux-devtools/instrument';\n\nconst source = '@devtools-extension';\nconst pageSource = '@devtools-page';\n// Chrome message limit is 64 MB, but we're using 32 MB to include other object's parts\nconst maxChromeMsgSize = 32 * 1024 * 1024;\nlet connected = false;\nlet bg: chrome.runtime.Port | undefined;\n\ndeclare global {\n  interface Window {\n    devToolsExtensionID?: string;\n  }\n}\n\ninterface StartAction {\n  readonly type: 'START';\n  readonly state: undefined;\n  readonly id: undefined;\n  readonly source: typeof source;\n}\n\ninterface StopAction {\n  readonly type: 'STOP';\n  readonly state: undefined;\n  readonly id: undefined;\n  readonly source: typeof source;\n  readonly failed?: boolean;\n}\n\ninterface DispatchAction {\n  readonly type: 'DISPATCH';\n  readonly payload: AppDispatchAction;\n  readonly state: string | undefined;\n  readonly id: string;\n  readonly source: typeof source;\n}\n\ninterface ImportAction {\n  readonly type: 'IMPORT';\n  readonly payload: undefined;\n  readonly state: string | undefined;\n  readonly id: string;\n  readonly source: typeof source;\n}\n\ninterface ActionAction {\n  readonly type: 'ACTION';\n  readonly payload: string | CustomAction;\n  readonly state: string | undefined;\n  readonly id: string;\n  readonly source: typeof source;\n}\n\ninterface ExportAction {\n  readonly type: 'EXPORT';\n  readonly payload: undefined;\n  readonly state: string | undefined;\n  readonly id: string;\n  readonly source: typeof source;\n}\n\ninterface UpdateAction {\n  readonly type: 'UPDATE';\n  readonly state: string | undefined;\n  readonly id: string;\n  readonly source: typeof source;\n}\n\ninterface OptionsAction {\n  readonly type: 'OPTIONS';\n  readonly options: Options;\n  readonly id: undefined;\n  readonly source: typeof source;\n}\n\nexport type ContentScriptToPageScriptMessage =\n  | StartAction\n  | StopAction\n  | DispatchAction\n  | ImportAction\n  | ActionAction\n  | ExportAction\n  | UpdateAction\n  | OptionsAction;\n\ninterface ImportStatePayload<S, A extends Action<string>> {\n  readonly type: 'IMPORT_STATE';\n  readonly nextLiftedState: LiftedState<S, A, unknown> | readonly A[];\n  readonly preloadedState?: S;\n}\n\ninterface ImportStateDispatchAction<S, A extends Action<string>> {\n  readonly type: 'DISPATCH';\n  readonly payload: ImportStatePayload<S, A>;\n}\n\nexport type ListenerMessage<S, A extends Action<string>> =\n  | StartAction\n  | StopAction\n  | DispatchAction\n  | ImportAction\n  | ActionAction\n  | ExportAction\n  | UpdateAction\n  | OptionsAction\n  | ImportStateDispatchAction<S, A>;\n\nfunction postToPageScript(message: ContentScriptToPageScriptMessage) {\n  window.postMessage(message, '*');\n}\n\nfunction connect() {\n  // Connect to the background script\n  connected = true;\n  const name = 'tab';\n  if (window.devToolsExtensionID) {\n    bg = chrome.runtime.connect(window.devToolsExtensionID, { name });\n  } else {\n    bg = chrome.runtime.connect({ name });\n  }\n\n  // Relay background script messages to the page script\n  bg.onMessage.addListener((message: TabMessage) => {\n    if ('action' in message) {\n      if (message.type === 'DISPATCH') {\n        postToPageScript({\n          type: message.type,\n          payload: message.action,\n          state: message.state,\n          id: message.id,\n          source,\n        });\n      } else if (message.type === 'ACTION') {\n        postToPageScript({\n          type: message.type,\n          payload: message.action,\n          state: message.state,\n          id: message.id,\n          source,\n        });\n      } else {\n        postToPageScript({\n          type: message.type,\n          payload: message.action,\n          state: message.state,\n          id: message.id,\n          source,\n        });\n      }\n    } else if (message.type === 'OPTIONS') {\n      postToPageScript({\n        type: message.type,\n        options: prepareOptionsForPage(message.options),\n        id: undefined,\n        source,\n      });\n    } else {\n      postToPageScript({\n        type: message.type,\n        state: message.state,\n        id: message.id,\n        source,\n      });\n    }\n  });\n\n  bg.onDisconnect.addListener(handleDisconnect);\n}\n\nfunction handleDisconnect() {\n  window.removeEventListener('message', handleMessages);\n  window.postMessage({ type: 'STOP', failed: true, source }, '*');\n  bg = undefined;\n}\n\ninterface SplitMessageBase {\n  readonly type?: never;\n}\n\ninterface SplitMessageStart extends SplitMessageBase {\n  readonly instanceId: number;\n  readonly source: typeof pageSource;\n  readonly split: 'start';\n}\n\ninterface SplitMessageChunk extends SplitMessageBase {\n  readonly instanceId: number;\n  readonly source: typeof pageSource;\n  readonly split: 'chunk';\n  readonly chunk: [string, string];\n}\n\ninterface SplitMessageEnd extends SplitMessageBase {\n  readonly instanceId: number;\n  readonly source: typeof pageSource;\n  readonly split: 'end';\n}\n\nexport type SplitMessage =\n  | SplitMessageStart\n  | SplitMessageChunk\n  | SplitMessageEnd;\n\nfunction tryCatch<S, A extends Action<string>>(\n  fn: (\n    args:\n      | PageScriptToContentScriptMessageWithoutDisconnect<S, A>\n      | SplitMessage,\n  ) => void,\n  args: PageScriptToContentScriptMessageWithoutDisconnect<S, A>,\n) {\n  try {\n    return fn(args);\n  } catch (err) {\n    if (\n      (err as Error).message ===\n      'Message length exceeded maximum allowed length.'\n    ) {\n      const instanceId = (args as any).instanceId;\n      const newArgs = {\n        split: 'start',\n      };\n      const toSplit: [string, string][] = [];\n      let size = 0;\n      let arg;\n      Object.keys(args).map((key) => {\n        arg = args[key as keyof typeof args];\n        if (typeof arg === 'string') {\n          size += arg.length;\n          if (size > maxChromeMsgSize) {\n            toSplit.push([key, arg]);\n            return;\n          }\n        }\n        newArgs[key as keyof typeof newArgs] = arg;\n      });\n      fn(newArgs as SplitMessage);\n      for (let i = 0; i < toSplit.length; i++) {\n        for (let j = 0; j < toSplit[i][1].length; j += maxChromeMsgSize) {\n          fn({\n            instanceId,\n            source: pageSource,\n            split: 'chunk',\n            chunk: [toSplit[i][0], toSplit[i][1].substr(j, maxChromeMsgSize)],\n          });\n        }\n      }\n      return fn({ instanceId, source: pageSource, split: 'end' });\n    }\n    handleDisconnect();\n    /* eslint-disable no-console */\n    if (process.env.NODE_ENV !== 'production') {\n      console.error('Failed to send message', err);\n    }\n    /* eslint-enable no-console */\n  }\n}\n\ninterface InitInstanceContentScriptToBackgroundMessage {\n  readonly name: 'INIT_INSTANCE';\n  readonly instanceId: number;\n}\n\ninterface RelayMessage<S, A extends Action<string>> {\n  readonly name: 'RELAY';\n  readonly message:\n    | PageScriptToContentScriptMessageWithoutDisconnectOrInitInstance<S, A>\n    | SplitMessage;\n}\n\nexport type ContentScriptToBackgroundMessage<S, A extends Action<string>> =\n  | InitInstanceContentScriptToBackgroundMessage\n  | RelayMessage<S, A>;\n\nfunction postToBackground<S, A extends Action<string>>(\n  message: ContentScriptToBackgroundMessage<S, A>,\n) {\n  bg!.postMessage(message);\n}\n\nfunction send<S, A extends Action<string>>(\n  message:\n    | PageScriptToContentScriptMessageWithoutDisconnect<S, A>\n    | SplitMessage,\n) {\n  if (!connected) connect();\n  if (message.type === 'INIT_INSTANCE') {\n    getOptions((options) => {\n      postToPageScript({\n        type: 'OPTIONS',\n        options: prepareOptionsForPage(options),\n        id: undefined,\n        source,\n      });\n    });\n    postToBackground({ name: 'INIT_INSTANCE', instanceId: message.instanceId });\n  } else {\n    postToBackground({ name: 'RELAY', message });\n  }\n}\n\n// Resend messages from the page to the background script\nfunction handleMessages<S, A extends Action<string>>(\n  event: MessageEvent<PageScriptToContentScriptMessage<S, A>>,\n) {\n  if (!isAllowed()) return;\n  if (!event || event.source !== window || typeof event.data !== 'object') {\n    return;\n  }\n  const message = event.data;\n  if (message.source !== pageSource) return;\n  if (message.type === 'DISCONNECT') {\n    if (bg) {\n      bg.disconnect();\n      connected = false;\n    }\n    return;\n  }\n\n  tryCatch(send, message);\n}\n\nprefetchOptions();\n\nwindow.addEventListener('message', handleMessages, false);\n"
  },
  {
    "path": "extension/src/devpanel/devpanel.pug",
    "content": "doctype html\r\n\r\nhtml\r\n  head\r\n    meta(charset='UTF-8')\r\n  title Redux DevTools\r\n  include ../style.pug\r\n\r\n  body\r\n    #root\r\n      div(style='display: flex; justify-content: center; align-items: center')\r\n        img(\r\n          src='/img/loading.svg',\r\n          height=300, width=350,\r\n        )\r\n    link(href='/devpanel.bundle.css', rel='stylesheet')\r\n    script(src='/devpanel.bundle.js')\r\n"
  },
  {
    "path": "extension/src/devpanel/index.tsx",
    "content": "import '../chromeApiMock.js';\nimport React, { CSSProperties, ReactNode } from 'react';\nimport { createRoot, Root } from 'react-dom/client';\nimport { Provider } from 'react-redux';\nimport { Persistor } from 'redux-persist';\nimport {\n  REMOVE_INSTANCE,\n  StoreAction,\n  StoreState,\n  UPDATE_STATE,\n} from '@redux-devtools/app';\nimport App from '../app/App.js';\nimport configureStore from './store/panelStore.js';\n\nimport { Action, Store } from 'redux';\nimport {\n  PanelMessageWithoutNA,\n  PanelMessageWithSplitAction,\n  SplitUpdateStateRequest,\n  UpdateStateRequest,\n} from '../background/store/apiMiddleware.js';\nimport { PersistGate } from 'redux-persist/integration/react';\n\nconst position = location.hash;\nconst messageStyle: CSSProperties = {\n  paddingTop: '20px',\n  width: '100%',\n  textAlign: 'center',\n  boxSizing: 'border-box',\n};\n\nlet rendered: boolean | undefined;\nlet currentRoot: Root | undefined;\nlet store: Store<StoreState, StoreAction> | undefined;\nlet persistor: Persistor | undefined;\nlet bgConnection: chrome.runtime.Port;\nlet naTimeout: NodeJS.Timeout;\n\nconst isChrome = !navigator.userAgent.includes('Firefox');\n\nfunction renderNodeAtRoot(node: ReactNode) {\n  if (currentRoot) currentRoot.unmount();\n  currentRoot = createRoot(document.getElementById('root')!);\n  currentRoot.render(node);\n}\n\nfunction renderDevTools() {\n  clearTimeout(naTimeout);\n  ({ store, persistor } = configureStore(position, bgConnection));\n  renderNodeAtRoot(\n    <Provider store={store}>\n      <PersistGate loading={null} persistor={persistor}>\n        <App position={position} />\n      </PersistGate>\n    </Provider>,\n  );\n  rendered = true;\n}\n\nfunction renderNA() {\n  if (rendered === false) return;\n  rendered = false;\n  naTimeout = setTimeout(() => {\n    let message = (\n      <div style={messageStyle}>\n        No store found. Make sure to follow{' '}\n        <a\n          href=\"https://github.com/zalmoxisus/redux-devtools-extension#usage\"\n          target=\"_blank\"\n          rel=\"noreferrer\"\n        >\n          the instructions\n        </a>\n        .\n      </div>\n    );\n    if (\n      isChrome &&\n      chrome &&\n      chrome.devtools &&\n      chrome.devtools.inspectedWindow\n    ) {\n      chrome.devtools.inspectedWindow.getResources((resources) => {\n        if (resources[0].url.substr(0, 4) === 'file') {\n          message = (\n            <div style={messageStyle}>\n              No store found. Most likely you did not allow access to file URLs.{' '}\n              <a\n                href=\"https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/Troubleshooting.md#access-file-url-file\"\n                target=\"_blank\"\n                rel=\"noreferrer\"\n              >\n                See details\n              </a>\n              .\n            </div>\n          );\n        }\n\n        renderNodeAtRoot(message);\n        store = undefined;\n      });\n    } else {\n      renderNodeAtRoot(message);\n      store = undefined;\n    }\n  }, 3500);\n}\n\nlet splitMessage: SplitUpdateStateRequest<unknown, Action<string>>;\n\nfunction init() {\n  renderNA();\n\n  let name = 'monitor';\n  if (chrome && chrome.devtools && chrome.devtools.inspectedWindow) {\n    name += chrome.devtools.inspectedWindow.tabId;\n  }\n  bgConnection = chrome.runtime.connect({ name });\n\n  bgConnection.onMessage.addListener(\n    <S, A extends Action<string>>(\n      message: PanelMessageWithSplitAction<S, A>,\n    ) => {\n      if (message.type === 'NA') {\n        // TODO Double-check this now that the name is different\n        if (message.id === name) renderNA();\n        else store!.dispatch({ type: REMOVE_INSTANCE, id: message.id });\n      } else {\n        if (!rendered) renderDevTools();\n\n        if (\n          message.type === UPDATE_STATE &&\n          (message.request as SplitUpdateStateRequest<S, A>).split\n        ) {\n          const request = message.request as SplitUpdateStateRequest<S, A>;\n\n          if (request.split === 'start') {\n            splitMessage = request;\n            return;\n          }\n\n          if (request.split === 'chunk') {\n            if (\n              (splitMessage as unknown as Record<string, string>)[\n                request.chunk[0]\n              ]\n            ) {\n              (splitMessage as unknown as Record<string, string>)[\n                request.chunk[0]\n              ] += request.chunk[1];\n            } else {\n              (splitMessage as unknown as Record<string, string>)[\n                request.chunk[0]\n              ] = request.chunk[1];\n            }\n            return;\n          }\n\n          if (request.split === 'end') {\n            store!.dispatch({\n              ...message,\n              request: splitMessage as UpdateStateRequest<S, A>,\n            });\n            return;\n          }\n\n          throw new Error(\n            `Unable to process split message with type: ${(request as any).split}`,\n          );\n        } else {\n          store!.dispatch(message as PanelMessageWithoutNA<S, A>);\n        }\n      }\n    },\n  );\n}\n\nif (position === '#popup') document.body.style.minWidth = '760px';\nif (position !== '#popup') document.body.style.minHeight = '100%';\n\ninit();\n"
  },
  {
    "path": "extension/src/devpanel/store/panelReducer.ts",
    "content": "import { combineReducers, Reducer } from 'redux';\nimport {\n  connection,\n  instances,\n  monitor,\n  notification,\n  reports,\n  section,\n  socket,\n  stateTreeSettings,\n  StoreAction,\n  StoreState,\n  theme,\n} from '@redux-devtools/app';\n\nconst rootReducer: Reducer<\n  StoreState,\n  StoreAction,\n  Partial<StoreState>\n> = combineReducers({\n  instances,\n  monitor,\n  reports,\n  notification,\n  section,\n  socket,\n  theme,\n  connection,\n  stateTreeSettings,\n}) as any;\n\nexport default rootReducer;\n"
  },
  {
    "path": "extension/src/devpanel/store/panelStore.ts",
    "content": "import { createStore, applyMiddleware, Reducer, Store } from 'redux';\nimport localForage from 'localforage';\nimport { persistReducer, persistStore } from 'redux-persist';\nimport {\n  exportStateMiddleware,\n  StoreAction,\n  StoreState,\n} from '@redux-devtools/app';\nimport panelDispatcher from './panelSyncMiddleware.js';\nimport rootReducer from './panelReducer.js';\n\nconst persistConfig = {\n  key: 'redux-devtools',\n  blacklist: ['instances', 'socket'],\n  storage: localForage,\n};\n\nconst persistedReducer: Reducer<StoreState, StoreAction> = persistReducer(\n  persistConfig,\n  rootReducer,\n) as any;\n\nexport default function configureStore(\n  position: string,\n  bgConnection: chrome.runtime.Port,\n) {\n  const enhancer = applyMiddleware(\n    exportStateMiddleware,\n    panelDispatcher(bgConnection),\n  );\n  const store = createStore(persistedReducer, enhancer);\n  const persistor = persistStore(store as Store);\n  return { store, persistor };\n}\n"
  },
  {
    "path": "extension/src/devpanel/store/panelSyncMiddleware.ts",
    "content": "import {\n  getActiveInstance,\n  LIFTED_ACTION,\n  SELECT_INSTANCE,\n  StoreAction,\n  StoreState,\n  TOGGLE_PERSIST,\n  UPDATE_STATE,\n} from '@redux-devtools/app';\nimport { Dispatch, Middleware, MiddlewareAPI } from 'redux';\n\nfunction selectInstance(\n  tabId: number,\n  store: MiddlewareAPI<Dispatch<StoreAction>, StoreState>,\n  next: (action: unknown) => unknown,\n) {\n  const instances = store.getState().instances;\n  if (instances.current === 'default') return;\n  const connections = instances.connections[tabId];\n  if (connections && connections.length === 1) {\n    next({ type: SELECT_INSTANCE, selected: connections[0] });\n  }\n}\n\nfunction getCurrentTabId(next: (tabId: number) => void) {\n  chrome.tabs.query(\n    {\n      active: true,\n      lastFocusedWindow: true,\n    },\n    (tabs) => {\n      const tab = tabs[0];\n      if (!tab) return;\n      next(tab.id!);\n    },\n  );\n}\n\nfunction panelDispatcher(\n  bgConnection: chrome.runtime.Port,\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n): Middleware<{}, StoreState, Dispatch<StoreAction>> {\n  let autoselected = false;\n\n  return (store) => (next) => (untypedAction) => {\n    const action = untypedAction as StoreAction;\n\n    const result = next(action);\n    if (!autoselected && action.type === UPDATE_STATE) {\n      autoselected = true;\n\n      if (chrome.devtools && chrome.devtools.inspectedWindow) {\n        selectInstance(chrome.devtools.inspectedWindow.tabId, store, next);\n      } else {\n        getCurrentTabId((tabId) => selectInstance(tabId, store, next));\n      }\n    }\n    if (action.type === LIFTED_ACTION || action.type === TOGGLE_PERSIST) {\n      const instances = store.getState().instances;\n      const instanceId = getActiveInstance(instances);\n      const id = instances.options[instanceId].connectionId;\n      bgConnection.postMessage({ ...action, instanceId, id });\n    }\n    return result;\n  };\n}\n\nexport default panelDispatcher;\n"
  },
  {
    "path": "extension/src/devtools/devtools.pug",
    "content": "doctype html\r\n\r\nhtml\r\n    head\r\n        meta(charset='UTF-8')\r\n    title Redux DevTools\r\n\r\n    body\r\n        #root\r\n        script(src='/devtools.bundle.js')\r\n"
  },
  {
    "path": "extension/src/devtools/index.ts",
    "content": "chrome.devtools.panels.create(\n  'Redux',\n  'img/logo/scalable.png',\n  'devpanel.html',\n  () => {\n    // do nothing.\n  },\n);\n"
  },
  {
    "path": "extension/src/options/AllowToRunGroup.tsx",
    "content": "import React from 'react';\nimport { OptionsProps } from './Options.js';\n\nexport default function AllowToRunGroup({ options, saveOption }: OptionsProps) {\n  const AllowToRunState = {\n    EVERYWHERE: true,\n    ON_SPECIFIC_URLS: false,\n  };\n\n  return (\n    <fieldset className=\"option-group\">\n      <legend className=\"option-group__title\">Allow to run</legend>\n\n      <div className=\"option option_type_radio\">\n        <input\n          className=\"option__element\"\n          id=\"inject-always\"\n          name=\"inject\"\n          type=\"radio\"\n          checked={options.inject === AllowToRunState.EVERYWHERE}\n          onChange={() => saveOption('inject', AllowToRunState.EVERYWHERE)}\n        />\n        <label className=\"option__label\" htmlFor=\"inject-always\">\n          Everywhere\n        </label>\n      </div>\n\n      <div className=\"option option_type_radio\">\n        <input\n          className=\"option__element\"\n          id=\"inject-specific\"\n          name=\"inject\"\n          type=\"radio\"\n          checked={options.inject === AllowToRunState.ON_SPECIFIC_URLS}\n          onChange={() =>\n            saveOption('inject', AllowToRunState.ON_SPECIFIC_URLS)\n          }\n        />\n        <label className=\"option__label\" htmlFor=\"inject-specific\">\n          Only on the following URLs:\n        </label>\n        <br />\n        <textarea\n          className=\"option__textarea\"\n          value={options.urls}\n          disabled={options.inject !== AllowToRunState.ON_SPECIFIC_URLS}\n          onChange={(e) => saveOption('urls', e.target.value)}\n        />\n        <div className=\"option__hint\">Each RegExp from the new line</div>\n      </div>\n    </fieldset>\n  );\n}\n"
  },
  {
    "path": "extension/src/options/ContextMenuGroup.tsx",
    "content": "import React from 'react';\nimport { OptionsProps } from './Options.js';\n\nexport default function ContextMenuGroup({\n  options,\n  saveOption,\n}: OptionsProps) {\n  return (\n    <fieldset className=\"option-group\">\n      <legend className=\"option-group__title\">Context Menu</legend>\n\n      <div className=\"option option_type_checkbox\">\n        <input\n          className=\"option__element\"\n          id=\"showContextMenus\"\n          type=\"checkbox\"\n          checked={options.showContextMenus}\n          onChange={(e) => saveOption('showContextMenus', e.target.checked)}\n        />\n        <label className=\"option__label\" htmlFor=\"showContextMenus\">\n          Add Context Menus\n        </label>\n        <div className=\"option__hint\">\n          Add Redux DevTools to right-click context menu\n        </div>\n      </div>\n    </fieldset>\n  );\n}\n"
  },
  {
    "path": "extension/src/options/EditorGroup.tsx",
    "content": "import React from 'react';\nimport { OptionsProps } from './Options.js';\n\nexport default function EditorGroup({ options, saveOption }: OptionsProps) {\n  const EditorState = {\n    BROWSER: 0,\n    EXTERNAL: 1,\n  };\n\n  return (\n    <fieldset className=\"option-group\">\n      <legend className=\"option-group__title\">Editor for stack traces</legend>\n\n      <div className=\"option option_type_radio\">\n        <input\n          className=\"option__element\"\n          id=\"editor-browser\"\n          name=\"useEditor\"\n          type=\"radio\"\n          checked={options.useEditor === EditorState.BROWSER}\n          onChange={() => saveOption('useEditor', EditorState.BROWSER)}\n        />\n        <label className=\"option__label\" htmlFor=\"editor-browser\">\n          {navigator.userAgent.includes('Firefox')\n            ? \"Don't open in external editor\"\n            : \"Use browser's debugger (from browser devpanel only)\"}\n        </label>\n      </div>\n\n      <div\n        className=\"option option_type_radio\"\n        style={{ display: 'flex', alignItems: 'center' }}\n      >\n        <input\n          className=\"option__element\"\n          id=\"editor-external\"\n          name=\"useEditor\"\n          type=\"radio\"\n          checked={options.useEditor === EditorState.EXTERNAL}\n          onChange={() => saveOption('useEditor', EditorState.EXTERNAL)}\n        />\n        <label className=\"option__label\" htmlFor=\"editor-external\">\n          External editor:&nbsp;\n        </label>\n        <input\n          className=\"option__element\"\n          id=\"editor\"\n          type=\"text\"\n          size={33}\n          maxLength={30}\n          placeholder=\"vscode, atom, webstorm, sublime...\"\n          value={options.editor}\n          disabled={options.useEditor !== EditorState.EXTERNAL}\n          onChange={(e) =>\n            saveOption('editor', e.target.value.replace(/\\W/g, ''))\n          }\n        />\n      </div>\n      <div className=\"option option_type_radio\">\n        <label\n          className=\"option__label\"\n          htmlFor=\"editor-external\"\n          style={{ marginLeft: '20px' }}\n        >\n          Absolute path to the project directory to open:\n        </label>\n        <br />\n        <textarea\n          className=\"option__textarea\"\n          placeholder=\"/home/user/my-awesome-app\"\n          value={options.projectPath}\n          disabled={options.useEditor !== EditorState.EXTERNAL}\n          onChange={(e) =>\n            saveOption('projectPath', e.target.value.replace('\\n', ''))\n          }\n        />\n        <div className=\"option__hint\">\n          Run `pwd` in your project root directory to get it\n        </div>\n      </div>\n    </fieldset>\n  );\n}\n"
  },
  {
    "path": "extension/src/options/FilterGroup.tsx",
    "content": "import React from 'react';\nimport { FilterState } from '../pageScript/api/filters.js';\nimport { OptionsProps } from './Options.js';\n\nexport default function FilterGroup({ options, saveOption }: OptionsProps) {\n  return (\n    <fieldset className=\"option-group\">\n      <legend className=\"option-group__title\">\n        Filter actions in DevTools\n      </legend>\n\n      <div className=\"option option_type_radio\">\n        <input\n          className=\"option__element\"\n          id=\"filter-do-not\"\n          name=\"filter\"\n          type=\"radio\"\n          checked={options.filter === FilterState.DO_NOT_FILTER}\n          onChange={() => saveOption('filter', FilterState.DO_NOT_FILTER)}\n        />\n        <label className=\"option__label\" htmlFor=\"filter-do-not\">\n          Don’t filter\n        </label>\n      </div>\n\n      <div className=\"option option_type_radio\">\n        <input\n          className=\"option__element\"\n          id=\"filter-hide\"\n          name=\"filter\"\n          type=\"radio\"\n          checked={options.filter === FilterState.DENYLIST_SPECIFIC}\n          onChange={() => saveOption('filter', FilterState.DENYLIST_SPECIFIC)}\n        />\n        <label className=\"option__label\" htmlFor=\"filter-hide\">\n          Hide the following:\n        </label>\n        <br />\n        <textarea\n          className=\"option__textarea\"\n          value={options.denylist}\n          disabled={options.filter !== FilterState.DENYLIST_SPECIFIC}\n          onChange={(e) => saveOption('denylist', e.target.value)}\n        />\n        <div className=\"option__hint\">Each action from the new line</div>\n      </div>\n\n      <div className=\"option option_type_radio\">\n        <input\n          className=\"option__element\"\n          id=\"filter-show\"\n          name=\"filter\"\n          type=\"radio\"\n          checked={options.filter === FilterState.ALLOWLIST_SPECIFIC}\n          onChange={() => saveOption('filter', FilterState.ALLOWLIST_SPECIFIC)}\n        />\n        <label className=\"option__label\" htmlFor=\"filter-show\">\n          Show the following:\n        </label>\n        <br />\n        <textarea\n          className=\"option__textarea\"\n          value={options.allowlist}\n          disabled={options.filter !== FilterState.ALLOWLIST_SPECIFIC}\n          onChange={(e) => saveOption('allowlist', e.target.value)}\n        />\n        <div className=\"option__hint\">Each action from the new line</div>\n      </div>\n    </fieldset>\n  );\n}\n"
  },
  {
    "path": "extension/src/options/MiscellaneousGroup.tsx",
    "content": "import React from 'react';\nimport { OptionsProps } from './Options.js';\n\nexport default function MiscellaneousGroup({\n  options,\n  saveOption,\n}: OptionsProps) {\n  return (\n    <fieldset className=\"option-group\">\n      <legend className=\"option-group__title\">Miscellaneous</legend>\n\n      <div className=\"option option_value_max-age\">\n        <label className=\"option__label\" htmlFor=\"maxAge\">\n          Limit the action history to\n        </label>{' '}\n        <input\n          className=\"option__element\"\n          id=\"maxAge\"\n          type=\"number\"\n          min=\"2\"\n          value={options.maxAge}\n          onChange={(e) => saveOption('maxAge', Number(e.target.value))}\n        />{' '}\n        <label className=\"option__label\" htmlFor=\"maxAge\">\n          items\n        </label>\n        <div className=\"option__hint\">\n          When the number is reached, DevTools start removing the oldest\n          actions. Improves the DevTools performance.{' '}\n          <a href=\"https://github.com/zalmoxisus/redux-devtools-extension/pull/54#issuecomment-188167725\">\n            More info\n          </a>\n        </div>\n      </div>\n\n      <div className=\"option option_type_checkbox\">\n        <input\n          className=\"option__element\"\n          id=\"notifyErrors\"\n          type=\"checkbox\"\n          checked={options.shouldCatchErrors}\n          onChange={(e) => saveOption('shouldCatchErrors', e.target.checked)}\n        />\n        <label className=\"option__label\" htmlFor=\"notifyErrors\">\n          Show errors\n        </label>\n        <div className=\"option__hint\">\n          Show the browser notifications when errors occur in the app\n        </div>\n      </div>\n    </fieldset>\n  );\n}\n"
  },
  {
    "path": "extension/src/options/Options.tsx",
    "content": "import React from 'react';\nimport EditorGroup from './EditorGroup.js';\nimport FilterGroup from './FilterGroup.js';\nimport AllowToRunGroup from './AllowToRunGroup.js';\nimport MiscellaneousGroup from './MiscellaneousGroup.js';\nimport ContextMenuGroup from './ContextMenuGroup.js';\nimport { Options } from './syncOptions.js';\n\nexport interface OptionsProps {\n  readonly options: Options;\n  readonly saveOption: <K extends keyof Options>(\n    name: K,\n    value: Options[K],\n  ) => void;\n}\n\nexport default function OptionsComponent(props: OptionsProps) {\n  return (\n    <div>\n      <EditorGroup {...props} />\n      <FilterGroup {...props} />\n      <AllowToRunGroup {...props} />\n      <MiscellaneousGroup {...props} />\n      <ContextMenuGroup {...props} />\n      <div style={{ color: 'red' }}>\n        <br />\n        <hr />\n        Setting options here is discouraged, and will not be possible in the\n        next major release. Please{' '}\n        <a\n          href=\"https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md\"\n          target=\"_blank\"\n          rel=\"noreferrer\"\n          style={{ color: 'red' }}\n        >\n          specify them as parameters\n        </a>\n        . See{' '}\n        <a\n          href=\"https://github.com/zalmoxisus/redux-devtools-extension/issues/296\"\n          target=\"_blank\"\n          rel=\"noreferrer\"\n          style={{ color: 'red' }}\n        >\n          the issue\n        </a>{' '}\n        for more details.\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "extension/src/options/index.tsx",
    "content": "import '../chromeApiMock.js';\nimport React from 'react';\nimport { createRoot } from 'react-dom/client';\nimport OptionsComponent from './Options.js';\nimport {\n  getOptions,\n  Options,\n  OptionsMessage,\n  saveOption,\n  subscribeToOptions,\n} from './syncOptions.js';\n\nsubscribeToOptions((options) => {\n  const message: OptionsMessage = { type: 'OPTIONS', options };\n  void chrome.runtime.sendMessage(message);\n});\n\nconst renderOptions = (options: Options) => {\n  const root = createRoot(document.getElementById('root')!);\n  root.render(<OptionsComponent options={options} saveOption={saveOption} />);\n};\n\nsubscribeToOptions(renderOptions);\ngetOptions((options) => {\n  renderOptions(options);\n});\n"
  },
  {
    "path": "extension/src/options/options.pug",
    "content": "doctype html\r\n\r\nhtml\r\n  head\r\n    meta(charset='UTF-8')\r\n  title Redux DevTools Options\r\n  style.\r\n    body {\r\n      padding: 2px;\r\n      min-width: 380px;\r\n    }\r\n\r\n    .option-group {\r\n      /* Reset the default fieldset styles */\r\n      margin: initial;\r\n      border: initial;\r\n      padding: initial;\r\n    }\r\n\r\n    .option-group + .option-group {\r\n      margin-top: 30px;\r\n    }\r\n\r\n    .option-group__title {\r\n      /* Reset the default legend styles */\r\n      margin: initial;\r\n      padding: initial;\r\n\r\n      margin-bottom: 8px;\r\n      font-weight: bold;\r\n      font-size: 30px;\r\n    }\r\n\r\n    .option + .option {\r\n      margin-top: 5px;\r\n    }\r\n\r\n    .option__textarea {\r\n      margin-top: 2px;\r\n      width: 300px;\r\n      min-height: 50px;\r\n    }\r\n\r\n    .option__hint {\r\n      margin-top: 2px;\r\n      font-size: 10px;\r\n    }\r\n\r\n    .option__textarea + .option__hint {\r\n      margin-top: -2px;\r\n    }\r\n\r\n    /* Checkbox and radio styling */\r\n    .option_type_checkbox .option__element,\r\n    .option_type_radio .option__element {\r\n      vertical-align: bottom;\r\n    }\r\n\r\n    .option_type_checkbox .option__label,\r\n    .option_type_radio .option__label {\r\n      margin-left: 4px;\r\n    }\r\n\r\n    .option_type_checkbox .option__textarea,\r\n    .option_type_checkbox .option__hint,\r\n    .option_type_radio .option__textarea,\r\n    .option_type_radio .option__hint {\r\n      margin-left: 20px;\r\n    }\r\n\r\n\r\n    /* Checkbox styling */\r\n    .option_type_checkbox .option__element {\r\n      /* Checkboxes in Chrome are 2px narrower than radio buttons.\r\n         These margins align them. */\r\n      margin-left: 1px;\r\n      /* ...margin-right is 2px instead of 1px\r\n         because both radios and checkboxes have initial margin-right of 1px */\r\n      margin-right: 2px;\r\n    }\r\n\r\n    /* Value-based styling */\r\n    .option_value_max-age {\r\n      margin-left: 20px;\r\n    }\r\n\r\n    .option_value_max-age .option__element {\r\n      width: 50px;\r\n    }\r\n\r\n  body\r\n    #root\r\n    script(src='/options.bundle.js')\r\n"
  },
  {
    "path": "extension/src/options/syncOptions.ts",
    "content": "import { FilterState, FilterStateValue } from '../pageScript/api/filters.js';\n\nexport interface Options {\n  readonly useEditor: number;\n  readonly editor: string;\n  readonly projectPath: string;\n  readonly maxAge: number;\n  readonly filter: FilterStateValue;\n  readonly allowlist: string;\n  readonly denylist: string;\n  readonly shouldCatchErrors: boolean;\n  readonly inject: boolean;\n  readonly urls: string;\n  readonly showContextMenus: boolean;\n}\n\ninterface OldOrNewOptions {\n  readonly useEditor: number;\n  readonly editor: string;\n  readonly projectPath: string;\n  readonly maxAge: number;\n  readonly filter:\n    | FilterStateValue\n    | 'WHITELIST_SPECIFIC'\n    | 'BLACKLIST_SPECIFIC'\n    | boolean;\n  readonly allowlist: string;\n  readonly denylist: string;\n  readonly whitelist: string;\n  readonly blacklist: string;\n  readonly shouldCatchErrors: boolean;\n  readonly inject: boolean;\n  readonly urls: string;\n  readonly showContextMenus: boolean;\n}\n\nlet options: Options | undefined;\nlet subscribers: ((options: Options) => void)[] = [];\n\nexport interface OptionsMessage {\n  readonly type: 'OPTIONS';\n  readonly options: Options;\n}\n\nexport const saveOption = <K extends keyof Options>(\n  key: K,\n  value: Options[K],\n) => {\n  const obj: { [K1 in keyof Options]?: Options[K1] } = {};\n  obj[key] = value;\n  void chrome.storage.sync.set(obj);\n  options![key] = value;\n  for (const subscriber of subscribers) {\n    subscriber(options!);\n  }\n};\n\nconst migrateOldOptions = (oldOptions: OldOrNewOptions): Options => ({\n  ...oldOptions,\n  filter:\n    // Migrate the old `filter` option from 2.2.1\n    typeof oldOptions.filter === 'boolean'\n      ? oldOptions.filter && oldOptions.whitelist.length > 0\n        ? FilterState.ALLOWLIST_SPECIFIC\n        : oldOptions.filter\n          ? FilterState.DENYLIST_SPECIFIC\n          : FilterState.DO_NOT_FILTER\n      : oldOptions.filter === 'WHITELIST_SPECIFIC'\n        ? FilterState.ALLOWLIST_SPECIFIC\n        : oldOptions.filter === 'BLACKLIST_SPECIFIC'\n          ? FilterState.DENYLIST_SPECIFIC\n          : oldOptions.filter,\n});\n\nexport const getOptions = (callback: (options: Options) => void) => {\n  if (options) callback(options);\n  else {\n    chrome.storage.sync.get<OldOrNewOptions>(\n      {\n        useEditor: 0,\n        editor: '',\n        projectPath: '',\n        maxAge: 50,\n        filter: FilterState.DO_NOT_FILTER,\n        whitelist: '',\n        blacklist: '',\n        allowlist: '',\n        denylist: '',\n        shouldCatchErrors: false,\n        inject: true,\n        urls: '^https?://localhost|0\\\\.0\\\\.0\\\\.0:\\\\d+\\n^https?://.+\\\\.github\\\\.io',\n        showContextMenus: true,\n      },\n      function (items) {\n        options = migrateOldOptions(items);\n        callback(options);\n      },\n    );\n  }\n};\n\nexport const prefetchOptions = () =>\n  getOptions(() => {\n    // do nothing.\n  });\n\nexport const subscribeToOptions = (callback: (options: Options) => void) => {\n  subscribers = subscribers.concat(callback);\n};\n\nconst toReg = (str: string) =>\n  str !== '' ? str.split('\\n').filter(Boolean).join('|') : null;\n\nexport const prepareOptionsForPage = (options: Options): Options => ({\n  ...options,\n  allowlist:\n    options.filter !== FilterState.DO_NOT_FILTER\n      ? toReg(options.allowlist)!\n      : options.allowlist,\n  denylist:\n    options.filter !== FilterState.DO_NOT_FILTER\n      ? toReg(options.denylist)!\n      : options.denylist,\n});\n\nexport const isAllowed = (localOptions = options) =>\n  !localOptions ||\n  localOptions.inject ||\n  !localOptions.urls ||\n  location.href.match(toReg(localOptions.urls)!);\n"
  },
  {
    "path": "extension/src/pageScript/Monitor.ts",
    "content": "import { Action } from 'redux';\nimport { LiftedState } from '@redux-devtools/instrument';\nimport { DispatchAction, LibConfig } from '@redux-devtools/app';\n\ndeclare global {\n  interface Window {\n    __REDUX_DEVTOOLS_EXTENSION_LOCKED__?: boolean;\n  }\n}\n\nexport default class Monitor<S, A extends Action<string>> {\n  update: (\n    liftedState?: LiftedState<S, A, unknown> | undefined,\n    libConfig?: LibConfig,\n  ) => void;\n  active?: boolean;\n  paused?: boolean;\n  lastAction?: string;\n  waitingTimeout?: number;\n\n  constructor(\n    update: (\n      liftedState?: LiftedState<S, A, unknown> | undefined,\n      libConfig?: LibConfig,\n    ) => void,\n  ) {\n    this.update = update;\n  }\n  reducer = (state = {}, action: DispatchAction) => {\n    if (!this.active) return state;\n    this.lastAction = action.type;\n    if (action.type === 'LOCK_CHANGES') {\n      window.__REDUX_DEVTOOLS_EXTENSION_LOCKED__ = action.status;\n    } else if (action.type === 'PAUSE_RECORDING') {\n      this.paused = action.status;\n    } else if (this.isHotReloaded()) {\n      // Send new lifted state on hot-reloading\n      setTimeout(this.update, 0);\n    }\n    return state;\n  };\n  start = (skipUpdate: boolean) => {\n    this.active = true;\n    if (!skipUpdate) this.update();\n  };\n  stop = () => {\n    this.active = false;\n    clearTimeout(this.waitingTimeout);\n  };\n  isHotReloaded = () =>\n    this.lastAction && /^@@redux\\/(INIT|REPLACE)/.test(this.lastAction);\n  isMonitorAction = () =>\n    this.lastAction && this.lastAction !== 'PERFORM_ACTION';\n  isTimeTraveling = () =>\n    this.lastAction === 'JUMP_TO_STATE' || this.lastAction === 'JUMP_TO_ACTION';\n  isPaused = () => {\n    if (this.paused) {\n      if (this.lastAction !== 'BLOCKED') {\n        if (!window.__REDUX_DEVTOOLS_EXTENSION_LOCKED__) {\n          this.lastAction = 'BLOCKED';\n        }\n        return false;\n      }\n      return true;\n    }\n    return false;\n  };\n  isLocked = () => {\n    if (window.__REDUX_DEVTOOLS_EXTENSION_LOCKED__) {\n      if (this.lastAction !== 'BLOCKED') {\n        this.lastAction = 'BLOCKED';\n        return false;\n      }\n      return true;\n    }\n    return false;\n  };\n}\n"
  },
  {
    "path": "extension/src/pageScript/api/filters.ts",
    "content": "import { Action } from 'redux';\nimport { LiftedState, PerformAction } from '@redux-devtools/instrument';\nimport { LocalFilter } from '@redux-devtools/utils';\n\nexport type FilterStateValue =\n  | 'DO_NOT_FILTER'\n  | 'DENYLIST_SPECIFIC'\n  | 'ALLOWLIST_SPECIFIC';\n\nexport const FilterState: { [K in FilterStateValue]: FilterStateValue } = {\n  DO_NOT_FILTER: 'DO_NOT_FILTER',\n  DENYLIST_SPECIFIC: 'DENYLIST_SPECIFIC',\n  ALLOWLIST_SPECIFIC: 'ALLOWLIST_SPECIFIC',\n};\n\nexport const noFiltersApplied = (localFilter: LocalFilter | undefined) =>\n  // !predicate &&\n  !localFilter &&\n  (!window.devToolsOptions ||\n    !window.devToolsOptions.filter ||\n    window.devToolsOptions.filter === FilterState.DO_NOT_FILTER);\n\nexport function isFiltered<A extends Action<string>>(\n  action: A | string,\n  localFilter: LocalFilter | undefined,\n) {\n  if (\n    noFiltersApplied(localFilter) ||\n    (typeof action !== 'string' && typeof action.type.match !== 'function')\n  ) {\n    return false;\n  }\n\n  const { allowlist, denylist } = localFilter || window.devToolsOptions || {};\n  const actionType = ((action as A).type || action) as string;\n  return (\n    (allowlist && !actionType.match(allowlist)) ||\n    (denylist && actionType.match(denylist))\n  );\n}\n\nfunction filterActions<A extends Action<string>>(\n  actionsById: { [p: number]: PerformAction<A> },\n  actionSanitizer: ((action: A, id: number) => A) | undefined,\n): { [p: number]: PerformAction<A> } {\n  if (!actionSanitizer) return actionsById;\n  return Object.fromEntries(\n    Object.entries(actionsById).map(([actionId, action]) => [\n      actionId,\n      {\n        ...action,\n        action: actionSanitizer(action.action, actionId as unknown as number),\n      },\n    ]),\n  );\n}\n\nfunction filterStates<S>(\n  computedStates: { state: S; error?: string | undefined }[],\n  stateSanitizer: ((state: S, index: number) => S) | undefined,\n) {\n  if (!stateSanitizer) return computedStates;\n  return computedStates.map((state, idx) => ({\n    ...state,\n    state: stateSanitizer(state.state, idx),\n  }));\n}\n\nexport function filterState<S, A extends Action<string>>(\n  state: LiftedState<S, A, unknown>,\n  localFilter: LocalFilter | undefined,\n  stateSanitizer: ((state: S, index: number) => S) | undefined,\n  actionSanitizer: ((action: A, id: number) => A) | undefined,\n  predicate: ((state: S, action: A) => boolean) | undefined,\n): LiftedState<S, A, unknown> {\n  if (predicate || !noFiltersApplied(localFilter)) {\n    const filteredStagedActionIds: number[] = [];\n    const filteredComputedStates: { state: S; error?: string | undefined }[] =\n      [];\n    const sanitizedActionsById: { [p: number]: PerformAction<A> } | undefined =\n      actionSanitizer && {};\n    const { actionsById } = state;\n    const { computedStates } = state;\n\n    state.stagedActionIds.forEach((id, idx) => {\n      const liftedAction = actionsById[id];\n      if (!liftedAction) return;\n      const currAction = liftedAction.action;\n      const liftedState = computedStates[idx];\n      const currState = liftedState.state;\n      if (idx) {\n        if (predicate && !predicate(currState, currAction)) return;\n        if (isFiltered(currAction, localFilter)) return;\n      }\n\n      filteredStagedActionIds.push(id);\n      filteredComputedStates.push(\n        stateSanitizer\n          ? { ...liftedState, state: stateSanitizer(currState, idx) }\n          : liftedState,\n      );\n      if (actionSanitizer) {\n        sanitizedActionsById![id] = {\n          ...liftedAction,\n          action: actionSanitizer(currAction, id),\n        };\n      }\n    });\n\n    return {\n      ...state,\n      actionsById: sanitizedActionsById || actionsById,\n      stagedActionIds: filteredStagedActionIds,\n      computedStates: filteredComputedStates,\n    };\n  }\n\n  if (!stateSanitizer && !actionSanitizer) return state;\n  return {\n    ...state,\n    actionsById: filterActions(state.actionsById, actionSanitizer),\n    computedStates: filterStates(state.computedStates, stateSanitizer),\n  };\n}\n\nexport interface PartialLiftedState<S, A extends Action<string>> {\n  readonly actionsById: { [actionId: number]: PerformAction<A> };\n  readonly computedStates: { state: S; error?: string }[];\n  readonly stagedActionIds: readonly number[];\n  readonly currentStateIndex: number;\n  readonly nextActionId: number;\n  readonly committedState?: S;\n}\n\nexport function startingFrom<S, A extends Action<string>>(\n  sendingActionId: number,\n  state: LiftedState<S, A, unknown>,\n  localFilter: LocalFilter | undefined,\n  stateSanitizer: (<S>(state: S, index: number) => S) | undefined,\n  actionSanitizer:\n    | (<A extends Action<string>>(action: A, id: number) => A)\n    | undefined,\n  predicate:\n    | (<S, A extends Action<string>>(state: S, action: A) => boolean)\n    | undefined,\n): LiftedState<S, A, unknown> | PartialLiftedState<S, A> | undefined {\n  const stagedActionIds = state.stagedActionIds;\n  if (sendingActionId <= stagedActionIds[1]) return state;\n  const index = stagedActionIds.indexOf(sendingActionId);\n  if (index === -1) return state;\n\n  const shouldFilter = predicate || !noFiltersApplied(localFilter);\n  const filteredStagedActionIds = shouldFilter ? [0] : stagedActionIds;\n  const actionsById = state.actionsById;\n  const computedStates = state.computedStates;\n  const newActionsById: { [key: number]: PerformAction<A> } = {};\n  const newComputedStates = [];\n  let key;\n  let currAction;\n  let currState;\n\n  for (let i = shouldFilter ? 1 : index; i < stagedActionIds.length; i++) {\n    key = stagedActionIds[i];\n    currAction = actionsById[key];\n    currState = computedStates[i];\n\n    if (shouldFilter) {\n      if (\n        (predicate && !predicate(currState.state, currAction.action)) ||\n        isFiltered(currAction.action, localFilter)\n      ) {\n        continue;\n      }\n      filteredStagedActionIds.push(key);\n      if (i < index) continue;\n    }\n\n    newActionsById[key] = !actionSanitizer\n      ? currAction\n      : { ...currAction, action: actionSanitizer(currAction.action, key) };\n    newComputedStates.push(\n      !stateSanitizer\n        ? currState\n        : { ...currState, state: stateSanitizer(currState.state, i) },\n    );\n  }\n\n  if (newComputedStates.length === 0) return undefined;\n\n  return {\n    actionsById: newActionsById,\n    computedStates: newComputedStates,\n    stagedActionIds: filteredStagedActionIds,\n    currentStateIndex: state.currentStateIndex,\n    nextActionId: state.nextActionId,\n  };\n}\n"
  },
  {
    "path": "extension/src/pageScript/api/generateInstanceId.ts",
    "content": "let id = 0;\n\nexport default function generateId(instanceId: number | undefined) {\n  return instanceId || ++id;\n}\n"
  },
  {
    "path": "extension/src/pageScript/api/importState.ts",
    "content": "import jsan from 'jsan';\nimport { immutableSerialize } from '@redux-devtools/serialize';\nimport type { Config, SerializeWithImmutable } from '../index.js';\nimport Immutable from 'immutable';\nimport { LiftedState } from '@redux-devtools/instrument';\nimport { Action } from 'redux';\n\ninterface SerializeWithRequiredImmutable extends SerializeWithImmutable {\n  readonly immutable: typeof Immutable;\n}\n\nfunction isSerializeWithImmutable(\n  serialize: boolean | SerializeWithImmutable,\n): serialize is SerializeWithRequiredImmutable {\n  return !!(serialize as SerializeWithImmutable).immutable;\n}\n\ninterface SerializeWithRequiredReviver extends SerializeWithImmutable {\n  readonly reviver: (key: string, value: unknown) => unknown;\n}\n\nfunction isSerializeWithReviver(\n  serialize: boolean | SerializeWithImmutable,\n): serialize is SerializeWithRequiredReviver {\n  return !!(serialize as SerializeWithImmutable).immutable;\n}\n\ninterface ParsedSerializedLiftedState {\n  readonly payload: string;\n  readonly preloadedState?: string;\n}\n\nexport default function importState<S, A extends Action<string>>(\n  state: string | undefined,\n  { serialize }: Config,\n) {\n  if (!state) return undefined;\n  let parse = jsan.parse;\n  if (serialize) {\n    if (isSerializeWithImmutable(serialize)) {\n      parse = (v) =>\n        jsan.parse(\n          v,\n          immutableSerialize(\n            serialize.immutable,\n            serialize.refs,\n            serialize.replacer,\n            serialize.reviver,\n          ).reviver,\n        );\n    } else if (isSerializeWithReviver(serialize)) {\n      parse = (v) => jsan.parse(v, serialize.reviver);\n    }\n  }\n\n  const parsedSerializedLiftedState:\n    | ParsedSerializedLiftedState\n    | LiftedState<S, A, unknown> = parse(state) as\n    | ParsedSerializedLiftedState\n    | LiftedState<S, A, unknown>;\n  const preloadedState =\n    'payload' in parsedSerializedLiftedState &&\n    parsedSerializedLiftedState.preloadedState\n      ? (parse(parsedSerializedLiftedState.preloadedState) as S)\n      : undefined;\n  const nextLiftedState =\n    'payload' in parsedSerializedLiftedState\n      ? (parse(parsedSerializedLiftedState.payload) as LiftedState<\n          S,\n          A,\n          unknown\n        >)\n      : parsedSerializedLiftedState;\n\n  return { nextLiftedState, preloadedState };\n}\n"
  },
  {
    "path": "extension/src/pageScript/api/index.ts",
    "content": "import jsan, { Options } from 'jsan';\nimport { throttle } from 'lodash-es';\nimport { immutableSerialize } from '@redux-devtools/serialize';\nimport { getActionsArray, getLocalFilter } from '@redux-devtools/utils';\nimport { isFiltered, PartialLiftedState } from './filters.js';\nimport importState from './importState.js';\nimport generateId from './generateInstanceId.js';\nimport type { Config } from '../index.js';\nimport { Action } from 'redux';\nimport { LiftedState, PerformAction } from '@redux-devtools/instrument';\nimport { LibConfig } from '@redux-devtools/app';\nimport type {\n  ContentScriptToPageScriptMessage,\n  ListenerMessage,\n} from '../../contentScript/index.js';\nimport type { Position } from './openWindow.js';\n\nconst listeners: {\n  [instanceId: string]:\n    | ((message: ContentScriptToPageScriptMessage) => void)\n    | ((message: ContentScriptToPageScriptMessage) => void)[];\n} = {};\nexport const source = '@devtools-page';\n\nfunction windowReplacer(key: string, value: unknown) {\n  if (value && (value as Window).window === value) {\n    return '[WINDOW]';\n  }\n  return value;\n}\n\nfunction tryCatchStringify(obj: unknown) {\n  try {\n    return JSON.stringify(obj);\n  } catch (err) {\n    /* eslint-disable no-console */\n    if (process.env.NODE_ENV !== 'production') {\n      console.log('Failed to stringify', err);\n    }\n    /* eslint-enable no-console */\n    return jsan.stringify(obj, windowReplacer, undefined, {\n      circular: '[CIRCULAR]',\n      date: true,\n    });\n  }\n}\n\nlet stringifyWarned: boolean;\nfunction stringify(obj: unknown, serialize?: Serialize | undefined) {\n  const str =\n    typeof serialize === 'undefined'\n      ? tryCatchStringify(obj)\n      : jsan.stringify(obj, serialize.replacer, undefined, serialize.options);\n\n  if (!stringifyWarned && str && str.length > 16 * 1024 * 1024) {\n    // 16 MB\n    /* eslint-disable no-console */\n    console.warn(\n      'Application state or actions payloads are too large making Redux DevTools serialization slow and consuming a lot of memory. See https://github.com/reduxjs/redux-devtools-extension/blob/master/docs/Troubleshooting.md#excessive-use-of-memory-and-cpu on how to configure it.',\n    );\n    /* eslint-enable no-console */\n    stringifyWarned = true;\n  }\n\n  return str;\n}\n\nexport interface Serialize {\n  readonly replacer?: (key: string, value: unknown) => unknown;\n  readonly reviver?: (key: string, value: unknown) => unknown;\n  readonly options?: Options | boolean;\n}\n\nexport function getSerializeParameter(config: Config) {\n  const serialize = config.serialize;\n  if (serialize) {\n    if (serialize === true) return { options: true };\n    if (serialize.immutable) {\n      const immutableSerializer = immutableSerialize(\n        serialize.immutable,\n        serialize.refs,\n        serialize.replacer,\n        serialize.reviver,\n      );\n      return {\n        replacer: immutableSerializer.replacer,\n        reviver: immutableSerializer.reviver,\n        options:\n          typeof serialize.options === 'object'\n            ? { ...immutableSerializer.options, ...serialize.options }\n            : immutableSerializer.options,\n      };\n    }\n    if (!serialize.replacer && !serialize.reviver) {\n      return { options: serialize.options };\n    }\n    return {\n      replacer: serialize.replacer,\n      reviver: serialize.reviver,\n      options: serialize.options || true,\n    };\n  }\n\n  return undefined;\n}\n\ninterface InitInstancePageScriptToContentScriptMessage {\n  readonly type: 'INIT_INSTANCE';\n  readonly instanceId: number;\n  readonly source: typeof source;\n}\n\ninterface DisconnectMessage {\n  readonly type: 'DISCONNECT';\n  readonly source: typeof source;\n}\n\ninterface InitMessage<S, A extends Action<string>> {\n  readonly type: 'INIT';\n  readonly payload: string;\n  readonly instanceId: number;\n  readonly source: typeof source;\n  action?: string;\n  name?: string | undefined;\n  liftedState?: LiftedState<S, A, unknown>;\n  libConfig?: LibConfig;\n}\n\ninterface SerializedPartialLiftedState {\n  readonly stagedActionIds: readonly number[];\n  readonly currentStateIndex: number;\n  readonly nextActionId: number;\n}\n\ninterface SerializedPartialStateMessage {\n  readonly type: 'PARTIAL_STATE';\n  readonly payload: SerializedPartialLiftedState;\n  readonly source: typeof source;\n  readonly instanceId: number;\n  readonly maxAge: number;\n  readonly actionsById: string;\n  readonly computedStates: string;\n  readonly committedState: boolean;\n}\n\ninterface SerializedExportMessage {\n  readonly type: 'EXPORT';\n  readonly payload: string;\n  readonly committedState: string | undefined;\n  readonly source: typeof source;\n  readonly instanceId: number;\n}\n\ninterface SerializedActionMessage {\n  readonly type: 'ACTION';\n  readonly payload: string;\n  readonly source: typeof source;\n  readonly instanceId: number;\n  readonly action: string;\n  readonly maxAge: number;\n  readonly nextActionId?: number;\n}\n\ninterface SerializedStateMessage<S, A extends Action<string>> {\n  readonly type: 'STATE';\n  readonly payload: Omit<\n    LiftedState<S, A, unknown>,\n    'actionsById' | 'computedStates' | 'committedState'\n  >;\n  readonly source: typeof source;\n  readonly instanceId: number;\n  readonly libConfig?: LibConfig;\n  readonly actionsById: string;\n  readonly computedStates: string;\n  readonly committedState: boolean;\n}\n\ninterface OpenMessage {\n  readonly source: typeof source;\n  readonly type: 'OPEN';\n  readonly position: Position;\n}\n\nexport type PageScriptToContentScriptMessageForwardedToMonitors<\n  S,\n  A extends Action<string>,\n> =\n  | InitMessage<S, A>\n  | LiftedMessage\n  | SerializedPartialStateMessage\n  | SerializedExportMessage\n  | SerializedActionMessage\n  | SerializedStateMessage<S, A>;\n\nexport type PageScriptToContentScriptMessageWithoutDisconnectOrInitInstance<\n  S,\n  A extends Action<string>,\n> =\n  | PageScriptToContentScriptMessageForwardedToMonitors<S, A>\n  | ErrorMessage\n  | GetReportMessage\n  | StopMessage\n  | OpenMessage;\n\nexport type PageScriptToContentScriptMessageWithoutDisconnect<\n  S,\n  A extends Action<string>,\n> =\n  | PageScriptToContentScriptMessageWithoutDisconnectOrInitInstance<S, A>\n  | InitInstancePageScriptToContentScriptMessage\n  | InitInstanceMessage;\n\nexport type PageScriptToContentScriptMessage<S, A extends Action<string>> =\n  | PageScriptToContentScriptMessageWithoutDisconnect<S, A>\n  | DisconnectMessage;\n\nfunction post<S, A extends Action<string>>(\n  message: PageScriptToContentScriptMessage<S, A>,\n) {\n  window.postMessage(message, '*');\n}\n\nfunction getStackTrace(\n  config: Config,\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n  toExcludeFromTrace: Function | undefined,\n) {\n  if (!config.trace) return undefined;\n  if (typeof config.trace === 'function') return config.trace();\n\n  let stack;\n  let extraFrames = 0;\n  let prevStackTraceLimit;\n  const traceLimit = config.traceLimit;\n  const error = Error();\n  if (Error.captureStackTrace) {\n    if (Error.stackTraceLimit < traceLimit!) {\n      prevStackTraceLimit = Error.stackTraceLimit;\n      Error.stackTraceLimit = traceLimit!;\n    }\n    Error.captureStackTrace(error, toExcludeFromTrace);\n  } else {\n    extraFrames = 3;\n  }\n  stack = error.stack;\n  if (prevStackTraceLimit) Error.stackTraceLimit = prevStackTraceLimit;\n  if (\n    extraFrames ||\n    typeof Error.stackTraceLimit !== 'number' ||\n    Error.stackTraceLimit > traceLimit!\n  ) {\n    // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n    const frames = stack!.split('\\n');\n    if (frames.length > traceLimit!) {\n      stack = frames\n        .slice(0, traceLimit! + extraFrames + (frames[0] === 'Error' ? 1 : 0))\n        .join('\\n');\n    }\n  }\n  return stack;\n}\n\nfunction amendActionType<A extends Action<string>>(\n  action:\n    | A\n    | StructuralPerformAction<A>\n    | StructuralPerformAction<A>[]\n    | string,\n  config: Config,\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n  toExcludeFromTrace: Function | undefined,\n): StructuralPerformAction<A> {\n  const timestamp = Date.now();\n  const stack = getStackTrace(config, toExcludeFromTrace);\n  if (typeof action === 'string') {\n    return { action: { type: action } as A, timestamp, stack };\n  }\n  if (!(action as A).type)\n    return { action: { type: 'update' } as A, timestamp, stack };\n  if ((action as StructuralPerformAction<A>).action)\n    return (\n      stack ? { stack, ...action } : action\n    ) as StructuralPerformAction<A>;\n  return { action, timestamp, stack } as StructuralPerformAction<A>;\n}\n\ninterface LiftedMessage {\n  readonly type: 'LIFTED';\n  readonly liftedState: { readonly isPaused: boolean | undefined };\n  readonly instanceId: number;\n  readonly source: typeof source;\n}\n\ninterface PartialStateMessage<S, A extends Action<string>> {\n  readonly type: 'PARTIAL_STATE';\n  readonly payload: PartialLiftedState<S, A>;\n  readonly source: typeof source;\n  readonly instanceId: number;\n  readonly maxAge: number;\n}\n\ninterface ExportMessage<S, A extends Action<string>> {\n  readonly type: 'EXPORT';\n  readonly payload: readonly A[];\n  readonly committedState: S;\n  readonly source: typeof source;\n  readonly instanceId: number;\n}\n\nexport interface StructuralPerformAction<A extends Action<string>> {\n  readonly action: A;\n  readonly timestamp?: number;\n  readonly stack?: string;\n}\n\ntype SingleUserAction<A extends Action<string>> =\n  | PerformAction<A>\n  | StructuralPerformAction<A>\n  | A;\ntype UserAction<A extends Action<string>> =\n  | SingleUserAction<A>\n  | readonly SingleUserAction<A>[];\n\ninterface ActionMessage<S, A extends Action<string>> {\n  readonly type: 'ACTION';\n  readonly payload: S;\n  readonly source: typeof source;\n  readonly instanceId: number;\n  readonly action: UserAction<A>;\n  readonly maxAge: number;\n  readonly nextActionId?: number;\n  readonly name?: string;\n}\n\ninterface StateMessage<S, A extends Action<string>> {\n  readonly type: 'STATE';\n  readonly payload: LiftedState<S, A, unknown>;\n  readonly source: typeof source;\n  readonly instanceId: number;\n  readonly libConfig?: LibConfig;\n  readonly action?: UserAction<A>;\n  readonly maxAge?: number;\n  readonly name?: string;\n}\n\nexport interface ErrorMessage {\n  readonly type: 'ERROR';\n  readonly payload: string;\n  readonly source: typeof source;\n  readonly instanceId: number;\n  readonly message?: string | undefined;\n}\n\ninterface InitInstanceMessage {\n  readonly type: 'INIT_INSTANCE';\n  readonly payload: undefined;\n  readonly source: typeof source;\n  readonly instanceId: number;\n}\n\ninterface GetReportMessage {\n  readonly type: 'GET_REPORT';\n  readonly payload: string;\n  readonly source: typeof source;\n  readonly instanceId: number;\n}\n\ninterface StopMessage {\n  readonly type: 'STOP';\n  readonly payload: undefined;\n  readonly source: typeof source;\n  readonly instanceId: number;\n}\n\ntype ToContentScriptMessage<S, A extends Action<string>> =\n  | LiftedMessage\n  | PartialStateMessage<S, A>\n  | ExportMessage<S, A>\n  | ActionMessage<S, A>\n  | StateMessage<S, A>\n  | ErrorMessage\n  | InitInstanceMessage\n  | GetReportMessage\n  | StopMessage;\n\nexport function toContentScript<S, A extends Action<string>>(\n  message: ToContentScriptMessage<S, A>,\n  serializeState?: Serialize | undefined,\n  serializeAction?: Serialize | undefined,\n) {\n  if (message.type === 'ACTION') {\n    post({\n      ...message,\n      action: stringify(message.action, serializeAction),\n      payload: stringify(message.payload, serializeState),\n    });\n  } else if (message.type === 'STATE') {\n    const { actionsById, computedStates, committedState, ...rest } =\n      message.payload;\n    post({\n      ...message,\n      payload: rest,\n      actionsById: stringify(actionsById, serializeAction),\n      computedStates: stringify(computedStates, serializeState),\n      committedState: typeof committedState !== 'undefined',\n    });\n  } else if (message.type === 'PARTIAL_STATE') {\n    const { actionsById, computedStates, committedState, ...rest } =\n      message.payload;\n    post({\n      ...message,\n      payload: rest,\n      actionsById: stringify(actionsById, serializeAction),\n      computedStates: stringify(computedStates, serializeState),\n      committedState: typeof committedState !== 'undefined',\n    });\n  } else if (message.type === 'EXPORT') {\n    post({\n      ...message,\n      payload: stringify(message.payload, serializeAction),\n      committedState:\n        typeof message.committedState !== 'undefined'\n          ? stringify(message.committedState, serializeState)\n          : (message.committedState as undefined),\n    });\n  } else {\n    post(message);\n  }\n}\n\nexport function sendMessage<S, A extends Action<string>>(\n  action: StructuralPerformAction<A> | StructuralPerformAction<A>[],\n  state: LiftedState<S, A, unknown>,\n  config: Config,\n  instanceId?: number,\n  name?: string,\n) {\n  let amendedAction = action;\n  if (typeof config !== 'object') {\n    // Legacy: sending actions not from connected part\n    config = {}; // eslint-disable-line no-param-reassign\n    if (action) amendedAction = amendActionType(action, config, sendMessage);\n  }\n  if (action) {\n    toContentScript(\n      {\n        type: 'ACTION',\n        action: amendedAction,\n        payload: state,\n        maxAge: config.maxAge!,\n        source,\n        name: config.name || name,\n        instanceId: config.instanceId || instanceId || 1,\n      },\n      config.serialize as Serialize | undefined,\n      config.serialize as Serialize | undefined,\n    );\n  } else {\n    toContentScript<S, A>(\n      {\n        type: 'STATE',\n        action: amendedAction,\n        payload: state,\n        maxAge: config.maxAge,\n        source,\n        name: config.name || name,\n        instanceId: config.instanceId || instanceId || 1,\n      },\n      config.serialize as Serialize | undefined,\n      config.serialize as Serialize | undefined,\n    );\n  }\n}\n\nfunction handleMessages(event: MessageEvent<ContentScriptToPageScriptMessage>) {\n  if (process.env.BABEL_ENV !== 'test' && (!event || event.source !== window)) {\n    return;\n  }\n  const message = event.data;\n  if (!message || message.source !== '@devtools-extension') return;\n  Object.keys(listeners).forEach((id) => {\n    if (message.id && id !== message.id) return;\n    const listenersForId = listeners[id];\n    if (typeof listenersForId === 'function') listenersForId(message);\n    else {\n      listenersForId.forEach((fn) => {\n        fn(message);\n      });\n    }\n  });\n}\n\nexport function setListener(\n  onMessage: (message: ContentScriptToPageScriptMessage) => void,\n  instanceId: number,\n) {\n  listeners[instanceId] = onMessage;\n  window.addEventListener('message', handleMessages, false);\n}\n\nconst liftListener =\n  <S, A extends Action<string>>(\n    listener: (message: ListenerMessage<S, A>) => void,\n    config: Config,\n  ) =>\n  (message: ContentScriptToPageScriptMessage) => {\n    if (message.type === 'IMPORT') {\n      listener({\n        type: 'DISPATCH',\n        payload: {\n          type: 'IMPORT_STATE',\n          ...importState<S, A>(message.state, config)!,\n        },\n      });\n    } else {\n      listener(message);\n    }\n  };\n\nexport function disconnect() {\n  window.removeEventListener('message', handleMessages);\n  post({ type: 'DISCONNECT', source });\n}\n\nexport interface ConnectResponse {\n  init: <S, A extends Action<string>>(\n    state: S,\n    liftedData?: LiftedState<S, A, unknown>,\n  ) => void;\n  subscribe: <S, A extends Action<string>>(\n    listener: (message: ListenerMessage<S, A>) => void,\n  ) => (() => void) | undefined;\n  unsubscribe: () => void;\n  send: <S, A extends Action<string>>(\n    action: A,\n    state: LiftedState<S, A, unknown>,\n  ) => void;\n  error: (payload: string) => void;\n}\n\nexport function connect(preConfig: Config): ConnectResponse {\n  const config = preConfig || {};\n  const id = generateId(config.instanceId);\n  if (!config.instanceId) config.instanceId = id;\n  if (!config.name) {\n    config.name =\n      document.title && id === 1 ? document.title : `Instance ${id}`;\n  }\n  if (config.serialize) config.serialize = getSerializeParameter(config);\n  const actionCreators = config.actionCreators || {};\n  const latency = config.latency;\n  const predicate = config.predicate;\n  const localFilter = getLocalFilter(config);\n  const autoPause = config.autoPause;\n  let isPaused = autoPause;\n  let delayedActions: StructuralPerformAction<Action<string>>[] = [];\n  let delayedStates: LiftedState<unknown, Action<string>, unknown>[] = [];\n\n  const rootListener = (action: ContentScriptToPageScriptMessage) => {\n    if (autoPause) {\n      if (action.type === 'START') isPaused = false;\n      else if (action.type === 'STOP') isPaused = true;\n    }\n    if (action.type === 'DISPATCH') {\n      const payload = action.payload;\n      if (payload.type === 'PAUSE_RECORDING') {\n        isPaused = payload.status;\n        toContentScript({\n          type: 'LIFTED',\n          liftedState: { isPaused },\n          instanceId: id,\n          source,\n        });\n      }\n    }\n  };\n\n  listeners[id] = [rootListener];\n\n  const subscribe = <S, A extends Action<string>>(\n    listener: (message: ListenerMessage<S, A>) => void,\n  ) => {\n    if (!listener) return undefined;\n    const liftedListener = liftListener(listener, config);\n    const listenersForId = listeners[id] as ((\n      message: ContentScriptToPageScriptMessage,\n    ) => void)[];\n    listenersForId.push(liftedListener);\n\n    return function unsubscribe() {\n      const index = listenersForId.indexOf(liftedListener);\n      listenersForId.splice(index, 1);\n    };\n  };\n\n  const unsubscribe = () => {\n    delete listeners[id];\n  };\n\n  const sendDelayed = throttle(() => {\n    sendMessage(\n      delayedActions,\n      delayedStates as unknown as LiftedState<unknown, Action<string>, unknown>,\n      config,\n    );\n    delayedActions = [];\n    delayedStates = [];\n  }, latency);\n\n  const send = <S, A extends Action<string>>(\n    action: A,\n    state: LiftedState<S, A, unknown>,\n  ) => {\n    if (\n      isPaused ||\n      isFiltered(action, localFilter) ||\n      (predicate && !predicate(state, action))\n    ) {\n      return;\n    }\n\n    let amendedAction: A | StructuralPerformAction<A> = action;\n    const amendedState = config.stateSanitizer\n      ? config.stateSanitizer(state)\n      : state;\n    if (action) {\n      if (config.getActionType) {\n        amendedAction = config.getActionType(action);\n        if (typeof amendedAction !== 'object') {\n          amendedAction = {\n            action: { type: amendedAction },\n            timestamp: Date.now(),\n          } as unknown as A;\n        }\n      } else if (config.actionSanitizer) {\n        amendedAction = config.actionSanitizer(action);\n      }\n      amendedAction = amendActionType(amendedAction, config, send);\n      if (latency) {\n        delayedActions.push(amendedAction);\n        delayedStates.push(amendedState);\n        sendDelayed();\n        return;\n      }\n    }\n    sendMessage(\n      amendedAction as StructuralPerformAction<A>,\n      amendedState,\n      config,\n    );\n  };\n\n  const init = <S, A extends Action<string>>(\n    state: S,\n    liftedData?: LiftedState<S, A, unknown>,\n  ) => {\n    const message: InitMessage<S, A> = {\n      type: 'INIT',\n      payload: stringify(state, config.serialize as Serialize | undefined),\n      instanceId: id,\n      source,\n    };\n    if (liftedData && Array.isArray(liftedData)) {\n      // Legacy\n      message.action = stringify(liftedData);\n      message.name = config.name;\n    } else {\n      if (liftedData) {\n        message.liftedState = liftedData;\n        if (liftedData.isPaused) isPaused = true;\n      }\n      message.libConfig = {\n        actionCreators: JSON.stringify(getActionsArray(actionCreators)),\n        name: config.name || document.title,\n        features: config.features,\n        serialize: !!config.serialize,\n        type: config.type,\n      };\n    }\n    post(message);\n  };\n\n  const error = (payload: string) => {\n    post({ type: 'ERROR', payload, instanceId: id, source });\n  };\n\n  window.addEventListener('message', handleMessages, false);\n\n  post({ type: 'INIT_INSTANCE', instanceId: id, source });\n\n  return {\n    init,\n    subscribe,\n    unsubscribe,\n    send,\n    error,\n  };\n}\n\nexport function isInIframe() {\n  try {\n    return window.self !== window.top;\n  } catch (e) {\n    return true;\n  }\n}\n"
  },
  {
    "path": "extension/src/pageScript/api/notifyErrors.ts",
    "content": "let handleError: (() => boolean) | undefined;\nlet lastTime = 0;\n\nfunction createExpBackoffTimer(step: number) {\n  let count = 1;\n  return function (reset?: boolean) {\n    // Reset call\n    if (reset) {\n      count = 1;\n      return 0;\n    }\n    // Calculate next timeout\n    const timeout = Math.pow(2, count - 1);\n    if (count < 5) count += 1;\n    return timeout * step;\n  };\n}\n\nconst nextErrorTimeout = createExpBackoffTimer(5000);\n\nfunction postError(message: string) {\n  if (handleError && !handleError()) return;\n  window.postMessage(\n    {\n      source: '@devtools-page',\n      type: 'ERROR',\n      message: message,\n    },\n    '*',\n  );\n}\n\nfunction catchErrors(e: ErrorEvent) {\n  if (\n    (window.devToolsOptions && !window.devToolsOptions.shouldCatchErrors) ||\n    e.timeStamp - lastTime < nextErrorTimeout()\n  ) {\n    return;\n  }\n  lastTime = e.timeStamp;\n  nextErrorTimeout(true);\n  postError(e.message);\n}\n\nexport default function notifyErrors(onError?: () => boolean) {\n  handleError = onError;\n  window.addEventListener('error', catchErrors, false);\n}\n"
  },
  {
    "path": "extension/src/pageScript/api/openWindow.ts",
    "content": "import { Action } from 'redux';\nimport type { PageScriptToContentScriptMessage } from './index.js';\n\nexport type Position = 'window' | 'remote';\n\nfunction post<S, A extends Action<string>>(\n  message: PageScriptToContentScriptMessage<S, A>,\n) {\n  window.postMessage(message, '*');\n}\n\nexport default function openWindow(position?: Position) {\n  post({\n    source: '@devtools-page',\n    type: 'OPEN',\n    position: position ?? 'window',\n  });\n}\n"
  },
  {
    "path": "extension/src/pageScript/enhancerStore.ts",
    "content": "import { Action, compose, Reducer, StoreEnhancerStoreCreator } from 'redux';\nimport { instrument } from '@redux-devtools/instrument';\nimport { persistState } from '@redux-devtools/core';\nimport type { ConfigWithExpandedMaxAge } from './index.js';\n\nexport function getUrlParam(key: string) {\n  const matches = new RegExp(`[?&]${key}=([^&#]+)\\\\b`).exec(\n    window.location.href,\n  );\n  return matches && matches.length > 0 ? matches[1] : null;\n}\n\ndeclare global {\n  interface Window {\n    shouldCatchErrors?: boolean;\n  }\n}\n\nexport default function configureStore<\n  S,\n  A extends Action<string>,\n  MonitorState,\n  MonitorAction extends Action<string>,\n>(\n  next: StoreEnhancerStoreCreator,\n  monitorReducer: Reducer<MonitorState, MonitorAction>,\n  config: ConfigWithExpandedMaxAge,\n) {\n  return compose(\n    instrument(monitorReducer, {\n      maxAge: config.maxAge,\n      trace: config.trace,\n      traceLimit: config.traceLimit,\n      shouldCatchErrors: config.shouldCatchErrors || window.shouldCatchErrors,\n      shouldHotReload: config.shouldHotReload,\n      shouldRecordChanges: config.shouldRecordChanges,\n      shouldStartLocked: config.shouldStartLocked,\n      pauseActionType: config.pauseActionType || '@@PAUSED',\n    }),\n    persistState(getUrlParam('debug_session')),\n  )(next);\n}\n"
  },
  {
    "path": "extension/src/pageScript/index.ts",
    "content": "import {\n  ActionCreatorObject,\n  evalAction,\n  getActionsArray,\n  getLocalFilter,\n} from '@redux-devtools/utils';\nimport { throttle } from 'lodash-es';\nimport { Action, ActionCreator, Dispatch, Reducer, StoreEnhancer } from 'redux';\nimport Immutable from 'immutable';\nimport {\n  EnhancedStore,\n  LiftedAction,\n  LiftedState,\n  PerformAction,\n} from '@redux-devtools/instrument';\nimport {\n  CustomAction,\n  DispatchAction,\n  LibConfig,\n  Features,\n} from '@redux-devtools/app';\nimport configureStore, { getUrlParam } from './enhancerStore.js';\nimport { isAllowed, Options } from '../options/syncOptions.js';\nimport Monitor from './Monitor.js';\nimport {\n  noFiltersApplied,\n  isFiltered,\n  filterState,\n  startingFrom,\n} from './api/filters.js';\nimport notifyErrors from './api/notifyErrors.js';\nimport importState from './api/importState.js';\nimport openWindow, { Position } from './api/openWindow.js';\nimport generateId from './api/generateInstanceId.js';\nimport {\n  toContentScript,\n  sendMessage,\n  setListener,\n  connect,\n  disconnect,\n  isInIframe,\n  getSerializeParameter,\n  Serialize,\n  StructuralPerformAction,\n  ConnectResponse,\n} from './api/index.js';\nimport type { ContentScriptToPageScriptMessage } from '../contentScript/index.js';\n\ntype EnhancedStoreWithInitialDispatch<\n  S,\n  A extends Action<string>,\n  MonitorState,\n> = EnhancedStore<S, A, MonitorState> & { initialDispatch: Dispatch<A> };\n\nconst source = '@devtools-page';\nconst stores: {\n  [K in string | number]: EnhancedStoreWithInitialDispatch<\n    unknown,\n    Action<string>,\n    unknown\n  >;\n} = {};\nlet reportId: string | null | undefined;\n\nfunction deprecateParam(oldParam: string, newParam: string) {\n  /* eslint-disable no-console */\n  console.warn(\n    `${oldParam} parameter is deprecated, use ${newParam} instead: https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/API/Arguments.md`,\n  );\n  /* eslint-enable no-console */\n}\n\nexport interface SerializeWithImmutable extends Serialize {\n  readonly immutable?: typeof Immutable;\n  readonly refs?: (new (data: any) => unknown)[] | null;\n}\n\nexport interface ConfigWithExpandedMaxAge {\n  instanceId?: number;\n  /**\n   * @deprecated Use actionsDenylist instead.\n   */\n  readonly actionsBlacklist?: string | readonly string[];\n  /**\n   * @deprecated Use actionsAllowlist instead.\n   */\n  readonly actionsWhitelist?: string | readonly string[];\n  readonly actionsDenylist?: string | readonly string[];\n  readonly actionsAllowlist?: string | readonly string[];\n  serialize?: boolean | SerializeWithImmutable;\n  readonly stateSanitizer?: <S>(state: S, index?: number) => S;\n  readonly actionSanitizer?: <A extends Action<string>>(\n    action: A,\n    id?: number,\n  ) => A;\n  readonly predicate?: <S, A extends Action<string>>(\n    state: S,\n    action: A,\n  ) => boolean;\n  readonly latency?: number;\n  readonly maxAge?:\n    | number\n    | (<S, A extends Action<string>>(\n        currentLiftedAction: LiftedAction<S, A, unknown>,\n        previousLiftedState: LiftedState<S, A, unknown> | undefined,\n      ) => number);\n  readonly trace?: boolean | (() => string | undefined);\n  readonly traceLimit?: number;\n  readonly shouldCatchErrors?: boolean;\n  readonly shouldHotReload?: boolean;\n  readonly shouldRecordChanges?: boolean;\n  readonly shouldStartLocked?: boolean;\n  readonly pauseActionType?: unknown;\n  name?: string;\n  readonly autoPause?: boolean;\n  readonly features?: Features;\n  readonly type?: string;\n  readonly getActionType?: <A extends Action<string>>(action: A) => A;\n  readonly actionCreators?: {\n    readonly [key: string]: ActionCreator<Action<string>>;\n  };\n}\n\nexport interface Config extends ConfigWithExpandedMaxAge {\n  readonly maxAge?: number;\n}\n\ninterface ReduxDevtoolsExtension {\n  (config?: Config): StoreEnhancer;\n  open: (position?: Position) => void;\n  notifyErrors: (onError?: () => boolean) => void;\n  send: <S, A extends Action<string>>(\n    action: StructuralPerformAction<A> | StructuralPerformAction<A>[],\n    state: LiftedState<S, A, unknown>,\n    config: Config,\n    instanceId?: number,\n    name?: string,\n  ) => void;\n  listen: (\n    onMessage: (message: ContentScriptToPageScriptMessage) => void,\n    instanceId: number,\n  ) => void;\n  connect: (preConfig: Config) => ConnectResponse;\n  disconnect: () => void;\n}\n\ndeclare global {\n  interface Window {\n    devToolsOptions: Options;\n  }\n}\n\nfunction __REDUX_DEVTOOLS_EXTENSION__<S, A extends Action<string>>(\n  config?: Config,\n): StoreEnhancer {\n  /* eslint-disable no-param-reassign */\n  if (typeof config !== 'object') config = {};\n  /* eslint-enable no-param-reassign */\n  if (!window.devToolsOptions) window.devToolsOptions = {} as any;\n\n  let store: EnhancedStoreWithInitialDispatch<S, A, unknown>;\n  let errorOccurred = false;\n  let maxAge: number | undefined;\n  let actionCreators: readonly ActionCreatorObject[];\n  let sendingActionId = 1;\n  const instanceId = generateId(config.instanceId);\n  const localFilter = getLocalFilter(config);\n  const serializeState = getSerializeParameter(config);\n  const serializeAction = getSerializeParameter(config);\n  const { stateSanitizer, actionSanitizer, predicate, latency = 500 } = config;\n\n  // Deprecate actionsWhitelist and actionsBlacklist\n  if (config.actionsWhitelist) {\n    deprecateParam('actionsWhiteList', 'actionsAllowlist');\n  }\n  if (config.actionsBlacklist) {\n    deprecateParam('actionsBlacklist', 'actionsDenylist');\n  }\n\n  const relayState = throttle(\n    (\n      liftedState?: LiftedState<S, A, unknown> | undefined,\n      libConfig?: LibConfig,\n    ) => {\n      relayAction.cancel();\n      const state = liftedState || store.liftedStore.getState();\n      sendingActionId = state.nextActionId;\n      toContentScript(\n        {\n          type: 'STATE',\n          payload: filterState(\n            state,\n            localFilter,\n            stateSanitizer,\n            actionSanitizer,\n            predicate,\n          ),\n          source,\n          instanceId,\n          libConfig,\n        },\n        serializeState,\n        serializeAction,\n      );\n    },\n    latency,\n  );\n\n  const monitor = new Monitor(relayState);\n\n  function exportState() {\n    const liftedState = store.liftedStore.getState();\n    const actionsById = liftedState.actionsById;\n    const payload: A[] = [];\n    liftedState.stagedActionIds.slice(1).forEach((id) => {\n      // if (isFiltered(actionsById[id].action, localFilter)) return;\n      payload.push(actionsById[id].action);\n    });\n    toContentScript(\n      {\n        type: 'EXPORT',\n        payload,\n        committedState: liftedState.committedState,\n        source,\n        instanceId,\n      },\n      serializeState,\n      serializeAction,\n    );\n  }\n\n  const relayAction = throttle(() => {\n    const liftedState = store.liftedStore.getState();\n    const nextActionId = liftedState.nextActionId;\n    const currentActionId = nextActionId - 1;\n    const liftedAction = liftedState.actionsById[currentActionId];\n\n    // Send a single action\n    if (sendingActionId === currentActionId) {\n      sendingActionId = nextActionId;\n      const action = liftedAction.action;\n      const computedStates = liftedState.computedStates;\n      if (\n        isFiltered(action, localFilter) ||\n        (predicate &&\n          !predicate(computedStates[computedStates.length - 1].state, action))\n      ) {\n        return;\n      }\n      const state =\n        liftedState.computedStates[liftedState.computedStates.length - 1].state;\n      toContentScript(\n        {\n          type: 'ACTION',\n          payload: !stateSanitizer\n            ? state\n            : stateSanitizer(state, nextActionId - 1),\n          source,\n          instanceId,\n          action: !actionSanitizer\n            ? liftedState.actionsById[nextActionId - 1]\n            : actionSanitizer(\n                liftedState.actionsById[nextActionId - 1].action,\n                nextActionId - 1,\n              ),\n          maxAge: getMaxAge(),\n          nextActionId,\n        },\n        serializeState,\n        serializeAction,\n      );\n      return;\n    }\n\n    // Send multiple actions\n    const payload = startingFrom(\n      sendingActionId,\n      liftedState,\n      localFilter,\n      stateSanitizer,\n      actionSanitizer,\n      predicate,\n    );\n    sendingActionId = nextActionId;\n    if (typeof payload === 'undefined') return;\n    if ('skippedActionIds' in payload) {\n      toContentScript(\n        {\n          type: 'STATE',\n          payload: filterState(\n            payload,\n            localFilter,\n            stateSanitizer,\n            actionSanitizer,\n            predicate,\n          ),\n          source,\n          instanceId,\n        },\n        serializeState,\n        serializeAction,\n      );\n      return;\n    }\n    toContentScript(\n      {\n        type: 'PARTIAL_STATE',\n        payload,\n        source,\n        instanceId,\n        maxAge: getMaxAge(),\n      },\n      serializeState,\n      serializeAction,\n    );\n  }, latency);\n\n  function dispatchRemotely(action: string | CustomAction) {\n    if (config!.features && !config!.features.dispatch) return;\n    try {\n      const result = evalAction(action, actionCreators);\n      (store.initialDispatch || store.dispatch)(result);\n    } catch (e) {\n      toContentScript(\n        {\n          type: 'ERROR',\n          payload: (e as Error).message,\n          source,\n          instanceId,\n        },\n        serializeState,\n        serializeAction,\n      );\n    }\n  }\n\n  function importPayloadFrom(state: string | undefined) {\n    if (config!.features && !config!.features.import) return;\n    try {\n      const nextLiftedState = importState<S, A>(state, config!);\n      if (!nextLiftedState) return;\n      store.liftedStore.dispatch({ type: 'IMPORT_STATE', ...nextLiftedState });\n    } catch (e) {\n      toContentScript(\n        {\n          type: 'ERROR',\n          payload: (e as Error).message,\n          source,\n          instanceId,\n        },\n        serializeState,\n        serializeAction,\n      );\n    }\n  }\n\n  function dispatchMonitorAction(action: DispatchAction) {\n    const features = config!.features;\n    if (features) {\n      if (\n        !features.jump &&\n        (action.type === 'JUMP_TO_STATE' || action.type === 'JUMP_TO_ACTION')\n      ) {\n        return;\n      }\n      if (!features.skip && action.type === 'TOGGLE_ACTION') return;\n      if (!features.reorder && action.type === 'REORDER_ACTION') return;\n      if (!features.import && action.type === 'IMPORT_STATE') return;\n      if (!features.lock && action.type === 'LOCK_CHANGES') return;\n      if (!features.pause && action.type === 'PAUSE_RECORDING') return;\n    }\n    store.liftedStore.dispatch(action as any);\n  }\n\n  function onMessage(message: ContentScriptToPageScriptMessage) {\n    switch (message.type) {\n      case 'DISPATCH':\n        dispatchMonitorAction(message.payload);\n        return;\n      case 'ACTION':\n        dispatchRemotely(message.payload);\n        return;\n      case 'IMPORT':\n        importPayloadFrom(message.state);\n        return;\n      case 'EXPORT':\n        exportState();\n        return;\n      case 'UPDATE':\n        relayState();\n        return;\n      case 'START':\n        monitor.start(true);\n        if (!actionCreators && config!.actionCreators) {\n          actionCreators = getActionsArray(config!.actionCreators);\n        }\n        relayState(undefined, {\n          name: config!.name || document.title,\n          actionCreators: JSON.stringify(actionCreators),\n          features: config!.features,\n          serialize: !!config!.serialize,\n          type: 'redux',\n        });\n\n        if (reportId) {\n          toContentScript(\n            {\n              type: 'GET_REPORT',\n              payload: reportId,\n              source,\n              instanceId,\n            },\n            serializeState,\n            serializeAction,\n          );\n          reportId = null;\n        }\n        return;\n      case 'STOP':\n        monitor.stop();\n        relayAction.cancel();\n        relayState.cancel();\n        if (!message.failed) {\n          toContentScript(\n            {\n              type: 'STOP',\n              payload: undefined,\n              source,\n              instanceId,\n            },\n            serializeState,\n            serializeAction,\n          );\n        }\n        return;\n      case 'OPTIONS':\n        window.devToolsOptions = Object.assign(\n          window.devToolsOptions || {},\n          message.options,\n        );\n        return;\n    }\n  }\n\n  const filteredActionIds: number[] = []; // simple circular buffer of non-excluded actions with fixed maxAge-1 length\n  const getMaxAge = (\n    liftedAction?: LiftedAction<S, A, unknown>,\n    liftedState?: LiftedState<S, A, unknown> | undefined,\n  ) => {\n    const m = (config && config.maxAge) || window.devToolsOptions.maxAge || 50;\n    if (\n      !liftedAction ||\n      noFiltersApplied(localFilter) ||\n      !(liftedAction as PerformAction<A>).action\n    ) {\n      return m;\n    }\n    if (!maxAge || maxAge < m) maxAge = m; // it can be modified in process on options page\n    if (isFiltered((liftedAction as PerformAction<A>).action, localFilter)) {\n      // TODO: check also predicate && !predicate(state, action) with current state\n      maxAge++;\n    } else {\n      filteredActionIds.push(liftedState!.nextActionId);\n      if (filteredActionIds.length >= m) {\n        const stagedActionIds = liftedState!.stagedActionIds;\n        let i = 1;\n        while (maxAge > m && !filteredActionIds.includes(stagedActionIds[i])) {\n          maxAge--;\n          i++;\n        }\n        filteredActionIds.shift();\n      }\n    }\n    return maxAge;\n  };\n\n  function init() {\n    setListener(onMessage, instanceId);\n    notifyErrors(() => {\n      errorOccurred = true;\n      const state = store.liftedStore.getState();\n      if (state.computedStates[state.currentStateIndex].error) {\n        relayState(state);\n      }\n      return true;\n    });\n\n    toContentScript(\n      {\n        type: 'INIT_INSTANCE',\n        payload: undefined,\n        source,\n        instanceId,\n      },\n      serializeState,\n      serializeAction,\n    );\n    store.subscribe(handleChange);\n\n    if (typeof reportId === 'undefined') {\n      reportId = getUrlParam('remotedev_report');\n      if (reportId) openWindow();\n    }\n  }\n\n  function handleChange() {\n    if (!monitor.active) return;\n    if (!errorOccurred && !monitor.isMonitorAction()) {\n      relayAction();\n      return;\n    }\n    if (monitor.isPaused() || monitor.isLocked() || monitor.isTimeTraveling()) {\n      return;\n    }\n    const liftedState = store.liftedStore.getState();\n    if (\n      errorOccurred &&\n      !liftedState.computedStates[liftedState.currentStateIndex].error\n    ) {\n      errorOccurred = false;\n    }\n    relayState(liftedState);\n  }\n\n  const enhance = (): StoreEnhancer => (next) => {\n    return <S2, A2 extends Action<string>, PreloadedState>(\n      reducer_: Reducer<S2, A2, PreloadedState>,\n      initialState_?: PreloadedState | undefined,\n    ) => {\n      if (!isAllowed(window.devToolsOptions)) {\n        return next(reducer_, initialState_);\n      }\n\n      store = stores[instanceId] = (\n        configureStore(next, monitor.reducer, {\n          ...config,\n          maxAge: getMaxAge as any,\n        }) as any\n      )(reducer_, initialState_);\n\n      if (isInIframe()) setTimeout(init, 3000);\n      else init();\n\n      return store as any;\n    };\n  };\n\n  return enhance();\n}\n\ndeclare global {\n  interface Window {\n    __REDUX_DEVTOOLS_EXTENSION__: ReduxDevtoolsExtension;\n  }\n}\n\n// noinspection JSAnnotator\nwindow.__REDUX_DEVTOOLS_EXTENSION__ = __REDUX_DEVTOOLS_EXTENSION__ as any;\nwindow.__REDUX_DEVTOOLS_EXTENSION__.open = openWindow;\nwindow.__REDUX_DEVTOOLS_EXTENSION__.notifyErrors = notifyErrors;\nwindow.__REDUX_DEVTOOLS_EXTENSION__.send = sendMessage;\nwindow.__REDUX_DEVTOOLS_EXTENSION__.listen = setListener;\nwindow.__REDUX_DEVTOOLS_EXTENSION__.connect = connect;\nwindow.__REDUX_DEVTOOLS_EXTENSION__.disconnect = disconnect;\n\nconst preEnhancer =\n  (instanceId: number): StoreEnhancer =>\n  (next) =>\n  (reducer, preloadedState) => {\n    const store = next(reducer, preloadedState);\n\n    if (stores[instanceId]) {\n      (stores[instanceId].initialDispatch as any) = store.dispatch;\n    }\n\n    return {\n      ...store,\n      dispatch: (...args: any[]) =>\n        !window.__REDUX_DEVTOOLS_EXTENSION_LOCKED__ &&\n        (store.dispatch as any)(...args),\n    } as any;\n  };\n\nexport type InferComposedStoreExt<StoreEnhancers> = StoreEnhancers extends [\n  infer HeadStoreEnhancer,\n  ...infer RestStoreEnhancers,\n]\n  ? HeadStoreEnhancer extends StoreEnhancer<infer StoreExt>\n    ? StoreExt & InferComposedStoreExt<RestStoreEnhancers>\n    : never\n  : // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n    {};\n\nconst extensionCompose =\n  (config: Config) =>\n  <StoreEnhancers extends readonly StoreEnhancer[]>(\n    ...funcs: StoreEnhancers\n  ): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>> => {\n    // @ts-expect-error FIXME\n    return (...args) => {\n      const instanceId = generateId(config.instanceId);\n      return [preEnhancer(instanceId), ...funcs].reduceRight(\n        (composed, f) => f(composed),\n        __REDUX_DEVTOOLS_EXTENSION__({ ...config, instanceId })(...args),\n      );\n    };\n  };\n\ninterface ReduxDevtoolsExtensionCompose {\n  (\n    config: Config,\n  ): <StoreEnhancers extends readonly StoreEnhancer[]>(\n    ...funcs: StoreEnhancers\n  ) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;\n  <StoreEnhancers extends readonly StoreEnhancer[]>(\n    ...funcs: StoreEnhancers\n  ): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;\n}\n\ndeclare global {\n  interface Window {\n    __REDUX_DEVTOOLS_EXTENSION_COMPOSE__: ReduxDevtoolsExtensionCompose;\n  }\n}\n\nfunction reduxDevtoolsExtensionCompose(\n  config: Config,\n): <StoreEnhancers extends readonly StoreEnhancer[]>(\n  ...funcs: StoreEnhancers\n) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;\nfunction reduxDevtoolsExtensionCompose<\n  StoreEnhancers extends readonly StoreEnhancer[],\n>(\n  ...funcs: StoreEnhancers\n): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;\nfunction reduxDevtoolsExtensionCompose(...funcs: [Config] | StoreEnhancer[]) {\n  if (funcs.length === 0) {\n    return __REDUX_DEVTOOLS_EXTENSION__();\n  }\n  if (funcs.length === 1 && typeof funcs[0] === 'object') {\n    return extensionCompose(funcs[0]);\n  }\n  return extensionCompose({})(...(funcs as StoreEnhancer[]));\n}\n\nwindow.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ = reduxDevtoolsExtensionCompose;\n"
  },
  {
    "path": "extension/src/remote/index.tsx",
    "content": "import React from 'react';\nimport { createRoot } from 'react-dom/client';\nimport { Root } from '@redux-devtools/app';\n\nchrome.storage.local.get(\n  {\n    'select-monitor': 'InspectorMonitor',\n    'test-templates': null,\n    'test-templates-sel': null,\n    's:hostname': null,\n    's:port': null,\n    's:secure': null,\n  },\n  (options) => {\n    const AppAsAny = Root as any;\n    const root = createRoot(document.getElementById('root')!);\n    root.render(\n      <AppAsAny\n        selectMonitor={options['select-monitor']}\n        testTemplates={options['test-templates']}\n        selectedTemplate={options['test-templates-sel']}\n        useCodemirror\n        socketOptions={\n          options['s:hostname'] && options['s:port']\n            ? {\n                hostname: options['s:hostname'],\n                port: options['s:port'],\n                secure: options['s:secure'],\n              }\n            : undefined\n        }\n      />,\n    );\n  },\n);\n"
  },
  {
    "path": "extension/src/remote/remote.pug",
    "content": "doctype html\r\n\r\nhtml\r\n  head\r\n    meta(charset='UTF-8')\r\n  title RemoteDev\r\n  include ../style.pug\r\n\r\n  body\r\n    #root\r\n    link(href='/remote.bundle.css', rel='stylesheet')\r\n    script(src='/remote.bundle.js')\r\n"
  },
  {
    "path": "extension/src/style.pug",
    "content": "style.\n  html {\n    height: 100%;\n    width: 100%;\n  }\n  body {\n    overflow: hidden;\n    height: 100%;\n    width: 100%;\n    min-width: 350px;\n    min-height: 400px;\n    margin: 0;\n    padding: 0;\n    font-family: \"Helvetica Neue\", \"Lucida Grande\", sans-serif;\n    font-size: 11px;\n    background-color: rgb(53, 59, 70);\n    color: #fff;\n  }\n  #root {\n    height: 100%;\n  }\n  #root > div {\n    height: 100%;\n  }\n  #root > div > div:nth-child(2) {\n    min-height: 0;\n  }\n  .ReactCodeMirror {\n    overflow: auto;\n    height: 100%;\n  }\n  button:disabled {\n    opacity: 0.5;\n    cursor: initial !important;\n  }\n\n  @media print {\n    @page {\n      size: auto;\n      margin: 0;\n    }\n\n    body {\n      position: static;\n    }\n\n    #root > div > div:not(:nth-child(2)) {\n      display: none !important;\n    }\n\n    #root > div > div:nth-child(2) {\n      overflow: visible !important;\n      position: absolute !important;\n      z-index: 2147483647;\n      page-break-after: avoid;\n    }\n\n    #root > div > div:nth-child(2) * {\n      overflow: visible !important;\n    }\n  }\n"
  },
  {
    "path": "extension/test/.eslintrc",
    "content": "{\n  \"env\": {\n    \"mocha\": true\n  },\n  \"globals\": {\n    \"UI\": true\n  },\n  \"rules\": {\n    \"no-unused-expressions\": 0\n  }\n}\n"
  },
  {
    "path": "extension/test/__mocks__/styleMock.js",
    "content": "export default {};\n"
  },
  {
    "path": "extension/test/app/containers/App.spec.jsx",
    "content": "import { jest } from '@jest/globals';\nimport React from 'react';\nimport { render, screen, within } from '@testing-library/react';\nimport { Provider } from 'react-redux';\nimport configureStore from '../../../src/devpanel/store/panelStore.js';\nimport App from '../../../src/app/App.js';\n\nObject.defineProperty(window, 'matchMedia', {\n  writable: true,\n  value: jest.fn().mockImplementation((query) => ({\n    matches: false,\n    media: query,\n    onchange: null,\n    addListener: jest.fn(), // deprecated\n    removeListener: jest.fn(), // deprecated\n    addEventListener: jest.fn(),\n    removeEventListener: jest.fn(),\n    dispatchEvent: jest.fn(),\n  })),\n});\n\nconst { store } = configureStore();\n\ndescribe('App container', () => {\n  it(\"should render inspector monitor's component\", () => {\n    render(\n      <Provider store={store}>\n        <App position=\"devtools-left\" />\n      </Provider>,\n    );\n    expect(screen.getByTestId('inspector')).toBeDefined();\n  });\n\n  it('should contain an empty action list', () => {\n    render(\n      <Provider store={store}>\n        <App position=\"devtools-left\" />\n      </Provider>,\n    );\n    const actionList = screen.getByTestId('actionList');\n    expect(within(actionList).queryByRole('button')).not.toBeInTheDocument();\n  });\n});\n"
  },
  {
    "path": "extension/test/app/inject/api.spec.js",
    "content": "import { jest } from '@jest/globals';\nimport { insertScript, listenMessage } from '../../utils/inject.js';\nimport '../../../src/pageScript/index.js';\n\ndescribe('API', () => {\n  it('should get window.__REDUX_DEVTOOLS_EXTENSION__ function', () => {\n    expect(typeof window.__REDUX_DEVTOOLS_EXTENSION__).toBe('function');\n  });\n\n  it('should notify error', () => {\n    const mockFunc = jest.fn(() => {});\n    window.__REDUX_DEVTOOLS_EXTENSION__.notifyErrors(mockFunc);\n    insertScript('hi()');\n    expect(mockFunc.mock.calls.length).toBeGreaterThan(0);\n  });\n\n  it('should open monitor', async () => {\n    let message = await listenMessage(() => {\n      window.__REDUX_DEVTOOLS_EXTENSION__.open();\n    });\n    expect(message).toEqual({\n      source: '@devtools-page',\n      type: 'OPEN',\n      position: 'window',\n    });\n  });\n\n  it('should send message', async () => {\n    let message = await listenMessage(() => {\n      window.__REDUX_DEVTOOLS_EXTENSION__.send('hi');\n    });\n    expect(message).toMatchObject({\n      type: 'ACTION',\n      payload: undefined,\n      instanceId: 1,\n      name: undefined,\n      source: '@devtools-page',\n    });\n    expect(message.action).toMatch(/{\"action\":{\"type\":\"hi\"},\"timestamp\":\\d+}/);\n\n    message = await listenMessage(() => {\n      window.__REDUX_DEVTOOLS_EXTENSION__.send(\n        { type: 'hi' },\n        { counter: 1 },\n        1,\n      );\n    });\n    expect(message).toMatchObject({\n      type: 'ACTION',\n      payload: '{\"counter\":1}',\n      instanceId: 1,\n      name: undefined,\n      source: '@devtools-page',\n    });\n    expect(message.action).toMatch(/{\"action\":{\"type\":\"hi\"},\"timestamp\":\\d+}/);\n\n    message = await listenMessage(() => {\n      window.__REDUX_DEVTOOLS_EXTENSION__.send(\n        { type: 'hi' },\n        { counter: 1 },\n        1,\n      );\n    });\n    expect(message).toMatchObject({\n      type: 'ACTION',\n      payload: '{\"counter\":1}',\n      instanceId: 1,\n      name: undefined,\n      source: '@devtools-page',\n    });\n    expect(message.action).toMatch(/{\"action\":{\"type\":\"hi\"},\"timestamp\":\\d+}/);\n\n    message = await listenMessage(() => {\n      window.__REDUX_DEVTOOLS_EXTENSION__.send(undefined, { counter: 1 }, 1);\n    });\n    expect(message).toEqual({\n      action: undefined,\n      type: 'STATE',\n      payload: { counter: 1 },\n      actionsById: undefined,\n      computedStates: undefined,\n      committedState: false,\n      instanceId: 1,\n      maxAge: undefined,\n      name: undefined,\n      source: '@devtools-page',\n    });\n  });\n});\n"
  },
  {
    "path": "extension/test/app/inject/enhancer.spec.js",
    "content": "import { createStore, compose } from 'redux';\nimport { insertScript, listenMessage } from '../../utils/inject.js';\nimport '../../../src/pageScript/index.js';\n\nfunction counter(state = 0, action) {\n  switch (action.type) {\n    case 'INCREMENT':\n      return state + 1;\n    case 'DECREMENT':\n      return state - 1;\n    default:\n      return state;\n  }\n}\n\ndescribe('Redux enhancer', () => {\n  it('should create the store', async () => {\n    const message = await listenMessage(() => {\n      window.store = createStore(\n        counter,\n        window.__REDUX_DEVTOOLS_EXTENSION__(),\n      );\n      expect(typeof window.store).toBe('object');\n    });\n    expect(message.type).toBe('INIT_INSTANCE');\n    expect(window.store.getState()).toBe(0);\n    insertScript('window.devToolsOptions = { serialize: false }');\n  });\n\n  it('should start monitoring', async () => {\n    let message = await listenMessage(() => {\n      window.postMessage({ type: 'START', source: '@devtools-extension' }, '*');\n    });\n    expect(message.type).toBe('START');\n\n    message = await listenMessage();\n    expect(message.type).toBe('STATE');\n    expect(message.actionsById).toMatch(\n      /{\"0\":{\"type\":\"PERFORM_ACTION\",\"action\":{\"type\":\"@@INIT\"},\"/,\n    );\n    expect(message.computedStates).toBe('[{\"state\":0}]');\n  });\n\n  it('should perform actions', async () => {\n    let message = await listenMessage(() => {\n      window.store.dispatch({ type: 'INCREMENT' });\n      expect(window.store.getState()).toBe(1);\n    });\n    expect(message.type).toBe('ACTION');\n    expect(message.action).toMatch(\n      /{\"type\":\"PERFORM_ACTION\",\"action\":{\"type\":\"INCREMENT\"},/,\n    );\n    expect(message.payload).toBe('1');\n\n    message = await listenMessage(() => {\n      window.store.dispatch({ type: 'INCREMENT' });\n      expect(window.store.getState()).toBe(2);\n    });\n    expect(message.type).toBe('ACTION');\n    expect(message.action).toMatch(\n      /{\"type\":\"PERFORM_ACTION\",\"action\":{\"type\":\"INCREMENT\"},/,\n    );\n    expect(message.payload).toBe('2');\n  });\n\n  it('should dispatch actions remotely', async () => {\n    let message = await listenMessage(() => {\n      window.postMessage(\n        {\n          type: 'ACTION',\n          payload: \"{ type: 'INCREMENT' }\",\n          source: '@devtools-extension',\n        },\n        '*',\n      );\n    });\n    expect(message.type).toBe('ACTION');\n\n    message = await listenMessage();\n    expect(message.type).toBe('ACTION');\n    expect(message.action).toMatch(\n      /{\"type\":\"PERFORM_ACTION\",\"action\":{\"type\":\"INCREMENT\"},/,\n    );\n    expect(message.payload).toBe('3');\n  });\n\n  it('should cancel (toggle) action', async () => {\n    let message = await listenMessage(() => {\n      window.postMessage(\n        {\n          type: 'DISPATCH',\n          payload: { type: 'TOGGLE_ACTION', id: 1 },\n          source: '@devtools-extension',\n        },\n        '*',\n      );\n    });\n    expect(message.type).toBe('DISPATCH');\n\n    message = await listenMessage();\n    expect(message.type).toBe('STATE');\n    expect(window.store.getState()).toBe(2);\n\n    message = await listenMessage(() => {\n      window.postMessage(\n        {\n          type: 'DISPATCH',\n          payload: { type: 'TOGGLE_ACTION', id: 1 },\n          source: '@devtools-extension',\n        },\n        '*',\n      );\n    });\n    expect(message.type).toBe('DISPATCH');\n\n    message = await listenMessage();\n    expect(message.type).toBe('STATE');\n    expect(window.store.getState()).toBe(3);\n  });\n\n  it('should move back and forward (time travel)', async () => {\n    let message = await listenMessage(() => {\n      window.postMessage(\n        {\n          type: 'DISPATCH',\n          payload: { type: 'JUMP_TO_STATE', index: 2, actionId: 2 },\n          source: '@devtools-extension',\n        },\n        '*',\n      );\n    });\n    expect(message.type).toBe('DISPATCH');\n    expect(window.store.getState()).toBe(2);\n\n    message = await listenMessage(() => {\n      window.postMessage(\n        {\n          type: 'DISPATCH',\n          payload: { type: 'JUMP_TO_STATE', index: 3, actionId: 3 },\n          source: '@devtools-extension',\n        },\n        '*',\n      );\n    });\n    expect(message.type).toBe('DISPATCH');\n    expect(window.store.getState()).toBe(3);\n  });\n\n  it('should import state history', async () => {\n    let message = await listenMessage(() => {\n      window.postMessage(\n        {\n          type: 'IMPORT',\n          state: JSON.stringify({\n            monitorState: {},\n            actionsById: {\n              0: { type: 'PERFORM_ACTION', action: { type: '@@INIT' } },\n              1: { type: 'PERFORM_ACTION', action: { type: 'INCREMENT' } },\n              2: { type: 'PERFORM_ACTION', action: { type: 'INCREMENT' } },\n            },\n            nextActionId: 3,\n            stagedActionIds: [0, 1, 2],\n            skippedActionIds: [],\n            currentStateIndex: 2,\n            computedStates: [{ state: 0 }, { state: 1 }, { state: 2 }],\n          }),\n          source: '@devtools-extension',\n        },\n        '*',\n      );\n    });\n    expect(message.type).toBe('IMPORT');\n    message = await listenMessage();\n    expect(message.type).toBe('STATE');\n    expect(window.store.getState()).toBe(2);\n  });\n\n  it('should create the store with config parameters', async () => {\n    const message = await listenMessage(() => {\n      window.store = createStore(\n        counter,\n        window.__REDUX_DEVTOOLS_EXTENSION__({\n          actionsDenylist: ['SOME_ACTION'],\n        }),\n      );\n      expect(typeof window.store).toBe('object');\n    });\n    expect(message.type).toBe('INIT_INSTANCE');\n  });\n\n  it('should create the store using old Redux api', async () => {\n    const message = await listenMessage(() => {\n      window.store =\n        window.__REDUX_DEVTOOLS_EXTENSION__()(createStore)(counter);\n      expect(typeof window.store).toBe('object');\n    });\n    expect(message.type).toBe('INIT_INSTANCE');\n  });\n\n  it('should create the store with several enhancers', async () => {\n    const testEnhancer = (next) => (reducer, initialState, enhancer) =>\n      next(reducer, initialState, enhancer);\n    const message = await listenMessage(() => {\n      window.store = createStore(\n        counter,\n        compose(testEnhancer, window.__REDUX_DEVTOOLS_EXTENSION__()),\n      );\n      expect(typeof window.store).toBe('object');\n    });\n    expect(message.type).toBe('INIT_INSTANCE');\n  });\n});\n"
  },
  {
    "path": "extension/test/chrome/extension.spec.js",
    "content": "import { resolve } from 'path';\nimport webdriver from 'selenium-webdriver';\nimport chrome from 'selenium-webdriver/chrome';\nimport { switchMonitorTests, delay } from '../utils/e2e.js';\n\nconst path = resolve(import.meta.dirname, '..', '..', 'dist');\nconst extensionId = 'lmhkpmbekcpmknklioeibfkpmmfibljd';\nconst actionsPattern =\n  /^@@INIT(.|\\n)+@@reduxReactRouter\\/routerDidChange(.|\\n)+@@reduxReactRouter\\/initRoutes(.|\\n)+$/;\n\ndescribe('Chrome extension', function () {\n  let driver;\n\n  beforeAll(async () => {\n    driver = new webdriver.Builder()\n      .setChromeOptions(\n        new chrome.Options()\n          .setBrowserVersion('stable')\n          .addArguments(`load-extension=${path}`),\n      )\n      .forBrowser('chrome')\n      .build();\n  });\n\n  afterAll(async () => {\n    await driver.quit();\n  });\n\n  it(\"should open extension's window\", async () => {\n    await driver.get(`chrome-extension://${extensionId}/devpanel.html`);\n    const url = await driver.getCurrentUrl();\n    expect(url).toBe(`chrome-extension://${extensionId}/devpanel.html`);\n  });\n\n  it('should match document title', async () => {\n    const title = await driver.getTitle();\n    expect(title).toBe('Redux DevTools');\n  });\n\n  it('should get actions list', async () => {\n    const url = 'https://zalmoxisus.github.io/examples/router/';\n    await driver.executeScript(`window.open('${url}')`);\n    await delay(2000);\n\n    const tabs = await driver.getAllWindowHandles();\n\n    await driver.switchTo().window(tabs[1]);\n    expect(await driver.getCurrentUrl()).toMatch(url);\n\n    await driver.switchTo().window(tabs[0]);\n\n    await delay(1000);\n    const result = await driver.wait(\n      driver\n        .findElement(webdriver.By.xpath('//div[@data-testid=\"actionListRows\"]'))\n        .getText()\n        .then((val) => {\n          return actionsPattern.test(val);\n        }),\n      15000,\n      \"it doesn't match actions pattern\",\n    );\n    expect(result).toBeTruthy();\n  });\n\n  it(\"should contain inspector monitor's component\", async () => {\n    const val = await driver\n      .findElement(webdriver.By.xpath('//div[@data-testid=\"inspector\"]'))\n      .getText();\n    expect(val).toBeDefined();\n  });\n\n  Object.keys(switchMonitorTests).forEach((description) =>\n    // eslint-disable-next-line jest/expect-expect,jest/valid-title\n    it(description, () => switchMonitorTests[description](driver)),\n  );\n});\n"
  },
  {
    "path": "extension/test/electron/devpanel.spec.js",
    "content": "import { join } from 'path';\nimport webdriver from 'selenium-webdriver';\nimport chrome from 'selenium-webdriver/chrome';\nimport electronPath from 'electron';\nimport chromedriver from 'chromedriver';\nimport { switchMonitorTests, delay } from '../utils/e2e.js';\n\nconst devPanelPath =\n  'chrome-extension://lmhkpmbekcpmknklioeibfkpmmfibljd/devpanel.html';\n\ndescribe('DevTools panel for Electron', function () {\n  let driver;\n\n  beforeAll(async () => {\n    chromedriver.start(['--port=9515']);\n    await delay(1000);\n    driver = new webdriver.Builder()\n      .usingServer('http://localhost:9515')\n      .setChromeOptions(\n        new chrome.Options()\n          .setChromeBinaryPath(electronPath)\n          .addArguments(`app=${join(import.meta.dirname, 'fixture')}`),\n      )\n      .forBrowser('chrome')\n      .build();\n  });\n\n  afterAll(async () => {\n    await driver.quit();\n    chromedriver.stop();\n  });\n\n  it('should open Redux DevTools tab', async () => {\n    if (!(await driver.getCurrentUrl()).startsWith('devtools')) {\n      const originalWindow = await driver.getWindowHandle();\n      const windows = await driver.getAllWindowHandles();\n      for (const window of windows) {\n        if (window === originalWindow) continue;\n        await driver.switchTo().window(window);\n        if ((await driver.getCurrentUrl()).startsWith('devtools')) {\n          break;\n        }\n      }\n    }\n    expect(await driver.getCurrentUrl()).toMatch(\n      /devtools:\\/\\/devtools\\/bundled\\/devtools_app.html/,\n    );\n\n    const id = await driver.executeAsyncScript(function (callback) {\n      let attempts = 5;\n      function showReduxPanel() {\n        if (attempts === 0) {\n          return callback('Redux panel not found');\n        }\n        if (EUI.InspectorView) {\n          const instance = EUI.InspectorView.InspectorView.instance();\n          const tabs = instance.tabbedPane.tabs;\n          const idList = tabs.map((tab) => tab.id);\n          const reduxPanelId =\n            'chrome-extension://lmhkpmbekcpmknklioeibfkpmmfibljdRedux';\n          if (idList.indexOf(reduxPanelId) !== -1) {\n            instance.showPanel(reduxPanelId);\n            return callback(reduxPanelId);\n          }\n        }\n        attempts--;\n        setTimeout(showReduxPanel, 500);\n      }\n      showReduxPanel();\n    });\n    expect(id).toBe('chrome-extension://lmhkpmbekcpmknklioeibfkpmmfibljdRedux');\n\n    const className = await driver\n      .findElement(webdriver.By.className(id))\n      .getAttribute('class');\n    expect(className).not.toMatch(/hidden/); // not hidden\n  });\n\n  // eslint-disable-next-line jest/expect-expect\n  it('should have Redux DevTools UI on current tab', async () => {\n    await driver\n      .switchTo()\n      .frame(\n        driver.findElement(\n          webdriver.By.xpath(`//iframe[@src='${devPanelPath}']`),\n        ),\n      );\n    await delay(1000);\n  });\n\n  it('should contain INIT action', async () => {\n    const element = await driver.wait(\n      webdriver.until.elementLocated(\n        webdriver.By.xpath('//div[@data-testid=\"actionListRows\"]'),\n      ),\n      5000,\n      'Element not found',\n    );\n    const val = await element.getText();\n    expect(val).toMatch(/@@INIT/);\n  });\n\n  it(\"should contain Inspector monitor's component\", async () => {\n    const val = await driver\n      .findElement(webdriver.By.xpath('//div[@data-testid=\"inspector\"]'))\n      .getText();\n    expect(val).toBeDefined();\n  });\n\n  Object.keys(switchMonitorTests).forEach((description) =>\n    // eslint-disable-next-line jest/expect-expect,jest/valid-title\n    it(description, () => switchMonitorTests[description](driver)),\n  );\n\n  // eslint-disable-next-line jest/no-commented-out-tests\n  /*  it('should be no logs in console of main window', async () => {\n    const handles = await driver.getAllWindowHandles();\n    await driver.switchTo().window(handles[1]); // Change to main window\n\n    expect(await driver.getTitle()).toBe('Electron Test');\n\n    const logs = await driver.manage().logs().get(webdriver.logging.Type.BROWSER);\n    expect(logs).toEqual([]);\n  });\n*/\n});\n"
  },
  {
    "path": "extension/test/electron/fixture/index.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Electron Test</title>\n  </head>\n  <body>\n    <span id=\"counter\">0</span>\n    <button id=\"increment\">+</button>\n    <button id=\"decrement\">-</button>\n    <script src=\"./dist/renderer.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "extension/test/electron/fixture/main.js",
    "content": "const path = require('path');\nconst { app, BrowserWindow, session } = require('electron');\n\napp.on('window-all-closed', app.quit);\napp.whenReady().then(async () => {\n  await session.defaultSession.loadExtension(\n    path.join(__dirname, '../../../dist'),\n    { allowFileAccess: true },\n  );\n\n  const mainWindow = new BrowserWindow({\n    width: 150,\n    height: 100,\n    webPreferences: {\n      nodeIntegration: true,\n      contextIsolation: false,\n    },\n  });\n  mainWindow.loadFile('index.html');\n  mainWindow.webContents.openDevTools({ mode: 'detach' });\n});\n"
  },
  {
    "path": "extension/test/electron/fixture/package.json",
    "content": "{\n  \"name\": \"electron-test\",\n  \"productName\": \"Electron Test\",\n  \"main\": \"main.js\",\n  \"version\": \"0.1.0\"\n}\n"
  },
  {
    "path": "extension/test/electron/fixture/src/renderer.js",
    "content": "const { createStore } = require('redux');\n\nconst INCREMENT_COUNTER = 'INCREMENT_COUNTER';\nconst DECREMENT_COUNTER = 'DECREMENT_COUNTER';\n\nconst initialState = { value: 0 };\n\nconst store = createStore(\n  (state, action) => {\n    switch (action.type) {\n      case INCREMENT_COUNTER:\n        return { value: state.value + 1 };\n      case DECREMENT_COUNTER:\n        return { value: state.value - 1 };\n      default:\n        return state;\n    }\n  },\n  initialState,\n  window.__REDUX_DEVTOOLS_EXTENSION__\n    ? window.__REDUX_DEVTOOLS_EXTENSION__()\n    : (noop) => noop,\n);\n\nconst el = document.getElementById('counter');\n\nstore.subscribe(() => {\n  el.innerHTML = store.getState().value;\n});\n\nconst increment = document.getElementById('increment');\nconst decrement = document.getElementById('decrement');\nincrement.onclick = () => store.dispatch({ type: INCREMENT_COUNTER });\ndecrement.onclick = () => store.dispatch({ type: DECREMENT_COUNTER });\n"
  },
  {
    "path": "extension/test/electron/fixture/webpack.config.js",
    "content": "const path = require('path');\n\nmodule.exports = {\n  mode: 'development',\n  entry: './test/electron/fixture/src/renderer.js',\n  output: {\n    filename: 'renderer.js',\n    path: path.resolve(__dirname, 'dist'),\n  },\n};\n"
  },
  {
    "path": "extension/test/perf/data.js",
    "content": "// Source: http://beta.json-generator.com/V1omRaUJG\n/* eslint-disable */\n\nexport const bigString = Array(10000000).join('t');\n\nexport const bigArray = [\n  {\n    _id: '580ddf0b168ab8fe470be6e0',\n    index: 0,\n    guid: '2ce09bef-e6a5-4894-b720-74c9eb72098d',\n    isActive: true,\n    balance: '$3,164.44',\n    picture: 'http://placehold.it/32x32',\n    age: 30,\n    eyeColor: 'green',\n    name: {\n      first: 'Kenya',\n      last: 'Hoover',\n    },\n    company: 'QUALITERN',\n    email: 'kenya.hoover@qualitern.biz',\n    phone: '+1 (829) 556-2040',\n    address: '605 Glenwood Road, Cherokee, Oklahoma, 8113',\n    about:\n      'Fugiat dolore ut esse ullamco incididunt culpa qui pariatur mollit nostrud incididunt. Quis pariatur sunt ut ipsum qui consequat sit dolore consequat esse elit consectetur do. Cillum labore cupidatat ipsum laboris. Non nisi minim adipisicing et culpa consectetur mollit incididunt ullamco. Non velit ea irure aute aliqua et incididunt officia laborum.',\n    registered: 'Monday, June 22, 2015 9:38 AM',\n    latitude: '84.835869',\n    longitude: '64.139911',\n    tags: ['eiusmod', 'aute', 'ipsum', 'ad', 'mollit'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Alba Bartlett',\n      },\n      {\n        id: 1,\n        name: 'Andrews Mcleod',\n      },\n      {\n        id: 2,\n        name: 'Elise Velazquez',\n      },\n    ],\n    greeting: 'Hello, Kenya! You have 8 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0bc26524220b80fa59',\n    index: 1,\n    guid: '80713a26-75b0-4a4e-914d-52f31fade72c',\n    isActive: true,\n    balance: '$1,455.30',\n    picture: 'http://placehold.it/32x32',\n    age: 28,\n    eyeColor: 'blue',\n    name: {\n      first: 'Jami',\n      last: 'Mcfarland',\n    },\n    company: 'LIMAGE',\n    email: 'jami.mcfarland@limage.co.uk',\n    phone: '+1 (944) 566-3918',\n    address: '804 Montgomery Place, Henrietta, Alaska, 9608',\n    about:\n      'Velit esse ut dolor Lorem laboris esse aute est pariatur tempor esse aute ut ut. In magna esse aute ea cillum qui mollit consectetur minim qui pariatur. Sit consequat fugiat ut veniam non ut deserunt culpa velit ex id laborum tempor. Duis est amet sunt id sunt. Ullamco minim officia irure quis veniam ipsum. Minim proident commodo ea ea dolore. Velit sunt magna commodo quis est dolor eiusmod aliqua occaecat tempor ut.',\n    registered: 'Saturday, October 24, 2015 9:38 AM',\n    latitude: '-39.25774',\n    longitude: '-118.315297',\n    tags: ['voluptate', 'dolor', 'enim', 'reprehenderit', 'et'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Goff Compton',\n      },\n      {\n        id: 1,\n        name: 'Sherry Randall',\n      },\n      {\n        id: 2,\n        name: 'Janell Mcconnell',\n      },\n    ],\n    greeting: 'Hello, Jami! You have 9 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0b8b30c17733f75cf3',\n    index: 2,\n    guid: 'dca38381-500a-4f4e-823a-d95484f9e87d',\n    isActive: false,\n    balance: '$1,451.88',\n    picture: 'http://placehold.it/32x32',\n    age: 27,\n    eyeColor: 'brown',\n    name: {\n      first: 'Jodie',\n      last: 'Holder',\n    },\n    company: 'AVIT',\n    email: 'jodie.holder@avit.us',\n    phone: '+1 (948) 512-2550',\n    address:\n      '371 Stockholm Street, Wattsville, Federated States Of Micronesia, 4778',\n    about:\n      'Voluptate nisi commodo duis sunt. Magna consectetur minim consectetur esse excepteur adipisicing laboris. Culpa sunt culpa sit exercitation. Duis ea culpa aliqua do exercitation adipisicing ullamco ut officia occaecat incididunt dolore nisi. Tempor est proident cillum nulla do exercitation dolor incididunt. Aute magna aliquip elit irure dolor anim voluptate.',\n    registered: 'Sunday, April 5, 2015 12:27 PM',\n    latitude: '68.671844',\n    longitude: '100.317594',\n    tags: ['Lorem', 'qui', 'do', 'excepteur', 'duis'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Mason Carroll',\n      },\n      {\n        id: 1,\n        name: 'Bonnie Ross',\n      },\n      {\n        id: 2,\n        name: 'Shields Mays',\n      },\n    ],\n    greeting: 'Hello, Jodie! You have 5 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0bd7a19dd3361592b6',\n    index: 3,\n    guid: '0c45af75-ee65-427a-a462-e01d5a3d882f',\n    isActive: true,\n    balance: '$1,883.45',\n    picture: 'http://placehold.it/32x32',\n    age: 25,\n    eyeColor: 'brown',\n    name: {\n      first: 'Britney',\n      last: 'Ryan',\n    },\n    company: 'BUNGA',\n    email: 'britney.ryan@bunga.name',\n    phone: '+1 (996) 502-2698',\n    address: '520 Monument Walk, Shindler, Iowa, 1721',\n    about:\n      'Cupidatat aute est consectetur eiusmod ut veniam qui sit adipisicing Lorem nostrud proident deserunt exercitation. Laborum ullamco minim nisi nulla ullamco fugiat laboris nisi eiusmod ullamco enim aliqua deserunt. Occaecat anim aliquip est sunt voluptate qui dolore. Minim mollit et esse quis tempor eu anim deserunt nostrud. Voluptate amet voluptate eu anim culpa quis. Non do aliqua sit cupidatat eiusmod commodo in sit esse consequat. Cupidatat elit do exercitation ex proident ex nulla ex ad ut.',\n    registered: 'Tuesday, January 19, 2016 12:05 PM',\n    latitude: '-12.692828',\n    longitude: '172.541591',\n    tags: ['fugiat', 'fugiat', 'anim', 'magna', 'in'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Jeanette Paul',\n      },\n      {\n        id: 1,\n        name: 'Jones Sherman',\n      },\n      {\n        id: 2,\n        name: 'Pruitt Gross',\n      },\n    ],\n    greeting: 'Hello, Britney! You have 8 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0bdb18815e253438a8',\n    index: 4,\n    guid: '35df48d8-e840-43fc-b99c-f078a0c028d5',\n    isActive: false,\n    balance: '$2,753.26',\n    picture: 'http://placehold.it/32x32',\n    age: 20,\n    eyeColor: 'blue',\n    name: {\n      first: 'West',\n      last: 'Sharp',\n    },\n    company: 'GROK',\n    email: 'west.sharp@grok.info',\n    phone: '+1 (947) 561-3088',\n    address: '217 Clay Street, Fingerville, Puerto Rico, 382',\n    about:\n      'Tempor ut ex aliqua ipsum. Ipsum fugiat dolor exercitation mollit eiusmod duis nulla occaecat excepteur ea irure minim minim sit. Proident esse id deserunt tempor dolor sit consectetur proident deserunt fugiat excepteur laborum. Incididunt fugiat id fugiat id Lorem est sit aliqua sit officia excepteur nulla mollit. Aliquip nulla nisi ea qui ex non nostrud culpa et anim. Velit labore esse id exercitation ex duis aliquip est ea eu. Sint Lorem mollit deserunt adipisicing do amet laborum velit nostrud commodo enim fugiat anim pariatur.',\n    registered: 'Tuesday, May 10, 2016 2:56 PM',\n    latitude: '6.032735',\n    longitude: '-168.931741',\n    tags: ['non', 'aliquip', 'ullamco', 'ex', 'veniam'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Head Riley',\n      },\n      {\n        id: 1,\n        name: 'Meyer Oneal',\n      },\n      {\n        id: 2,\n        name: 'Molina Tyson',\n      },\n    ],\n    greeting: 'Hello, West! You have 6 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0ba2234b9e4a2b47b2',\n    index: 5,\n    guid: '16a1e635-f30b-49d7-b0f2-69ee74313900',\n    isActive: true,\n    balance: '$3,982.09',\n    picture: 'http://placehold.it/32x32',\n    age: 40,\n    eyeColor: 'blue',\n    name: {\n      first: 'Manuela',\n      last: 'Henry',\n    },\n    company: 'MEDCOM',\n    email: 'manuela.henry@medcom.io',\n    phone: '+1 (876) 521-2923',\n    address: '112 Clove Road, Cliffside, Kansas, 6979',\n    about:\n      'Exercitation ea esse aliquip sint nisi consequat dolor adipisicing do pariatur et id est voluptate. In occaecat dolor exercitation do aliquip cillum in. Deserunt nisi deserunt Lorem aliqua adipisicing. Consequat eiusmod occaecat pariatur mollit aliqua non tempor aliquip sint consequat sit enim. Elit consectetur dolor sint ipsum officia in duis laboris irure aliquip ea labore. Aliquip ullamco fugiat dolore fugiat id. Deserunt id amet eiusmod tempor do tempor ut laborum.',\n    registered: 'Wednesday, March 4, 2015 4:00 PM',\n    latitude: '-53.534313',\n    longitude: '101.348892',\n    tags: ['sint', 'voluptate', 'duis', 'laboris', 'nisi'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Beryl Chang',\n      },\n      {\n        id: 1,\n        name: 'Pierce Simpson',\n      },\n      {\n        id: 2,\n        name: 'Sonja Pacheco',\n      },\n    ],\n    greeting: 'Hello, Manuela! You have 6 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0b39bcca5393e6b4a5',\n    index: 6,\n    guid: '4c69c263-a646-4446-adfe-eeac5481ade3',\n    isActive: false,\n    balance: '$1,557.52',\n    picture: 'http://placehold.it/32x32',\n    age: 36,\n    eyeColor: 'green',\n    name: {\n      first: 'Marcy',\n      last: 'Collier',\n    },\n    company: 'KINETICA',\n    email: 'marcy.collier@kinetica.com',\n    phone: '+1 (812) 599-2621',\n    address: '701 Melrose Street, Cloverdale, North Dakota, 8703',\n    about:\n      'Cupidatat velit cupidatat officia ad. Nulla cupidatat esse velit velit. Officia amet ea cupidatat sint consequat cupidatat. Eiusmod deserunt laborum qui proident tempor ullamco tempor officia laborum cillum ipsum commodo mollit.',\n    registered: 'Sunday, December 7, 2014 11:48 PM',\n    latitude: '19.152716',\n    longitude: '119.251991',\n    tags: ['minim', 'qui', 'exercitation', 'tempor', 'sunt'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Estes Porter',\n      },\n      {\n        id: 1,\n        name: 'Sheila Miller',\n      },\n      {\n        id: 2,\n        name: 'Bell Rosario',\n      },\n    ],\n    greeting: 'Hello, Marcy! You have 9 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0b0887381e90657c23',\n    index: 7,\n    guid: '80b50d03-70cd-4ce5-b6c7-c3d60b9e29ff',\n    isActive: false,\n    balance: '$3,203.72',\n    picture: 'http://placehold.it/32x32',\n    age: 34,\n    eyeColor: 'green',\n    name: {\n      first: 'Esperanza',\n      last: 'Mack',\n    },\n    company: 'FURNAFIX',\n    email: 'esperanza.mack@furnafix.tv',\n    phone: '+1 (948) 511-2731',\n    address: '502 Bliss Terrace, Marenisco, Northern Mariana Islands, 7773',\n    about:\n      'Proident deserunt ipsum aute irure laboris nisi non velit officia nisi anim. Magna nisi eiusmod deserunt ad veniam sit ullamco sit fugiat officia dolor incididunt id irure. Laborum id fugiat pariatur dolor proident Lorem do ex occaecat.',\n    registered: 'Sunday, April 24, 2016 9:33 AM',\n    latitude: '79.033601',\n    longitude: '138.782377',\n    tags: ['velit', 'sint', 'est', 'proident', 'in'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Roy Clemons',\n      },\n      {\n        id: 1,\n        name: 'Baldwin Glenn',\n      },\n      {\n        id: 2,\n        name: 'Castaneda Combs',\n      },\n    ],\n    greeting: 'Hello, Esperanza! You have 6 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0bee6486345816b9f4',\n    index: 8,\n    guid: '629ee6bb-bbe3-4f7e-9f6c-b8b53761e7b5',\n    isActive: false,\n    balance: '$2,112.11',\n    picture: 'http://placehold.it/32x32',\n    age: 37,\n    eyeColor: 'green',\n    name: {\n      first: 'Bender',\n      last: 'Sheppard',\n    },\n    company: 'PROXSOFT',\n    email: 'bender.sheppard@proxsoft.net',\n    phone: '+1 (986) 490-3036',\n    address: '509 Fuller Place, Dodge, Montana, 1706',\n    about:\n      'Ullamco dolore fugiat nulla non amet Lorem elit ullamco ipsum. Mollit anim do eiusmod esse sint esse voluptate exercitation ipsum ut nulla. Dolore pariatur eiusmod amet reprehenderit. Ea officia in ipsum laborum officia id tempor quis nostrud id ex id duis. Eiusmod incididunt voluptate duis sint laborum.',\n    registered: 'Sunday, June 19, 2016 8:45 AM',\n    latitude: '-35.720137',\n    longitude: '-49.926356',\n    tags: ['enim', 'cupidatat', 'cupidatat', 'tempor', 'cupidatat'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Owens Branch',\n      },\n      {\n        id: 1,\n        name: 'Williams Boone',\n      },\n      {\n        id: 2,\n        name: 'Doris Morrison',\n      },\n    ],\n    greeting: 'Hello, Bender! You have 5 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0b4b41ebbb13abd5d0',\n    index: 9,\n    guid: '54401f5b-ae5f-412c-9149-7a361a73e02f',\n    isActive: true,\n    balance: '$1,483.87',\n    picture: 'http://placehold.it/32x32',\n    age: 26,\n    eyeColor: 'brown',\n    name: {\n      first: 'Summers',\n      last: 'Donaldson',\n    },\n    company: 'ARTIQ',\n    email: 'summers.donaldson@artiq.org',\n    phone: '+1 (972) 486-2456',\n    address: '980 Pierrepont Street, Gerber, Ohio, 9892',\n    about:\n      'Proident veniam officia sunt esse culpa labore anim quis do. Sunt ullamco elit amet incididunt fugiat magna id do veniam ullamco et anim. Aute labore pariatur ex ea deserunt nulla Lorem adipisicing non ad. Id ea proident voluptate aliqua velit aliquip enim incididunt. Do ipsum ipsum voluptate voluptate aliquip ex officia velit in officia ex esse aute.',\n    registered: 'Tuesday, December 30, 2014 1:21 AM',\n    latitude: '-83.907394',\n    longitude: '10.741994',\n    tags: ['laborum', 'proident', 'occaecat', 'elit', 'occaecat'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Love Lott',\n      },\n      {\n        id: 1,\n        name: 'Johnson Clay',\n      },\n      {\n        id: 2,\n        name: 'Nelson Blair',\n      },\n    ],\n    greeting: 'Hello, Summers! You have 8 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0bc2e80831e45b4dc6',\n    index: 10,\n    guid: '0e7ba51d-202e-4e28-a6a5-a9b6ec63abd4',\n    isActive: false,\n    balance: '$3,079.46',\n    picture: 'http://placehold.it/32x32',\n    age: 38,\n    eyeColor: 'blue',\n    name: {\n      first: 'Shelby',\n      last: 'Conway',\n    },\n    company: 'ZINCA',\n    email: 'shelby.conway@zinca.me',\n    phone: '+1 (985) 510-2634',\n    address: '955 Seagate Terrace, Verdi, Oregon, 6649',\n    about:\n      'Incididunt aliqua veniam elit ea cupidatat dolore. Ipsum culpa ut consequat velit sint sint ad. Ex fugiat consequat et sit ex sit esse ullamco magna reprehenderit ea id reprehenderit. Adipisicing et esse commodo sit Lorem ipsum ea fugiat officia do et culpa reprehenderit sunt.',\n    registered: 'Tuesday, March 1, 2016 12:46 PM',\n    latitude: '79.379348',\n    longitude: '-179.029537',\n    tags: ['elit', 'dolore', 'in', 'excepteur', 'sit'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Dean Salinas',\n      },\n      {\n        id: 1,\n        name: 'Josie Calhoun',\n      },\n      {\n        id: 2,\n        name: 'Huffman Walton',\n      },\n    ],\n    greeting: 'Hello, Shelby! You have 10 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0b38c03f61248fbb18',\n    index: 11,\n    guid: '004be9ab-5520-4f85-b6e9-806c701faafe',\n    isActive: false,\n    balance: '$3,974.78',\n    picture: 'http://placehold.it/32x32',\n    age: 23,\n    eyeColor: 'green',\n    name: {\n      first: 'Reynolds',\n      last: 'Hurley',\n    },\n    company: 'TELLIFLY',\n    email: 'reynolds.hurley@tellifly.ca',\n    phone: '+1 (906) 482-2018',\n    address: '364 Jackson Court, Edmund, Arizona, 5300',\n    about:\n      'Aute deserunt labore consectetur non anim culpa mollit. Cillum Lorem excepteur esse non anim. Duis aliqua id laborum ex mollit id tempor nisi non voluptate. Nostrud enim in labore consequat id laboris Lorem veniam veniam amet. Laboris nostrud dolore proident labore incididunt elit quis officia elit est exercitation veniam aute.',\n    registered: 'Friday, May 27, 2016 1:32 PM',\n    latitude: '-5.022457',\n    longitude: '96.958037',\n    tags: ['sit', 'laboris', 'Lorem', 'dolor', 'sint'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Heidi Flores',\n      },\n      {\n        id: 1,\n        name: 'Armstrong Middleton',\n      },\n      {\n        id: 2,\n        name: 'Figueroa Camacho',\n      },\n    ],\n    greeting: 'Hello, Reynolds! You have 9 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0b1835b3ed2579bfc0',\n    index: 12,\n    guid: '88c12f0a-23df-4161-8e3a-c6c3101292f2',\n    isActive: false,\n    balance: '$1,419.27',\n    picture: 'http://placehold.it/32x32',\n    age: 38,\n    eyeColor: 'blue',\n    name: {\n      first: 'Young',\n      last: 'Santiago',\n    },\n    company: 'GINKLE',\n    email: 'young.santiago@ginkle.biz',\n    phone: '+1 (922) 566-2702',\n    address: '278 Bartlett Place, Tetherow, Vermont, 191',\n    about:\n      'Est consectetur esse culpa ullamco. Dolore voluptate aute consequat voluptate. Exercitation fugiat est anim qui exercitation nostrud.',\n    registered: 'Tuesday, June 28, 2016 7:18 AM',\n    latitude: '-43.055507',\n    longitude: '45.085776',\n    tags: ['sit', 'Lorem', 'deserunt', 'fugiat', 'cupidatat'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Sheryl Smith',\n      },\n      {\n        id: 1,\n        name: 'Felicia Mcintosh',\n      },\n      {\n        id: 2,\n        name: 'Hoover Hardy',\n      },\n    ],\n    greeting: 'Hello, Young! You have 5 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0bf31dbaaeb3c9cfcd',\n    index: 13,\n    guid: '3a39f0ef-3659-4e01-b2d7-bb537fdd1a3a',\n    isActive: false,\n    balance: '$2,529.26',\n    picture: 'http://placehold.it/32x32',\n    age: 34,\n    eyeColor: 'blue',\n    name: {\n      first: 'Trina',\n      last: 'Decker',\n    },\n    company: 'SULTRAXIN',\n    email: 'trina.decker@sultraxin.co.uk',\n    phone: '+1 (980) 524-2887',\n    address: '874 Llama Court, Klondike, California, 293',\n    about:\n      'Ad duis Lorem nulla ex. Proident pariatur Lorem pariatur fugiat deserunt duis incididunt esse eiusmod officia. Eiusmod quis pariatur mollit sint exercitation aute. Mollit enim consequat aliqua quis. Fugiat Lorem do duis aute sit dolore.',\n    registered: 'Friday, February 19, 2016 1:30 PM',\n    latitude: '15.917567',\n    longitude: '-1.518009',\n    tags: ['ex', 'sit', 'enim', 'consequat', 'sit'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Wyatt Pickett',\n      },\n      {\n        id: 1,\n        name: 'Valarie Barr',\n      },\n      {\n        id: 2,\n        name: 'Pace Best',\n      },\n    ],\n    greeting: 'Hello, Trina! You have 6 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0b3934d0edbaeaba18',\n    index: 14,\n    guid: 'd5f5a79c-de56-4aca-bcc4-1b9df58a2b1d',\n    isActive: false,\n    balance: '$3,670.31',\n    picture: 'http://placehold.it/32x32',\n    age: 35,\n    eyeColor: 'green',\n    name: {\n      first: 'Tasha',\n      last: 'Merritt',\n    },\n    company: 'RODEOCEAN',\n    email: 'tasha.merritt@rodeocean.us',\n    phone: '+1 (940) 421-2122',\n    address: '790 Suydam Place, Keyport, Idaho, 2211',\n    about:\n      'Ad elit cillum laboris laborum ut minim aute non ullamco ipsum incididunt labore officia velit. Cillum sunt do laboris enim eiusmod ad elit nostrud est deserunt quis. Consectetur ea ex consectetur commodo cillum sunt mollit Lorem ea sunt sit ut magna. Quis labore fugiat aliquip non consectetur est. Ut pariatur duis veniam ut exercitation est est. Ullamco dolore nulla est pariatur.',\n    registered: 'Wednesday, October 22, 2014 11:57 PM',\n    latitude: '12.554934',\n    longitude: '-149.800679',\n    tags: ['reprehenderit', 'ex', 'tempor', 'sint', 'exercitation'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Dennis Mills',\n      },\n      {\n        id: 1,\n        name: 'Vargas Guerrero',\n      },\n      {\n        id: 2,\n        name: 'Hollie Chavez',\n      },\n    ],\n    greeting: 'Hello, Tasha! You have 6 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0bafee284452c9a02e',\n    index: 15,\n    guid: 'b35eff37-836a-4928-9a06-701c2bc32881',\n    isActive: true,\n    balance: '$2,931.23',\n    picture: 'http://placehold.it/32x32',\n    age: 24,\n    eyeColor: 'blue',\n    name: {\n      first: 'Maryann',\n      last: 'Ewing',\n    },\n    company: 'ASSISTIA',\n    email: 'maryann.ewing@assistia.name',\n    phone: '+1 (911) 512-2851',\n    address: '450 Seeley Street, Winfred, Mississippi, 587',\n    about:\n      'Aliquip et Lorem aliquip aute adipisicing nisi incididunt deserunt non ipsum irure cillum voluptate. Sunt exercitation irure mollit proident anim ut veniam enim ullamco eiusmod do sint aliqua aliqua. Enim sunt quis exercitation culpa velit. Officia commodo amet enim quis ipsum non Lorem non excepteur. Quis aute elit irure elit sit ullamco cupidatat ullamco enim et cillum id.',\n    registered: 'Friday, June 17, 2016 2:12 PM',\n    latitude: '47.215077',\n    longitude: '81.317216',\n    tags: ['commodo', 'id', 'nulla', 'pariatur', 'exercitation'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Sue Finley',\n      },\n      {\n        id: 1,\n        name: 'Chandler Mccarty',\n      },\n      {\n        id: 2,\n        name: 'Laura Coleman',\n      },\n    ],\n    greeting: 'Hello, Maryann! You have 8 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0b5b3b1890b6b64d7b',\n    index: 16,\n    guid: 'ef7682f0-23ff-479d-8a81-54d01e2641ec',\n    isActive: true,\n    balance: '$1,841.30',\n    picture: 'http://placehold.it/32x32',\n    age: 30,\n    eyeColor: 'brown',\n    name: {\n      first: 'Hammond',\n      last: 'Koch',\n    },\n    company: 'CYCLONICA',\n    email: 'hammond.koch@cyclonica.info',\n    phone: '+1 (974) 481-2184',\n    address: '141 Exeter Street, Kipp, Alabama, 643',\n    about:\n      'Ullamco aliqua id veniam ea do. Commodo dolore fugiat ut aliquip. Est ut qui elit amet. Aliquip mollit occaecat consequat id exercitation eu fugiat voluptate culpa labore eiusmod aliqua cillum. Eu amet consequat deserunt enim qui mollit aliqua nisi ad ut veniam elit pariatur.',\n    registered: 'Sunday, July 13, 2014 10:47 PM',\n    latitude: '8.698118',\n    longitude: '-68.775186',\n    tags: ['id', 'voluptate', 'labore', 'magna', 'Lorem'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Mildred Brewer',\n      },\n      {\n        id: 1,\n        name: 'Buck Potts',\n      },\n      {\n        id: 2,\n        name: 'Kline Valencia',\n      },\n    ],\n    greeting: 'Hello, Hammond! You have 5 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0be6e62a7ef65bf203',\n    index: 17,\n    guid: '2c45743d-dfe7-4621-acc2-7664fc7a39f1',\n    isActive: true,\n    balance: '$3,281.24',\n    picture: 'http://placehold.it/32x32',\n    age: 23,\n    eyeColor: 'blue',\n    name: {\n      first: 'Holt',\n      last: 'Pennington',\n    },\n    company: 'NORALEX',\n    email: 'holt.pennington@noralex.io',\n    phone: '+1 (948) 557-3137',\n    address: '483 Woodruff Avenue, Kapowsin, Illinois, 6162',\n    about:\n      'Nisi non consectetur est deserunt nisi aliqua. Mollit labore dolore ex ex id eu proident nostrud deserunt consequat nostrud. Ad irure duis ex enim commodo proident ullamco esse. Ex sit eiusmod occaecat minim nulla ut Lorem Lorem. Quis est in et est cupidatat fugiat dolor minim voluptate.',\n    registered: 'Saturday, September 20, 2014 3:43 AM',\n    latitude: '-1.585287',\n    longitude: '-32.054323',\n    tags: ['ex', 'adipisicing', 'est', 'aute', 'amet'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Irma Wynn',\n      },\n      {\n        id: 1,\n        name: 'Branch Todd',\n      },\n      {\n        id: 2,\n        name: 'Carey Dejesus',\n      },\n    ],\n    greeting: 'Hello, Holt! You have 7 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0bd38a23008f8a6714',\n    index: 18,\n    guid: 'ef07b7c0-ee2e-4163-9c25-829cfcd2b142',\n    isActive: true,\n    balance: '$2,267.65',\n    picture: 'http://placehold.it/32x32',\n    age: 27,\n    eyeColor: 'brown',\n    name: {\n      first: 'Farley',\n      last: 'Jensen',\n    },\n    company: 'CODACT',\n    email: 'farley.jensen@codact.com',\n    phone: '+1 (861) 581-3498',\n    address: '535 Richmond Street, Boomer, Rhode Island, 4214',\n    about:\n      'Et dolore do qui velit aliquip sit laboris consequat tempor officia pariatur ex. Consectetur adipisicing non exercitation qui culpa deserunt reprehenderit magna qui laboris irure commodo ex excepteur. Do sit eiusmod amet pariatur velit reprehenderit pariatur tempor irure.',\n    registered: 'Thursday, January 21, 2016 10:53 PM',\n    latitude: '57.38679',\n    longitude: '-118.607665',\n    tags: ['esse', 'ipsum', 'nisi', 'tempor', 'veniam'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Roslyn Bush',\n      },\n      {\n        id: 1,\n        name: 'Garrison Good',\n      },\n      {\n        id: 2,\n        name: 'Langley Mccray',\n      },\n    ],\n    greeting: 'Hello, Farley! You have 7 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0b4d770216e6684e75',\n    index: 19,\n    guid: '7d88afe0-cc56-454c-ae62-bebcd97bf1ce',\n    isActive: false,\n    balance: '$2,132.97',\n    picture: 'http://placehold.it/32x32',\n    age: 20,\n    eyeColor: 'green',\n    name: {\n      first: 'Lindsey',\n      last: 'Mccall',\n    },\n    company: 'CENTICE',\n    email: 'lindsey.mccall@centice.tv',\n    phone: '+1 (833) 454-2919',\n    address: '809 Seaview Court, Sexton, New Mexico, 333',\n    about:\n      'Id minim voluptate ullamco voluptate elit in consectetur irure commodo velit qui eiusmod exercitation. Commodo magna consectetur excepteur eiusmod est minim ipsum occaecat amet. Labore quis anim aliqua Lorem qui. Sint ad cillum cillum excepteur eu nostrud aute.',\n    registered: 'Thursday, February 20, 2014 10:05 AM',\n    latitude: '41.095766',\n    longitude: '-80.580867',\n    tags: ['esse', 'do', 'velit', 'deserunt', 'officia'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Allie Deleon',\n      },\n      {\n        id: 1,\n        name: 'Trudy Miles',\n      },\n      {\n        id: 2,\n        name: 'Lucy Lambert',\n      },\n    ],\n    greeting: 'Hello, Lindsey! You have 5 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0b1cd38dd10da43b88',\n    index: 20,\n    guid: '29e94d5c-de50-4bd1-93bd-ccbb98e2b0b5',\n    isActive: true,\n    balance: '$1,494.27',\n    picture: 'http://placehold.it/32x32',\n    age: 35,\n    eyeColor: 'brown',\n    name: {\n      first: 'Schmidt',\n      last: 'Terry',\n    },\n    company: 'ACCUSAGE',\n    email: 'schmidt.terry@accusage.net',\n    phone: '+1 (917) 421-2816',\n    address: '949 Beard Street, Allensworth, Marshall Islands, 5372',\n    about:\n      'Sint ex aute irure consequat mollit nostrud non. Non laboris ut deserunt nulla commodo id deserunt ut magna duis irure cupidatat. Deserunt eu incididunt exercitation velit ad laborum ad ipsum mollit reprehenderit laboris occaecat ullamco nulla. Consequat culpa id ullamco voluptate esse incididunt sint labore anim minim Lorem quis duis. In officia ex enim enim.',\n    registered: 'Tuesday, January 26, 2016 1:28 PM',\n    latitude: '41.675283',\n    longitude: '-72.234891',\n    tags: ['consequat', 'aliqua', 'nostrud', 'voluptate', 'dolor'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Vonda Byers',\n      },\n      {\n        id: 1,\n        name: 'Ashley Mayer',\n      },\n      {\n        id: 2,\n        name: 'Deborah Fuller',\n      },\n    ],\n    greeting: 'Hello, Schmidt! You have 6 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0b06efb327eb692d35',\n    index: 21,\n    guid: 'ea02ef2d-6359-47c3-b324-c753511ea778',\n    isActive: false,\n    balance: '$1,009.38',\n    picture: 'http://placehold.it/32x32',\n    age: 24,\n    eyeColor: 'brown',\n    name: {\n      first: 'Bradley',\n      last: 'Wyatt',\n    },\n    company: 'PANZENT',\n    email: 'bradley.wyatt@panzent.org',\n    phone: '+1 (875) 520-2168',\n    address: '287 Utica Avenue, Hendersonville, Nebraska, 8366',\n    about:\n      'Do duis proident qui reprehenderit adipisicing nisi aliquip. Ut proident adipisicing quis proident sunt laboris adipisicing dolor. Non est aute Lorem cupidatat minim ea irure laborum minim eiusmod tempor nulla.',\n    registered: 'Tuesday, May 6, 2014 6:25 PM',\n    latitude: '77.325105',\n    longitude: '-85.665071',\n    tags: ['in', 'laborum', 'irure', 'irure', 'exercitation'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Stacey Banks',\n      },\n      {\n        id: 1,\n        name: 'Kelley Cox',\n      },\n      {\n        id: 2,\n        name: 'Gayle Ochoa',\n      },\n    ],\n    greeting: 'Hello, Bradley! You have 6 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0b39a0426fed8383c6',\n    index: 22,\n    guid: '061746b2-33e4-4f40-b19d-d829a2068d87',\n    isActive: true,\n    balance: '$2,235.00',\n    picture: 'http://placehold.it/32x32',\n    age: 32,\n    eyeColor: 'blue',\n    name: {\n      first: 'Stafford',\n      last: 'Sweet',\n    },\n    company: 'VIRVA',\n    email: 'stafford.sweet@virva.me',\n    phone: '+1 (902) 447-3038',\n    address: '688 Bond Street, Robinette, Pennsylvania, 3883',\n    about:\n      'Proident minim quis esse excepteur voluptate reprehenderit ea. Adipisicing esse ex aute in exercitation aute enim ut qui fugiat ex tempor eiusmod. Consectetur minim exercitation dolor aliquip pariatur cupidatat deserunt eu reprehenderit anim duis occaecat culpa. Sint aliquip ad mollit ut dolor excepteur duis nulla ipsum.',\n    registered: 'Sunday, March 30, 2014 7:54 PM',\n    latitude: '83.670234',\n    longitude: '-59.354751',\n    tags: ['proident', 'et', 'sit', 'id', 'reprehenderit'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Christi Willis',\n      },\n      {\n        id: 1,\n        name: 'Deidre Thompson',\n      },\n      {\n        id: 2,\n        name: 'Torres Kennedy',\n      },\n    ],\n    greeting: 'Hello, Stafford! You have 9 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0bbd300e4bf08c3141',\n    index: 23,\n    guid: '9319b49d-63ef-4a31-bf86-70b0ceb377d9',\n    isActive: false,\n    balance: '$2,151.45',\n    picture: 'http://placehold.it/32x32',\n    age: 25,\n    eyeColor: 'blue',\n    name: {\n      first: 'Clarke',\n      last: 'Rhodes',\n    },\n    company: 'LIQUIDOC',\n    email: 'clarke.rhodes@liquidoc.ca',\n    phone: '+1 (861) 411-3808',\n    address: '276 Gain Court, Downsville, Maine, 6619',\n    about:\n      'Ullamco eu enim fugiat duis quis eiusmod elit eiusmod aute. Adipisicing anim mollit non cillum irure velit deserunt magna voluptate incididunt ad dolore laboris non. Excepteur aute cillum dolore voluptate mollit quis ut ea non ullamco sint. Ullamco exercitation quis consequat proident ipsum aliqua dolor laboris voluptate dolore excepteur veniam. Nostrud sunt proident officia quis laborum proident elit laboris do.',\n    registered: 'Sunday, February 15, 2015 5:43 AM',\n    latitude: '-81.487322',\n    longitude: '-112.87443',\n    tags: ['velit', 'nostrud', 'enim', 'voluptate', 'et'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Mindy Horne',\n      },\n      {\n        id: 1,\n        name: 'Pamela Logan',\n      },\n      {\n        id: 2,\n        name: 'Peters Mccullough',\n      },\n    ],\n    greeting: 'Hello, Clarke! You have 7 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0b736919e3a60cfa05',\n    index: 24,\n    guid: '8e31e6e1-3cc6-4a9f-bfa7-9955ec571776',\n    isActive: true,\n    balance: '$3,542.80',\n    picture: 'http://placehold.it/32x32',\n    age: 25,\n    eyeColor: 'brown',\n    name: {\n      first: 'Simon',\n      last: 'Sellers',\n    },\n    company: 'PEARLESSA',\n    email: 'simon.sellers@pearlessa.biz',\n    phone: '+1 (963) 586-2837',\n    address: '691 Wyona Street, Calvary, West Virginia, 216',\n    about:\n      'Mollit consequat aliquip ad ut in reprehenderit. Ea aute laborum id dolor labore est adipisicing deserunt sit aliquip culpa culpa eiusmod excepteur. Mollit veniam magna ut mollit. Exercitation elit veniam laboris nostrud deserunt sint aute.',\n    registered: 'Monday, November 9, 2015 12:10 AM',\n    latitude: '-3.493185',\n    longitude: '-172.87793',\n    tags: ['id', 'labore', 'consequat', 'ea', 'occaecat'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Lorrie Eaton',\n      },\n      {\n        id: 1,\n        name: 'Puckett Harper',\n      },\n      {\n        id: 2,\n        name: 'Roach Powers',\n      },\n    ],\n    greeting: 'Hello, Simon! You have 10 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0b2d85bc8100e78a3c',\n    index: 25,\n    guid: 'c836a6ee-d898-46a8-82f5-30408c199ed9',\n    isActive: false,\n    balance: '$1,425.17',\n    picture: 'http://placehold.it/32x32',\n    age: 36,\n    eyeColor: 'blue',\n    name: {\n      first: 'Tyler',\n      last: 'Rose',\n    },\n    company: 'ZOGAK',\n    email: 'tyler.rose@zogak.co.uk',\n    phone: '+1 (959) 508-3061',\n    address: '575 Furman Avenue, Zeba, South Dakota, 5624',\n    about:\n      'Lorem irure eiusmod quis nostrud anim aute consequat mollit est. Fugiat laboris tempor officia voluptate commodo dolore. Aute elit ipsum esse cupidatat laborum anim nisi in exercitation quis duis. Nisi exercitation labore pariatur quis fugiat. Consequat cillum deserunt exercitation officia mollit amet reprehenderit laborum adipisicing id ex cupidatat. Tempor in aliqua irure ad. Cupidatat qui et aliqua sunt sint laboris incididunt in.',\n    registered: 'Friday, November 27, 2015 6:39 PM',\n    latitude: '21.932938',\n    longitude: '-144.979719',\n    tags: ['mollit', 'excepteur', 'deserunt', 'ipsum', 'proident'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Felecia Cantrell',\n      },\n      {\n        id: 1,\n        name: 'Ortega Wilkinson',\n      },\n      {\n        id: 2,\n        name: 'Linda Jennings',\n      },\n    ],\n    greeting: 'Hello, Tyler! You have 6 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0b0a52937ecb5d0c4d',\n    index: 26,\n    guid: 'a7778e1d-70c3-4f66-ac41-60035653fb5f',\n    isActive: true,\n    balance: '$1,640.96',\n    picture: 'http://placehold.it/32x32',\n    age: 21,\n    eyeColor: 'green',\n    name: {\n      first: 'Greer',\n      last: 'Robbins',\n    },\n    company: 'KYAGURU',\n    email: 'greer.robbins@kyaguru.us',\n    phone: '+1 (925) 443-3311',\n    address: '650 Grant Avenue, Falmouth, Texas, 2573',\n    about:\n      'Ipsum adipisicing occaecat occaecat deserunt non cupidatat non velit deserunt velit amet velit exercitation sint. Commodo eiusmod nisi velit ea officia laborum cupidatat mollit sunt esse tempor est non. Veniam aliquip dolor est sunt et. Et laboris nostrud reprehenderit nisi dolor aliqua occaecat aute commodo aute duis do. Esse exercitation Lorem adipisicing sunt cillum nisi minim pariatur consectetur. Ipsum amet dolore id voluptate ipsum amet ut cupidatat laboris fugiat ex sunt minim.',\n    registered: 'Wednesday, January 27, 2016 1:24 AM',\n    latitude: '43.532255',\n    longitude: '102.388279',\n    tags: ['non', 'occaecat', 'deserunt', 'exercitation', 'velit'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Hogan Powell',\n      },\n      {\n        id: 1,\n        name: 'Valenzuela Chase',\n      },\n      {\n        id: 2,\n        name: 'Lakeisha Ball',\n      },\n    ],\n    greeting: 'Hello, Greer! You have 6 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0b10e85c3f2db6e944',\n    index: 27,\n    guid: '7f5f0c36-a744-4121-81f0-8840fb327754',\n    isActive: true,\n    balance: '$2,977.50',\n    picture: 'http://placehold.it/32x32',\n    age: 23,\n    eyeColor: 'green',\n    name: {\n      first: 'Kitty',\n      last: 'Saunders',\n    },\n    company: 'SINGAVERA',\n    email: 'kitty.saunders@singavera.name',\n    phone: '+1 (896) 427-2344',\n    address: '107 Norfolk Street, Noxen, Missouri, 169',\n    about:\n      'Commodo voluptate consectetur id et occaecat consequat consectetur adipisicing eiusmod commodo. Aute nisi culpa fugiat sunt proident. Aliquip laboris elit veniam quis cillum. Nulla enim proident excepteur magna. Proident do aute tempor exercitation nostrud. Lorem officia id excepteur commodo incididunt et deserunt excepteur qui officia est incididunt mollit ut. Aute dolore cupidatat eu pariatur.',\n    registered: 'Sunday, April 27, 2014 10:20 PM',\n    latitude: '33.543748',\n    longitude: '10.300569',\n    tags: ['id', 'esse', 'voluptate', 'occaecat', 'incididunt'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Webb Hawkins',\n      },\n      {\n        id: 1,\n        name: 'Angie Cline',\n      },\n      {\n        id: 2,\n        name: 'Mathews Juarez',\n      },\n    ],\n    greeting: 'Hello, Kitty! You have 9 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0baf8e44be8a693264',\n    index: 28,\n    guid: '99b20c7a-567f-4810-a793-8470571ce457',\n    isActive: false,\n    balance: '$1,017.55',\n    picture: 'http://placehold.it/32x32',\n    age: 36,\n    eyeColor: 'green',\n    name: {\n      first: 'Faith',\n      last: 'Mendoza',\n    },\n    company: 'XPLOR',\n    email: 'faith.mendoza@xplor.info',\n    phone: '+1 (872) 504-2016',\n    address: '323 Leonard Street, Deltaville, New Hampshire, 5194',\n    about:\n      'Tempor commodo laborum fugiat sit consequat reprehenderit sint anim voluptate. In velit do non aliquip officia est deserunt incididunt. Officia dolor id incididunt cillum minim dolore aliqua proident duis. Irure excepteur irure culpa commodo veniam culpa quis Lorem aute.',\n    registered: 'Saturday, May 30, 2015 7:01 AM',\n    latitude: '12.428182',\n    longitude: '-166.07543',\n    tags: ['non', 'aute', 'aute', 'sint', 'consequat'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Blair Mcknight',\n      },\n      {\n        id: 1,\n        name: 'Mcclain Mcguire',\n      },\n      {\n        id: 2,\n        name: 'Araceli Dorsey',\n      },\n    ],\n    greeting: 'Hello, Faith! You have 8 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0b52e4d918273360dd',\n    index: 29,\n    guid: '8c61aed3-6235-4e09-8ec4-ece4fe285a9c',\n    isActive: false,\n    balance: '$1,182.53',\n    picture: 'http://placehold.it/32x32',\n    age: 36,\n    eyeColor: 'green',\n    name: {\n      first: 'Amie',\n      last: 'Crane',\n    },\n    company: 'RODEOLOGY',\n    email: 'amie.crane@rodeology.io',\n    phone: '+1 (955) 536-3756',\n    address: '578 Box Street, Shelby, Hawaii, 1306',\n    about:\n      'Ex esse et minim dolore sint pariatur incididunt esse. Aute dolore quis ad dolor minim laborum amet. Aliquip deserunt ad aute fugiat proident mollit adipisicing mollit sit duis.',\n    registered: 'Thursday, June 19, 2014 2:34 PM',\n    latitude: '-19.02611',\n    longitude: '127.57473',\n    tags: ['ad', 'nostrud', 'sit', 'duis', 'adipisicing'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Kirk Stewart',\n      },\n      {\n        id: 1,\n        name: 'Rice Horton',\n      },\n      {\n        id: 2,\n        name: 'Kathy Shaffer',\n      },\n    ],\n    greeting: 'Hello, Amie! You have 7 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0c28c0b7bda4325a1d',\n    index: 30,\n    guid: 'ed1385bf-c7d8-41fa-a099-734894807171',\n    isActive: false,\n    balance: '$3,062.06',\n    picture: 'http://placehold.it/32x32',\n    age: 39,\n    eyeColor: 'green',\n    name: {\n      first: 'Best',\n      last: 'Buchanan',\n    },\n    company: 'CONFERIA',\n    email: 'best.buchanan@conferia.com',\n    phone: '+1 (845) 406-3653',\n    address: '742 Miami Court, Wanship, Georgia, 6992',\n    about:\n      'Officia labore velit non mollit adipisicing sit do anim ullamco ut. Incididunt labore aliquip nostrud irure adipisicing id voluptate nulla ex. Ex duis incididunt eu sit et pariatur ullamco incididunt fugiat ex incididunt ea laboris.',\n    registered: 'Tuesday, December 30, 2014 11:23 AM',\n    latitude: '-14.672379',\n    longitude: '123.40741',\n    tags: ['et', 'deserunt', 'cupidatat', 'pariatur', 'eu'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Hudson Mejia',\n      },\n      {\n        id: 1,\n        name: 'Byers Montoya',\n      },\n      {\n        id: 2,\n        name: 'Patty Spencer',\n      },\n    ],\n    greeting: 'Hello, Best! You have 6 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0c9e948778b2db882e',\n    index: 31,\n    guid: '700b5215-132e-4524-9ca8-1224a746f09b',\n    isActive: true,\n    balance: '$3,891.22',\n    picture: 'http://placehold.it/32x32',\n    age: 29,\n    eyeColor: 'green',\n    name: {\n      first: 'Francine',\n      last: 'Green',\n    },\n    company: 'NUTRALAB',\n    email: 'francine.green@nutralab.tv',\n    phone: '+1 (841) 589-3865',\n    address: '165 Union Street, Hebron, North Carolina, 8094',\n    about:\n      'Sunt eu irure aute incididunt mollit. Nisi mollit nulla aliquip cupidatat aute culpa cupidatat mollit tempor. Irure magna officia sint officia. Quis adipisicing ullamco non id aliquip. Non velit commodo quis elit nostrud adipisicing nisi incididunt non sint enim. In qui fugiat ullamco irure Lorem veniam pariatur culpa.',\n    registered: 'Tuesday, June 30, 2015 2:52 AM',\n    latitude: '-83.386439',\n    longitude: '-80.298927',\n    tags: ['mollit', 'aliqua', 'dolor', 'tempor', 'sit'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Page Beasley',\n      },\n      {\n        id: 1,\n        name: 'Keith Atkinson',\n      },\n      {\n        id: 2,\n        name: 'Hahn Evans',\n      },\n    ],\n    greeting: 'Hello, Francine! You have 6 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0c565d848f7f4b0064',\n    index: 32,\n    guid: '88163664-2ab3-4a01-80f9-10b83ad3dece',\n    isActive: false,\n    balance: '$2,387.41',\n    picture: 'http://placehold.it/32x32',\n    age: 35,\n    eyeColor: 'green',\n    name: {\n      first: 'Kelly',\n      last: 'Fowler',\n    },\n    company: 'COMVERGES',\n    email: 'kelly.fowler@comverges.net',\n    phone: '+1 (926) 440-3886',\n    address: '917 Kathleen Court, Outlook, Arkansas, 505',\n    about:\n      'Esse dolore eiusmod culpa ea velit elit culpa veniam proident culpa consequat cupidatat. Fugiat id proident pariatur est fugiat ea. Esse ex dolor minim cillum incididunt voluptate ipsum. Non dolor amet labore excepteur enim eu duis in qui. Sint dolore minim anim mollit laborum proident ea ipsum officia aliquip. Amet culpa adipisicing nisi occaecat commodo irure in ad veniam ipsum officia labore labore.',\n    registered: 'Friday, April 4, 2014 7:14 PM',\n    latitude: '-24.694221',\n    longitude: '43.274287',\n    tags: ['sunt', 'ex', 'est', 'nisi', 'sint'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Cash Hull',\n      },\n      {\n        id: 1,\n        name: 'Lorene Michael',\n      },\n      {\n        id: 2,\n        name: 'Rodgers Underwood',\n      },\n    ],\n    greeting: 'Hello, Kelly! You have 9 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0cab9f4bf7a91707f2',\n    index: 33,\n    guid: '7f857967-0524-44fc-a028-14bc9b78be00',\n    isActive: false,\n    balance: '$3,904.91',\n    picture: 'http://placehold.it/32x32',\n    age: 34,\n    eyeColor: 'brown',\n    name: {\n      first: 'Walters',\n      last: 'Bishop',\n    },\n    company: 'CEPRENE',\n    email: 'walters.bishop@ceprene.org',\n    phone: '+1 (955) 536-2146',\n    address: '441 Livonia Avenue, Norvelt, Indiana, 8326',\n    about:\n      'Enim ad culpa ut aliqua id eiusmod ad aliqua. Cupidatat voluptate enim esse amet anim officia aliquip incididunt ipsum ut. Dolore magna cillum sunt duis duis elit commodo ipsum cillum aliquip proident nisi laboris. Ad Lorem cillum commodo quis tempor consequat laborum velit aliquip et laboris deserunt officia labore. Commodo enim et est id aute nostrud id. Excepteur consequat aliquip laboris ipsum sit aliqua proident esse adipisicing sint consectetur enim aliquip veniam.',\n    registered: 'Sunday, August 2, 2015 11:14 AM',\n    latitude: '-33.507298',\n    longitude: '-177.843777',\n    tags: ['est', 'officia', 'ad', 'fugiat', 'fugiat'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Sloan Larson',\n      },\n      {\n        id: 1,\n        name: 'Lora Howe',\n      },\n      {\n        id: 2,\n        name: 'Cheri Cain',\n      },\n    ],\n    greeting: 'Hello, Walters! You have 8 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0c41960d0332abb69f',\n    index: 34,\n    guid: 'c179f976-46db-4ceb-97dd-d511c2ff2cba',\n    isActive: false,\n    balance: '$3,922.97',\n    picture: 'http://placehold.it/32x32',\n    age: 36,\n    eyeColor: 'brown',\n    name: {\n      first: 'Jamie',\n      last: 'Justice',\n    },\n    company: 'CEMENTION',\n    email: 'jamie.justice@cemention.me',\n    phone: '+1 (886) 453-3323',\n    address: '534 Downing Street, Coldiron, Louisiana, 2936',\n    about:\n      'Ad sint ut qui duis commodo magna sit irure duis labore reprehenderit dolor voluptate. Cillum non dolore mollit amet proident. Tempor sunt aliquip pariatur ullamco incididunt laboris. Adipisicing incididunt magna Lorem voluptate.',\n    registered: 'Wednesday, February 25, 2015 4:11 AM',\n    latitude: '-83.79595',\n    longitude: '71.384564',\n    tags: ['quis', 'nisi', 'dolore', 'voluptate', 'fugiat'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Harvey Ramos',\n      },\n      {\n        id: 1,\n        name: 'Mays Shannon',\n      },\n      {\n        id: 2,\n        name: 'Ball Mcbride',\n      },\n    ],\n    greeting: 'Hello, Jamie! You have 5 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0c9fb032931aaf922e',\n    index: 35,\n    guid: '2d85869d-f1e0-4f2d-8544-78652740bb11',\n    isActive: true,\n    balance: '$1,468.38',\n    picture: 'http://placehold.it/32x32',\n    age: 38,\n    eyeColor: 'green',\n    name: {\n      first: 'Dyer',\n      last: 'Tran',\n    },\n    company: 'COMVEYOR',\n    email: 'dyer.tran@comveyor.ca',\n    phone: '+1 (890) 529-2771',\n    address: '299 Hyman Court, Sims, Colorado, 8328',\n    about:\n      'Adipisicing dolor velit non tempor incididunt magna magna dolore. Officia pariatur mollit anim Lorem Lorem esse. Occaecat eiusmod ipsum ipsum excepteur ut duis commodo esse incididunt. Veniam non officia consequat amet duis nulla qui qui ex sint veniam.',\n    registered: 'Tuesday, October 11, 2016 7:57 AM',\n    latitude: '-58.389129',\n    longitude: '-86.760618',\n    tags: ['incididunt', 'laboris', 'consectetur', 'voluptate', 'aliqua'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Dominguez Woodard',\n      },\n      {\n        id: 1,\n        name: 'Leach Kramer',\n      },\n      {\n        id: 2,\n        name: 'Cruz Wilder',\n      },\n    ],\n    greeting: 'Hello, Dyer! You have 6 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0cc5bcf8eb53c8bfdf',\n    index: 36,\n    guid: '6ced7a65-2989-44d3-8d79-7f02fbaf0f4b',\n    isActive: true,\n    balance: '$1,243.22',\n    picture: 'http://placehold.it/32x32',\n    age: 32,\n    eyeColor: 'green',\n    name: {\n      first: 'Maureen',\n      last: 'Ramsey',\n    },\n    company: 'PROFLEX',\n    email: 'maureen.ramsey@proflex.biz',\n    phone: '+1 (966) 547-2724',\n    address: '828 Louise Terrace, Groton, Michigan, 9563',\n    about:\n      'Enim aliqua qui velit ut dolore Lorem officia. Nisi Lorem aute consequat consectetur reprehenderit tempor. Consectetur velit laboris Lorem do anim ex exercitation. Est deserunt mollit reprehenderit eu amet aute eu reprehenderit mollit voluptate adipisicing excepteur dolor. Cillum commodo laborum in commodo do incididunt excepteur exercitation nostrud. Officia aliquip labore id aliquip sunt officia deserunt. Sunt officia nulla commodo sit velit excepteur dolor ea occaecat commodo eu.',\n    registered: 'Monday, May 18, 2015 11:36 AM',\n    latitude: '35.536999',\n    longitude: '-158.630389',\n    tags: ['qui', 'amet', 'eu', 'eu', 'mollit'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Good Spears',\n      },\n      {\n        id: 1,\n        name: 'Gina Rodriguez',\n      },\n      {\n        id: 2,\n        name: 'Snow Harrington',\n      },\n    ],\n    greeting: 'Hello, Maureen! You have 6 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0c4f6c60bdf26873c9',\n    index: 37,\n    guid: '4883e626-07c8-47af-97d4-8ea82f07aa9d',\n    isActive: false,\n    balance: '$2,250.74',\n    picture: 'http://placehold.it/32x32',\n    age: 21,\n    eyeColor: 'blue',\n    name: {\n      first: 'Cannon',\n      last: 'Walters',\n    },\n    company: 'LUNCHPAD',\n    email: 'cannon.walters@lunchpad.co.uk',\n    phone: '+1 (830) 427-3699',\n    address: '202 Clarkson Avenue, Durham, New Jersey, 3075',\n    about:\n      'Ipsum sint nulla labore do magna fugiat et in irure ex laborum sunt consequat ipsum. Duis et velit nostrud et sit incididunt laborum magna laboris do ex. Reprehenderit culpa nostrud eu qui labore sint ipsum amet reprehenderit dolor incididunt. Nulla proident dolor Lorem culpa officia eu excepteur anim in anim esse id sunt qui. Sit Lorem ea irure id ipsum culpa qui deserunt nulla veniam nisi in. Eiusmod laborum Lorem esse consectetur enim quis minim culpa nostrud.',\n    registered: 'Thursday, October 6, 2016 6:33 PM',\n    latitude: '84.142398',\n    longitude: '15.387476',\n    tags: ['occaecat', 'officia', 'sunt', 'labore', 'consequat'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Coleman Hendrix',\n      },\n      {\n        id: 1,\n        name: 'Bridges Benson',\n      },\n      {\n        id: 2,\n        name: 'Anthony Mathews',\n      },\n    ],\n    greeting: 'Hello, Cannon! You have 7 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0cf09ee09c6eaa88cb',\n    index: 38,\n    guid: 'c54b0b2a-2a0f-4168-b335-bc9a8e0460ca',\n    isActive: true,\n    balance: '$3,203.52',\n    picture: 'http://placehold.it/32x32',\n    age: 33,\n    eyeColor: 'brown',\n    name: {\n      first: 'Nannie',\n      last: 'Beard',\n    },\n    company: 'ANIMALIA',\n    email: 'nannie.beard@animalia.us',\n    phone: '+1 (889) 443-3959',\n    address: '225 Jay Street, Datil, Wyoming, 5453',\n    about:\n      'Esse culpa ipsum duis minim ut ex tempor proident sunt minim consequat commodo ipsum anim. Lorem exercitation cupidatat tempor Lorem quis officia minim qui proident et. Qui esse non ex mollit magna nostrud cillum sit pariatur magna fugiat qui id.',\n    registered: 'Saturday, April 25, 2015 9:25 AM',\n    latitude: '-87.539067',\n    longitude: '63.880414',\n    tags: ['ut', 'et', 'esse', 'cillum', 'nulla'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Francis Barron',\n      },\n      {\n        id: 1,\n        name: 'Pate Aguirre',\n      },\n      {\n        id: 2,\n        name: 'Gay Acosta',\n      },\n    ],\n    greeting: 'Hello, Nannie! You have 10 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0cca904f751c058d2e',\n    index: 39,\n    guid: '7a2ff5cf-270a-4211-a2e8-3509d8884622',\n    isActive: false,\n    balance: '$3,606.94',\n    picture: 'http://placehold.it/32x32',\n    age: 35,\n    eyeColor: 'blue',\n    name: {\n      first: 'Lacy',\n      last: 'Beach',\n    },\n    company: 'DATAGEN',\n    email: 'lacy.beach@datagen.name',\n    phone: '+1 (831) 573-3879',\n    address: '984 Adelphi Street, Herbster, Maryland, 4378',\n    about:\n      'Occaecat do consectetur voluptate veniam id id officia ea deserunt aute anim irure magna quis. Ipsum cupidatat ea commodo dolor ea dolor nisi non. Excepteur irure veniam laborum qui id eu nulla reprehenderit mollit ad aute consectetur elit Lorem.',\n    registered: 'Thursday, March 13, 2014 1:02 PM',\n    latitude: '-9.391908',\n    longitude: '159.065461',\n    tags: ['dolor', 'reprehenderit', 'labore', 'aute', 'voluptate'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Rosa Mercado',\n      },\n      {\n        id: 1,\n        name: 'Fuentes Valenzuela',\n      },\n      {\n        id: 2,\n        name: 'Dixon Singleton',\n      },\n    ],\n    greeting: 'Hello, Lacy! You have 10 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0c1458894607879e9d',\n    index: 40,\n    guid: '45bbc6f7-4183-4eeb-b34a-98ecc8787e7a',\n    isActive: false,\n    balance: '$2,097.65',\n    picture: 'http://placehold.it/32x32',\n    age: 34,\n    eyeColor: 'brown',\n    name: {\n      first: 'Cara',\n      last: 'Lyons',\n    },\n    company: 'VICON',\n    email: 'cara.lyons@vicon.info',\n    phone: '+1 (933) 546-2258',\n    address: '813 Ingraham Street, Riner, Tennessee, 3069',\n    about:\n      'Commodo quis excepteur nulla qui. Fugiat ullamco ex excepteur tempor. Sint duis aute magna in fugiat. Laborum sit magna est duis reprehenderit elit nulla elit. Mollit Lorem ut incididunt nostrud ad voluptate aliquip et et sint ullamco.',\n    registered: 'Sunday, May 11, 2014 7:13 AM',\n    latitude: '11.108367',\n    longitude: '-144.351099',\n    tags: ['excepteur', 'cillum', 'sunt', 'et', 'duis'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Ayala Black',\n      },\n      {\n        id: 1,\n        name: 'Nichole Sutton',\n      },\n      {\n        id: 2,\n        name: 'Mathis Cash',\n      },\n    ],\n    greeting: 'Hello, Cara! You have 9 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0ca9d8edf2d7811aab',\n    index: 41,\n    guid: 'f4aa6a49-0c71-4ad7-9514-614ecb9cc221',\n    isActive: true,\n    balance: '$2,945.42',\n    picture: 'http://placehold.it/32x32',\n    age: 33,\n    eyeColor: 'blue',\n    name: {\n      first: 'Jean',\n      last: 'Copeland',\n    },\n    company: 'KIGGLE',\n    email: 'jean.copeland@kiggle.io',\n    phone: '+1 (841) 470-2173',\n    address: '687 Prospect Place, Welda, New York, 4786',\n    about:\n      'Quis eiusmod enim ad velit mollit occaecat. Ea aute laborum fugiat consequat. Exercitation laboris aliquip ad tempor culpa. Ipsum aute excepteur in fugiat adipisicing incididunt exercitation non occaecat. Id labore ex occaecat esse dolore sit commodo duis quis incididunt enim reprehenderit. Tempor sit qui irure ut pariatur laborum laboris in nostrud sit excepteur.',\n    registered: 'Monday, June 22, 2015 4:57 AM',\n    latitude: '-36.057061',\n    longitude: '-91.348514',\n    tags: ['occaecat', 'sit', 'id', 'anim', 'elit'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Sherman Christian',\n      },\n      {\n        id: 1,\n        name: 'Janna Weiss',\n      },\n      {\n        id: 2,\n        name: 'Janette Nieves',\n      },\n    ],\n    greeting: 'Hello, Jean! You have 8 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0c06cac977a4bff550',\n    index: 42,\n    guid: 'e0aacdb6-61dd-44b2-afa5-d23f8b11ff2d',\n    isActive: true,\n    balance: '$2,740.65',\n    picture: 'http://placehold.it/32x32',\n    age: 29,\n    eyeColor: 'blue',\n    name: {\n      first: 'Alfreda',\n      last: 'Duncan',\n    },\n    company: 'BITREX',\n    email: 'alfreda.duncan@bitrex.com',\n    phone: '+1 (903) 491-3912',\n    address: '541 Sunnyside Court, Ryderwood, Virginia, 9259',\n    about:\n      'Pariatur mollit qui veniam sunt enim Lorem non. Commodo ea deserunt aute dolor id enim anim Lorem occaecat esse nostrud id irure. Aliquip dolore voluptate enim dolore velit adipisicing id est dolore consequat enim. Voluptate ex duis duis elit. Occaecat ex nulla labore ex sit. Proident officia sunt mollit irure non quis commodo sint laboris tempor ut aliquip incididunt. Aliquip ea ad consectetur incididunt.',\n    registered: 'Saturday, March 12, 2016 2:20 PM',\n    latitude: '33.795212',\n    longitude: '-48.161379',\n    tags: ['velit', 'dolore', 'deserunt', 'exercitation', 'nostrud'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Tracie Hendricks',\n      },\n      {\n        id: 1,\n        name: 'Deann Mathis',\n      },\n      {\n        id: 2,\n        name: 'Newman Pace',\n      },\n    ],\n    greeting: 'Hello, Alfreda! You have 10 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0c547ba7b2b5b2ff68',\n    index: 43,\n    guid: '63630a5c-d6b6-4dd9-a096-ae1c81a92bc5',\n    isActive: false,\n    balance: '$2,655.36',\n    picture: 'http://placehold.it/32x32',\n    age: 31,\n    eyeColor: 'green',\n    name: {\n      first: 'Estelle',\n      last: 'Carson',\n    },\n    company: 'GEEKFARM',\n    email: 'estelle.carson@geekfarm.tv',\n    phone: '+1 (829) 551-2574',\n    address: '854 Calder Place, Greer, Nevada, 7137',\n    about:\n      'Laborum velit deserunt ad magna et qui sint sint sunt elit. Exercitation eiusmod ea deserunt quis consectetur sit cillum tempor eiusmod labore ad consequat. Pariatur tempor sunt Lorem sit tempor elit sint ex exercitation. Aliquip tempor irure aute anim tempor sint exercitation exercitation. Consectetur veniam laboris tempor ipsum duis sit tempor laboris eu aute.',\n    registered: 'Wednesday, June 3, 2015 5:48 PM',\n    latitude: '45.625966',\n    longitude: '-113.836952',\n    tags: ['esse', 'nostrud', 'consectetur', 'est', 'qui'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Albert Conrad',\n      },\n      {\n        id: 1,\n        name: 'Etta Lara',\n      },\n      {\n        id: 2,\n        name: 'James Joseph',\n      },\n    ],\n    greeting: 'Hello, Estelle! You have 6 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0ce1fbdc13fd921dfa',\n    index: 44,\n    guid: 'bab756db-f4f0-4c20-8819-805f4de1acf1',\n    isActive: false,\n    balance: '$3,043.42',\n    picture: 'http://placehold.it/32x32',\n    age: 28,\n    eyeColor: 'green',\n    name: {\n      first: 'Flowers',\n      last: 'Guthrie',\n    },\n    company: 'GLOBOIL',\n    email: 'flowers.guthrie@globoil.net',\n    phone: '+1 (848) 547-2136',\n    address: '757 Rodney Street, Lupton, Washington, 290',\n    about:\n      'Nulla sunt ut laboris id consequat id quis excepteur et eu sint esse est. Nostrud voluptate voluptate minim enim exercitation sunt labore ea cillum veniam mollit pariatur enim. Officia ipsum voluptate eu veniam dolor est do. Ullamco minim excepteur aute eu cillum reprehenderit non laborum. Do magna eiusmod veniam eu cillum magna deserunt labore. Nisi culpa nisi proident amet eu et cillum mollit reprehenderit veniam et. Ad elit sint aliquip cupidatat exercitation do ex velit esse nisi sunt nostrud.',\n    registered: 'Wednesday, May 7, 2014 11:25 PM',\n    latitude: '-18.985921',\n    longitude: '-170.937155',\n    tags: ['sunt', 'nostrud', 'ex', 'qui', 'proident'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Holcomb Joyce',\n      },\n      {\n        id: 1,\n        name: 'Dolores Guy',\n      },\n      {\n        id: 2,\n        name: 'Alisa Garrett',\n      },\n    ],\n    greeting: 'Hello, Flowers! You have 8 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0ce0cd552ea52c7f2c',\n    index: 45,\n    guid: 'dea849a7-62f2-4a50-8215-6070082f02e7',\n    isActive: false,\n    balance: '$2,088.13',\n    picture: 'http://placehold.it/32x32',\n    age: 35,\n    eyeColor: 'green',\n    name: {\n      first: 'Duran',\n      last: 'Houston',\n    },\n    company: 'ENQUILITY',\n    email: 'duran.houston@enquility.org',\n    phone: '+1 (968) 460-3781',\n    address: '968 Prospect Avenue, Eastmont, Minnesota, 5346',\n    about:\n      'Irure nisi occaecat quis ipsum exercitation esse minim nulla magna sunt nisi culpa exercitation. Nulla ea ipsum exercitation est culpa consequat nostrud duis ex do incididunt est. Dolore et sit labore ex non do ipsum. Do velit voluptate sint nisi enim sit sunt tempor voluptate aliquip ullamco reprehenderit do. Id sunt cillum ea nisi aute qui do tempor nisi aute nostrud. Ipsum cupidatat laboris elit dolore pariatur tempor mollit exercitation tempor et voluptate laboris eu. Ex Lorem sint sit tempor sunt elit.',\n    registered: 'Saturday, June 11, 2016 4:20 PM',\n    latitude: '18.300079',\n    longitude: '-83.967577',\n    tags: ['labore', 'sunt', 'mollit', 'voluptate', 'duis'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Lori Roach',\n      },\n      {\n        id: 1,\n        name: 'Benita Farley',\n      },\n      {\n        id: 2,\n        name: 'Sheri Hurst',\n      },\n    ],\n    greeting: 'Hello, Duran! You have 9 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0c491e46a12015041d',\n    index: 46,\n    guid: '2c10fc4c-47d7-41b0-ab6d-b27348fd3a2c',\n    isActive: false,\n    balance: '$1,874.46',\n    picture: 'http://placehold.it/32x32',\n    age: 24,\n    eyeColor: 'green',\n    name: {\n      first: 'Cortez',\n      last: 'Levy',\n    },\n    company: 'OPTICON',\n    email: 'cortez.levy@opticon.me',\n    phone: '+1 (831) 454-3969',\n    address: '707 Lefferts Avenue, Stouchsburg, District Of Columbia, 5615',\n    about:\n      'Dolor labore exercitation magna eu exercitation veniam culpa ad dolore ut consequat Lorem et officia. Voluptate aliqua laborum amet voluptate consequat id. Laboris tempor dolor cillum ut ullamco voluptate incididunt amet ipsum laboris exercitation tempor. Do quis duis qui magna eu irure sunt.',\n    registered: 'Wednesday, November 4, 2015 7:46 PM',\n    latitude: '5.931545',\n    longitude: '58.787345',\n    tags: ['enim', 'consequat', 'irure', 'sit', 'voluptate'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Marquita Figueroa',\n      },\n      {\n        id: 1,\n        name: 'Justice Stephens',\n      },\n      {\n        id: 2,\n        name: 'Traci Blevins',\n      },\n    ],\n    greeting: 'Hello, Cortez! You have 6 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0c163f106a3d9867a0',\n    index: 47,\n    guid: '2299f9f1-f9c9-4d53-b9f5-829132d1b1f6',\n    isActive: false,\n    balance: '$3,704.08',\n    picture: 'http://placehold.it/32x32',\n    age: 31,\n    eyeColor: 'brown',\n    name: {\n      first: 'Sampson',\n      last: 'Sloan',\n    },\n    company: 'ZAGGLES',\n    email: 'sampson.sloan@zaggles.ca',\n    phone: '+1 (812) 536-2825',\n    address: '921 Beadel Street, Manila, Guam, 2501',\n    about:\n      'Nisi irure laboris dolore Lorem nulla irure consectetur mollit commodo aliqua pariatur et. Officia magna veniam culpa excepteur ea sint reprehenderit eiusmod. Ex dolor non nisi enim eu et ad occaecat magna id ullamco in occaecat. Commodo labore Lorem aliqua quis amet irure labore. Deserunt proident cillum et do consequat mollit reprehenderit eiusmod voluptate proident sunt ex. Aute aliqua ullamco duis laborum labore et exercitation.',\n    registered: 'Sunday, October 26, 2014 2:43 AM',\n    latitude: '83.228508',\n    longitude: '0.459083',\n    tags: ['tempor', 'exercitation', 'proident', 'exercitation', 'et'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Hannah Schneider',\n      },\n      {\n        id: 1,\n        name: 'White Williamson',\n      },\n      {\n        id: 2,\n        name: 'Annie Moreno',\n      },\n    ],\n    greeting: 'Hello, Sampson! You have 5 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0ccd1cc56b6ac487a6',\n    index: 48,\n    guid: '857676b3-f998-4efa-9ec8-6762b2468e43',\n    isActive: false,\n    balance: '$3,662.77',\n    picture: 'http://placehold.it/32x32',\n    age: 35,\n    eyeColor: 'blue',\n    name: {\n      first: 'Nona',\n      last: 'Nguyen',\n    },\n    company: 'QUARMONY',\n    email: 'nona.nguyen@quarmony.biz',\n    phone: '+1 (921) 562-2588',\n    address: '660 Sutton Street, Eggertsville, American Samoa, 7519',\n    about:\n      'Et esse sit labore pariatur eu eiusmod eu et non elit adipisicing mollit esse id. Quis dolore magna ipsum do velit cupidatat in officia do dolore voluptate anim laboris aliquip. Lorem amet sunt irure laborum ad sunt commodo cillum minim consectetur. Eiusmod id exercitation occaecat esse enim magna consectetur reprehenderit nostrud quis ea dolor sit incididunt. Ipsum eu quis consequat ad eiusmod amet velit veniam aliquip reprehenderit in ea. Duis et aliquip voluptate dolor proident incididunt eiusmod. Magna eu aliquip aliquip id.',\n    registered: 'Friday, January 22, 2016 1:24 AM',\n    latitude: '45.499893',\n    longitude: '71.913207',\n    tags: ['proident', 'irure', 'eu', 'laborum', 'tempor'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Ross Landry',\n      },\n      {\n        id: 1,\n        name: 'Chan Joyner',\n      },\n      {\n        id: 2,\n        name: 'Richardson Snow',\n      },\n    ],\n    greeting: 'Hello, Nona! You have 5 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0c4546f881c8f7555f',\n    index: 49,\n    guid: '28bddafd-23f4-49a2-bae8-643e1e7c9fb3',\n    isActive: false,\n    balance: '$2,081.58',\n    picture: 'http://placehold.it/32x32',\n    age: 38,\n    eyeColor: 'brown',\n    name: {\n      first: 'Wendi',\n      last: 'Cleveland',\n    },\n    company: 'EVENTEX',\n    email: 'wendi.cleveland@eventex.co.uk',\n    phone: '+1 (935) 410-2326',\n    address: '737 Ebony Court, Elfrida, Delaware, 5439',\n    about:\n      'Enim deserunt commodo qui laboris mollit ullamco. Id qui laboris magna do consequat nostrud sint occaecat amet officia. Laboris excepteur Lorem aliqua in est exercitation ut laborum et. Officia nisi eiusmod veniam mollit laborum magna esse labore elit pariatur pariatur. Esse ipsum pariatur pariatur eiusmod est ex tempor non.',\n    registered: 'Sunday, March 9, 2014 5:48 PM',\n    latitude: '88.457536',\n    longitude: '-65.024239',\n    tags: ['aliquip', 'duis', 'tempor', 'ipsum', 'velit'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Gabrielle Cote',\n      },\n      {\n        id: 1,\n        name: 'Brandi Downs',\n      },\n      {\n        id: 2,\n        name: 'Rhonda Ellison',\n      },\n    ],\n    greeting: 'Hello, Wendi! You have 9 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0cec2076eb6d116dfc',\n    index: 50,\n    guid: '39489d24-b8b8-47bc-b7d0-c3481f3ad5bd',\n    isActive: false,\n    balance: '$1,075.68',\n    picture: 'http://placehold.it/32x32',\n    age: 40,\n    eyeColor: 'blue',\n    name: {\n      first: 'Dale',\n      last: 'Douglas',\n    },\n    company: 'DELPHIDE',\n    email: 'dale.douglas@delphide.us',\n    phone: '+1 (977) 457-3984',\n    address: '754 Hicks Street, Vaughn, Palau, 7264',\n    about:\n      'Ad incididunt proident proident ipsum nisi ipsum cillum consectetur cupidatat aliquip labore duis aliquip est. Esse nulla sit magna ipsum. Proident aliquip sint fugiat dolor sunt elit velit qui tempor officia amet nostrud.',\n    registered: 'Saturday, July 30, 2016 8:55 AM',\n    latitude: '-8.058598',\n    longitude: '-33.314846',\n    tags: ['irure', 'nisi', 'consequat', 'cillum', 'dolor'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Harriett Gamble',\n      },\n      {\n        id: 1,\n        name: 'Hester Pittman',\n      },\n      {\n        id: 2,\n        name: 'Lesley Washington',\n      },\n    ],\n    greeting: 'Hello, Dale! You have 10 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0cd4ecef796970cd3f',\n    index: 51,\n    guid: '52dc9e03-d6bc-4776-975e-22735a673bb9',\n    isActive: false,\n    balance: '$2,094.76',\n    picture: 'http://placehold.it/32x32',\n    age: 23,\n    eyeColor: 'green',\n    name: {\n      first: 'Eula',\n      last: 'Huber',\n    },\n    company: 'COMTENT',\n    email: 'eula.huber@comtent.name',\n    phone: '+1 (914) 552-2231',\n    address: '389 Grove Street, Eagletown, Massachusetts, 8524',\n    about:\n      'Id sunt consectetur nostrud occaecat ea eu reprehenderit excepteur amet nostrud et ea. In ipsum occaecat aliquip est ex aute labore nostrud eu incididunt velit est. Aliquip velit occaecat laborum consectetur dolor.',\n    registered: 'Saturday, June 20, 2015 8:33 AM',\n    latitude: '-27.235963',\n    longitude: '17.691481',\n    tags: ['eu', 'ex', 'exercitation', 'reprehenderit', 'irure'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Melva Coffey',\n      },\n      {\n        id: 1,\n        name: 'Farmer Weaver',\n      },\n      {\n        id: 2,\n        name: 'Watkins Serrano',\n      },\n    ],\n    greeting: 'Hello, Eula! You have 7 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0ccb817c1dc5c145c8',\n    index: 52,\n    guid: '7ec24512-cb72-4fa5-b411-44c7b7ac0cde',\n    isActive: true,\n    balance: '$3,388.55',\n    picture: 'http://placehold.it/32x32',\n    age: 33,\n    eyeColor: 'green',\n    name: {\n      first: 'Lamb',\n      last: 'Contreras',\n    },\n    company: 'COMTRAK',\n    email: 'lamb.contreras@comtrak.info',\n    phone: '+1 (866) 451-3939',\n    address: '403 Himrod Street, Haring, South Carolina, 7598',\n    about:\n      'Labore labore ipsum non eu quis eiusmod sint fugiat qui tempor sit. Ex exercitation culpa exercitation sunt ipsum nisi et adipisicing proident adipisicing do. Amet cillum amet sit ea dolor. Ex mollit ut eu ad quis consequat cillum ullamco aliquip. Minim enim ut et incididunt occaecat ea. Et dolor nisi sunt eiusmod duis. Reprehenderit aliqua eiusmod amet dolor aliqua.',\n    registered: 'Tuesday, December 23, 2014 11:42 AM',\n    latitude: '-56.076139',\n    longitude: '126.054413',\n    tags: ['nostrud', 'et', 'commodo', 'nisi', 'deserunt'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Kasey Andrews',\n      },\n      {\n        id: 1,\n        name: 'Pearl Bridges',\n      },\n      {\n        id: 2,\n        name: 'Tameka Chandler',\n      },\n    ],\n    greeting: 'Hello, Lamb! You have 10 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0c39b5a56a264d4bcf',\n    index: 53,\n    guid: 'e07bd38e-e79b-4ceb-bcbc-ea60b4b0e740',\n    isActive: false,\n    balance: '$1,011.72',\n    picture: 'http://placehold.it/32x32',\n    age: 28,\n    eyeColor: 'blue',\n    name: {\n      first: 'Angelique',\n      last: 'Barry',\n    },\n    company: 'INSOURCE',\n    email: 'angelique.barry@insource.io',\n    phone: '+1 (983) 464-3474',\n    address: '691 Heyward Street, Bodega, Florida, 4333',\n    about:\n      'Deserunt voluptate eiusmod sit et quis aliquip eiusmod ex consequat velit. Cillum elit excepteur ex esse officia cupidatat ut. Nostrud pariatur ex et ullamco dolor dolore fugiat excepteur irure exercitation. Id Lorem proident ea quis.',\n    registered: 'Tuesday, April 26, 2016 12:53 PM',\n    latitude: '69.146806',\n    longitude: '-136.72291',\n    tags: ['qui', 'anim', 'anim', 'quis', 'pariatur'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Doyle Tanner',\n      },\n      {\n        id: 1,\n        name: 'Gloria Stevens',\n      },\n      {\n        id: 2,\n        name: 'Sally Chapman',\n      },\n    ],\n    greeting: 'Hello, Angelique! You have 7 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0c653a65b1bde5a9af',\n    index: 54,\n    guid: '79ad167a-209e-4ce3-8e84-cc46e9d79702',\n    isActive: true,\n    balance: '$2,652.68',\n    picture: 'http://placehold.it/32x32',\n    age: 33,\n    eyeColor: 'blue',\n    name: {\n      first: 'Marissa',\n      last: 'Head',\n    },\n    company: 'BOLAX',\n    email: 'marissa.head@bolax.com',\n    phone: '+1 (919) 411-2094',\n    address: '224 Tampa Court, Harleigh, Virgin Islands, 2507',\n    about:\n      'Nulla elit do ullamco nulla. Fugiat incididunt culpa deserunt deserunt dolore nisi commodo. Labore exercitation pariatur aliqua id id duis.',\n    registered: 'Saturday, April 9, 2016 11:53 PM',\n    latitude: '12.624239',\n    longitude: '-108.119849',\n    tags: ['labore', 'proident', 'labore', 'eiusmod', 'aute'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Chambers Lester',\n      },\n      {\n        id: 1,\n        name: 'Mckenzie Mcdonald',\n      },\n      {\n        id: 2,\n        name: 'Benson Clark',\n      },\n    ],\n    greeting: 'Hello, Marissa! You have 6 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0cbbf466925baae126',\n    index: 55,\n    guid: '44384d90-908a-44f7-ac6a-f3e4e9ce3541',\n    isActive: false,\n    balance: '$2,707.40',\n    picture: 'http://placehold.it/32x32',\n    age: 33,\n    eyeColor: 'blue',\n    name: {\n      first: 'Avila',\n      last: 'Pena',\n    },\n    company: 'TERASCAPE',\n    email: 'avila.pena@terascape.tv',\n    phone: '+1 (973) 462-2068',\n    address: '393 Story Court, Veguita, Utah, 6716',\n    about:\n      'Reprehenderit nostrud laborum duis excepteur adipisicing voluptate dolor. Quis aliqua et laborum officia dolor nostrud laborum est. Excepteur aliquip ipsum id eiusmod esse laboris nostrud in excepteur est. Non eiusmod esse non ut.',\n    registered: 'Tuesday, August 11, 2015 11:07 PM',\n    latitude: '-40.827485',\n    longitude: '159.48116',\n    tags: ['et', 'culpa', 'cupidatat', 'ut', 'sunt'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Boone Goodman',\n      },\n      {\n        id: 1,\n        name: 'Jenny Weeks',\n      },\n      {\n        id: 2,\n        name: 'Tracy Franklin',\n      },\n    ],\n    greeting: 'Hello, Avila! You have 10 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0c0224b3b46507d00d',\n    index: 56,\n    guid: '7631262c-7af8-4caf-9dd6-9882b20e9ccf',\n    isActive: true,\n    balance: '$3,127.77',\n    picture: 'http://placehold.it/32x32',\n    age: 24,\n    eyeColor: 'brown',\n    name: {\n      first: 'Graciela',\n      last: 'Vang',\n    },\n    company: 'EARWAX',\n    email: 'graciela.vang@earwax.net',\n    phone: '+1 (810) 450-2884',\n    address: '620 Tech Place, Glendale, Connecticut, 369',\n    about:\n      'Cillum laboris elit laboris irure ex aliquip amet aute commodo ea ea sunt nostrud irure. Ex incididunt anim nostrud excepteur in dolore aliqua laboris incididunt consequat officia dolore. Aliqua aliqua minim elit pariatur nulla occaecat aliquip consectetur mollit sit elit proident.',\n    registered: 'Thursday, September 1, 2016 6:03 PM',\n    latitude: '-22.465372',\n    longitude: '174.750198',\n    tags: ['irure', 'amet', 'ad', 'cupidatat', 'consequat'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Teresa Dickson',\n      },\n      {\n        id: 1,\n        name: 'Reyna Gonzales',\n      },\n      {\n        id: 2,\n        name: 'Carol Hunt',\n      },\n    ],\n    greeting: 'Hello, Graciela! You have 9 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0c44df164b323518f0',\n    index: 57,\n    guid: '21cf0aae-e2fd-4987-a12a-df9845dfe256',\n    isActive: true,\n    balance: '$2,129.83',\n    picture: 'http://placehold.it/32x32',\n    age: 38,\n    eyeColor: 'green',\n    name: {\n      first: 'Kaye',\n      last: 'Whitehead',\n    },\n    company: 'TALKOLA',\n    email: 'kaye.whitehead@talkola.org',\n    phone: '+1 (998) 495-2808',\n    address: '933 Sands Street, Frystown, Wisconsin, 9993',\n    about:\n      'Laborum id id esse fugiat eu consectetur non nostrud eu sint. Enim dolor aliquip ut elit et. Officia labore labore duis veniam reprehenderit. Ut id nulla minim adipisicing laboris deserunt pariatur. Laborum aute magna laboris quis.',\n    registered: 'Friday, May 2, 2014 8:39 PM',\n    latitude: '5.18003',\n    longitude: '-138.228885',\n    tags: ['elit', 'labore', 'id', 'nisi', 'pariatur'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Leona Soto',\n      },\n      {\n        id: 1,\n        name: 'Cunningham Blankenship',\n      },\n      {\n        id: 2,\n        name: 'Campbell Turner',\n      },\n    ],\n    greeting: 'Hello, Kaye! You have 10 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0ca827218ce430db2f',\n    index: 58,\n    guid: 'f1cc09e1-4502-4b54-8aa6-272b93335375',\n    isActive: true,\n    balance: '$1,635.66',\n    picture: 'http://placehold.it/32x32',\n    age: 38,\n    eyeColor: 'green',\n    name: {\n      first: 'Vickie',\n      last: 'Walsh',\n    },\n    company: 'ZORK',\n    email: 'vickie.walsh@zork.me',\n    phone: '+1 (966) 458-2157',\n    address: '770 Flatlands Avenue, Marion, Oklahoma, 5819',\n    about:\n      'Velit laboris sint velit elit esse est commodo est officia. Sit do ut eiusmod duis ex ullamco eiusmod proident esse est cupidatat aliqua pariatur veniam. Culpa incididunt Lorem ea ut. Sint nostrud quis et tempor magna voluptate. Aliqua ea irure ad sint. Irure non nostrud non in ad officia officia laboris nostrud eiusmod. Labore commodo sit consequat velit ipsum culpa tempor.',\n    registered: 'Friday, June 24, 2016 6:10 AM',\n    latitude: '-21.293579',\n    longitude: '-171.238054',\n    tags: ['quis', 'dolore', 'sunt', 'sint', 'ut'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Kristie Davenport',\n      },\n      {\n        id: 1,\n        name: 'Sandy Foreman',\n      },\n      {\n        id: 2,\n        name: 'Eve Patel',\n      },\n    ],\n    greeting: 'Hello, Vickie! You have 7 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0ca320d90456f0650c',\n    index: 59,\n    guid: '7bfed2cf-dbf1-461b-949a-42c300172e0f',\n    isActive: false,\n    balance: '$3,809.61',\n    picture: 'http://placehold.it/32x32',\n    age: 22,\n    eyeColor: 'blue',\n    name: {\n      first: 'Travis',\n      last: 'Carrillo',\n    },\n    company: 'INTERODEO',\n    email: 'travis.carrillo@interodeo.ca',\n    phone: '+1 (820) 527-3349',\n    address: '878 Dekalb Avenue, Jeff, Alaska, 4205',\n    about:\n      'Sit aliqua aliqua eiusmod aliquip ullamco amet nulla fugiat anim dolor est cillum eiusmod. Proident dolor consectetur officia voluptate do tempor aliquip qui minim. Dolore culpa magna nulla irure. Est ad laborum deserunt amet commodo esse officia incididunt. Sit aute laborum aliqua id excepteur sunt ipsum cupidatat commodo exercitation proident.',\n    registered: 'Saturday, November 7, 2015 11:49 PM',\n    latitude: '59.311122',\n    longitude: '38.059303',\n    tags: ['ex', 'elit', 'voluptate', 'consectetur', 'Lorem'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Velez Daniel',\n      },\n      {\n        id: 1,\n        name: 'Mae Burris',\n      },\n      {\n        id: 2,\n        name: 'Henson Francis',\n      },\n    ],\n    greeting: 'Hello, Travis! You have 10 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0c4d57f9870f521abc',\n    index: 60,\n    guid: '6de5e184-4e24-41c1-8071-7fbd2fc184f0',\n    isActive: false,\n    balance: '$3,692.96',\n    picture: 'http://placehold.it/32x32',\n    age: 33,\n    eyeColor: 'blue',\n    name: {\n      first: 'Elvia',\n      last: 'Haynes',\n    },\n    company: 'OPTICOM',\n    email: 'elvia.haynes@opticom.biz',\n    phone: '+1 (918) 418-2771',\n    address: '646 Quincy Street, Fedora, Federated States Of Micronesia, 1232',\n    about:\n      'Occaecat officia amet ipsum ut mollit. Eu qui tempor voluptate sint pariatur id Lorem eiusmod veniam magna sint qui esse proident. Reprehenderit ut est sit ad tempor sit magna veniam consectetur. Id quis aliquip occaecat sint excepteur in nisi voluptate laborum ad anim. Id Lorem in incididunt ut culpa culpa duis aliqua mollit adipisicing.',\n    registered: 'Monday, November 16, 2015 2:49 AM',\n    latitude: '-82.030922',\n    longitude: '-160.684246',\n    tags: ['esse', 'minim', 'nulla', 'eiusmod', 'est'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Mcdowell Maxwell',\n      },\n      {\n        id: 1,\n        name: 'Dawson Gay',\n      },\n      {\n        id: 2,\n        name: 'Herminia Leach',\n      },\n    ],\n    greeting: 'Hello, Elvia! You have 8 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0c62a1b2744f05b1a7',\n    index: 61,\n    guid: 'fe9f08a4-cfe5-4cdb-b2e4-9ecfa54d873b',\n    isActive: false,\n    balance: '$3,807.03',\n    picture: 'http://placehold.it/32x32',\n    age: 30,\n    eyeColor: 'blue',\n    name: {\n      first: 'Blackwell',\n      last: 'Benton',\n    },\n    company: 'TUBESYS',\n    email: 'blackwell.benton@tubesys.co.uk',\n    phone: '+1 (897) 452-2584',\n    address: '343 Dupont Street, Blodgett, Iowa, 509',\n    about:\n      'Ut anim consectetur enim officia. Mollit anim et proident pariatur exercitation consectetur exercitation incididunt. Ullamco pariatur sit enim velit minim aliquip.',\n    registered: 'Thursday, September 25, 2014 1:31 AM',\n    latitude: '50.446336',\n    longitude: '-17.513084',\n    tags: ['ipsum', 'quis', 'et', 'labore', 'est'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Henrietta Santana',\n      },\n      {\n        id: 1,\n        name: 'Carla Cobb',\n      },\n      {\n        id: 2,\n        name: 'Nita Durham',\n      },\n    ],\n    greeting: 'Hello, Blackwell! You have 7 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0ce6f3ef88019d28bc',\n    index: 62,\n    guid: '62666a91-4a93-404c-bbce-170ab0668ee7',\n    isActive: false,\n    balance: '$3,792.15',\n    picture: 'http://placehold.it/32x32',\n    age: 40,\n    eyeColor: 'brown',\n    name: {\n      first: 'Stanton',\n      last: 'Potter',\n    },\n    company: 'UTARIAN',\n    email: 'stanton.potter@utarian.us',\n    phone: '+1 (965) 569-3822',\n    address: '498 Holmes Lane, Belgreen, Puerto Rico, 1728',\n    about:\n      'Ullamco esse sunt aliquip incididunt velit mollit aute. Et est eiusmod commodo aliqua cillum sint nostrud in dolor labore fugiat deserunt aliquip nostrud. Velit non incididunt consectetur tempor veniam minim. Magna enim minim dolore labore do magna ea pariatur tempor anim.',\n    registered: 'Thursday, November 20, 2014 7:07 PM',\n    latitude: '13.26351',\n    longitude: '-169.826766',\n    tags: ['dolore', 'commodo', 'ex', 'anim', 'commodo'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Jillian Burnett',\n      },\n      {\n        id: 1,\n        name: 'Evangelina Blackburn',\n      },\n      {\n        id: 2,\n        name: 'Castro Nolan',\n      },\n    ],\n    greeting: 'Hello, Stanton! You have 6 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0c66bd8e3191775b81',\n    index: 63,\n    guid: 'babde8c1-773d-4f96-aeb9-bcf68d233204',\n    isActive: true,\n    balance: '$2,096.56',\n    picture: 'http://placehold.it/32x32',\n    age: 23,\n    eyeColor: 'green',\n    name: {\n      first: 'Kerry',\n      last: 'Barnes',\n    },\n    company: 'PYRAMIS',\n    email: 'kerry.barnes@pyramis.name',\n    phone: '+1 (959) 455-2215',\n    address: '676 Roder Avenue, Eden, Kansas, 7602',\n    about:\n      'Et non et mollit velit proident exercitation velit elit cillum voluptate. Lorem reprehenderit nulla ex sunt adipisicing laborum excepteur in occaecat culpa fugiat enim fugiat proident. Duis minim deserunt aliqua ea. Ea minim ea eiusmod qui elit. Cupidatat quis commodo irure nisi.',\n    registered: 'Wednesday, October 21, 2015 7:02 PM',\n    latitude: '77.232279',\n    longitude: '153.606067',\n    tags: ['in', 'cupidatat', 'Lorem', 'consequat', 'laborum'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Veronica Beck',\n      },\n      {\n        id: 1,\n        name: 'Hull Velez',\n      },\n      {\n        id: 2,\n        name: 'Meghan Wiley',\n      },\n    ],\n    greeting: 'Hello, Kerry! You have 10 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0c8e8776857572353b',\n    index: 64,\n    guid: 'd34861fb-ed0e-4fd1-a315-c41e04ec60f3',\n    isActive: true,\n    balance: '$1,081.03',\n    picture: 'http://placehold.it/32x32',\n    age: 33,\n    eyeColor: 'green',\n    name: {\n      first: 'Cameron',\n      last: 'Barber',\n    },\n    company: 'FRANSCENE',\n    email: 'cameron.barber@franscene.info',\n    phone: '+1 (849) 484-3425',\n    address: '446 Macon Street, Heil, North Dakota, 4499',\n    about:\n      'Consectetur elit eu labore adipisicing. Enim dolore sunt sint duis exercitation do quis enim veniam enim incididunt sint nostrud. Est veniam exercitation deserunt irure consectetur non esse ut eu aliqua ad. Occaecat commodo dolore magna labore ad id ipsum. Aliquip ad consectetur incididunt laborum exercitation cillum cillum minim commodo laboris proident in. Sit aliqua consequat sunt dolor veniam.',\n    registered: 'Wednesday, March 25, 2015 12:58 AM',\n    latitude: '-0.119378',\n    longitude: '-52.799542',\n    tags: ['laboris', 'ut', 'nostrud', 'nisi', 'tempor'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Young Bates',\n      },\n      {\n        id: 1,\n        name: 'Rhea Chen',\n      },\n      {\n        id: 2,\n        name: 'Alissa Morin',\n      },\n    ],\n    greeting: 'Hello, Cameron! You have 5 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0c3a6582461fb89886',\n    index: 65,\n    guid: '4974e20f-b8df-4cbd-92ce-fe1cfc9c3657',\n    isActive: false,\n    balance: '$1,022.79',\n    picture: 'http://placehold.it/32x32',\n    age: 40,\n    eyeColor: 'blue',\n    name: {\n      first: 'Ashlee',\n      last: 'Randolph',\n    },\n    company: 'SLUMBERIA',\n    email: 'ashlee.randolph@slumberia.io',\n    phone: '+1 (850) 590-3733',\n    address: '539 Wortman Avenue, Rose, Northern Mariana Islands, 4842',\n    about:\n      'Lorem non commodo ea anim proident reprehenderit id consequat velit laborum deserunt. Veniam ad excepteur anim laboris laboris quis ad in dolor. Minim irure ad mollit reprehenderit dolor voluptate duis dolor incididunt cillum irure.',\n    registered: 'Saturday, March 28, 2015 2:02 AM',\n    latitude: '45.475368',\n    longitude: '-140.783475',\n    tags: ['nulla', 'ea', 'eiusmod', 'adipisicing', 'ea'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Martin Abbott',\n      },\n      {\n        id: 1,\n        name: 'Franco Munoz',\n      },\n      {\n        id: 2,\n        name: 'Briggs Briggs',\n      },\n    ],\n    greeting: 'Hello, Ashlee! You have 8 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0c9b9a0708efa913ae',\n    index: 66,\n    guid: 'd7e3871b-05bc-4db9-8ebb-aa136e9349a1',\n    isActive: false,\n    balance: '$1,282.07',\n    picture: 'http://placehold.it/32x32',\n    age: 24,\n    eyeColor: 'brown',\n    name: {\n      first: 'Karin',\n      last: 'Mcintyre',\n    },\n    company: 'QIAO',\n    email: 'karin.mcintyre@qiao.com',\n    phone: '+1 (827) 522-3528',\n    address: '476 Kings Place, Rowe, Montana, 1003',\n    about:\n      'Anim Lorem irure commodo sunt culpa proident velit quis consectetur. Et qui irure et ullamco ut ipsum. In sit dolor cupidatat dolore veniam sunt aliquip elit aliquip incididunt commodo eu in. Quis labore adipisicing officia eu mollit veniam officia ipsum excepteur dolor.',\n    registered: 'Sunday, February 9, 2014 3:39 PM',\n    latitude: '-50.934733',\n    longitude: '80.069751',\n    tags: ['non', 'aliqua', 'deserunt', 'exercitation', 'sint'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Bradshaw Vega',\n      },\n      {\n        id: 1,\n        name: 'Imelda Barnett',\n      },\n      {\n        id: 2,\n        name: 'Margaret Cross',\n      },\n    ],\n    greeting: 'Hello, Karin! You have 5 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0c5e44b5027bec1ac0',\n    index: 67,\n    guid: '4be33215-4b35-4079-9831-c2632a0bfe28',\n    isActive: false,\n    balance: '$2,900.86',\n    picture: 'http://placehold.it/32x32',\n    age: 38,\n    eyeColor: 'blue',\n    name: {\n      first: 'Rowe',\n      last: 'Hogan',\n    },\n    company: 'ISOSURE',\n    email: 'rowe.hogan@isosure.tv',\n    phone: '+1 (925) 401-2733',\n    address: '978 Ditmas Avenue, Herald, Ohio, 4322',\n    about:\n      'Nostrud commodo deserunt Lorem magna esse nulla eu cillum. Aliquip aute est laborum enim ut irure enim exercitation anim ipsum minim cillum. Qui commodo labore veniam et anim proident anim. Aliquip ut veniam consectetur amet mollit reprehenderit qui.',\n    registered: 'Wednesday, April 13, 2016 6:04 AM',\n    latitude: '38.442477',\n    longitude: '-127.884805',\n    tags: ['et', 'occaecat', 'elit', 'tempor', 'sint'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Elnora Guzman',\n      },\n      {\n        id: 1,\n        name: 'Talley Townsend',\n      },\n      {\n        id: 2,\n        name: 'Chaney Harvey',\n      },\n    ],\n    greeting: 'Hello, Rowe! You have 8 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0c9075ebf36eef4cb0',\n    index: 68,\n    guid: '6cc1ae86-7aa6-4c1f-8338-1cd7b3630ade',\n    isActive: true,\n    balance: '$3,381.58',\n    picture: 'http://placehold.it/32x32',\n    age: 27,\n    eyeColor: 'blue',\n    name: {\n      first: 'Ronda',\n      last: 'Parker',\n    },\n    company: 'BOILCAT',\n    email: 'ronda.parker@boilcat.net',\n    phone: '+1 (888) 404-2571',\n    address: '836 Java Street, Detroit, Oregon, 9319',\n    about:\n      'Fugiat quis est id anim. Enim nostrud tempor esse in officia enim deserunt. Nisi anim adipisicing nostrud occaecat laboris occaecat. Qui laborum ut exercitation culpa aute veniam exercitation tempor qui adipisicing minim. Dolor ex voluptate pariatur aliquip dolor cillum laborum est. Ex adipisicing mollit ea occaecat ut eu.',\n    registered: 'Friday, August 12, 2016 6:40 AM',\n    latitude: '-67.552112',\n    longitude: '-148.920666',\n    tags: ['enim', 'occaecat', 'ex', 'est', 'magna'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Ora Cannon',\n      },\n      {\n        id: 1,\n        name: 'Mcintosh Carter',\n      },\n      {\n        id: 2,\n        name: 'Glenn Foley',\n      },\n    ],\n    greeting: 'Hello, Ronda! You have 6 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0cd164eec1663b2d49',\n    index: 69,\n    guid: '03ba15d9-ec37-4820-9833-5191c760dabe',\n    isActive: false,\n    balance: '$3,202.56',\n    picture: 'http://placehold.it/32x32',\n    age: 33,\n    eyeColor: 'brown',\n    name: {\n      first: 'Gallegos',\n      last: 'Preston',\n    },\n    company: 'VETRON',\n    email: 'gallegos.preston@vetron.org',\n    phone: '+1 (923) 570-3649',\n    address: '327 Irvington Place, Snelling, Arizona, 5946',\n    about:\n      'Anim aliquip deserunt commodo id incididunt mollit cillum et fugiat ullamco magna sint fugiat. Minim qui ea sint commodo eiusmod velit cupidatat excepteur eu. Enim cillum est sint incididunt. Culpa deserunt ex sunt labore voluptate. Ad laboris in pariatur dolore laboris dolor duis quis esse do sit velit pariatur dolore.',\n    registered: 'Saturday, July 23, 2016 4:24 AM',\n    latitude: '23.3067',\n    longitude: '26.605291',\n    tags: ['adipisicing', 'aute', 'consequat', 'fugiat', 'elit'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Raquel Dillard',\n      },\n      {\n        id: 1,\n        name: 'Conway Cruz',\n      },\n      {\n        id: 2,\n        name: 'Hope Woods',\n      },\n    ],\n    greeting: 'Hello, Gallegos! You have 7 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0c0282495ae724dd00',\n    index: 70,\n    guid: 'e4e4b345-ccb8-46bd-ad7e-25905e3f887d',\n    isActive: false,\n    balance: '$2,592.79',\n    picture: 'http://placehold.it/32x32',\n    age: 28,\n    eyeColor: 'green',\n    name: {\n      first: 'Scott',\n      last: 'Anderson',\n    },\n    company: 'SCENTRIC',\n    email: 'scott.anderson@scentric.me',\n    phone: '+1 (869) 517-3912',\n    address: '408 Caton Place, Nadine, Vermont, 538',\n    about:\n      'Do elit sunt eiusmod anim anim eiusmod ex. Ipsum officia velit ipsum non minim enim. Enim culpa nostrud occaecat voluptate sit minim consectetur sit ut eiusmod. Magna voluptate fugiat occaecat id et eiusmod voluptate. Dolore consequat fugiat quis ipsum non deserunt ex culpa ut aliqua officia.',\n    registered: 'Wednesday, February 25, 2015 11:02 AM',\n    latitude: '88.07987',\n    longitude: '157.464013',\n    tags: ['dolore', 'sint', 'amet', 'voluptate', 'nulla'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Browning Brock',\n      },\n      {\n        id: 1,\n        name: 'Goldie Greer',\n      },\n      {\n        id: 2,\n        name: 'Bright Clayton',\n      },\n    ],\n    greeting: 'Hello, Scott! You have 9 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0c997d595f28bed4b2',\n    index: 71,\n    guid: '2e81e82f-097d-4ed9-816b-678f7b5f28f4',\n    isActive: true,\n    balance: '$1,316.05',\n    picture: 'http://placehold.it/32x32',\n    age: 23,\n    eyeColor: 'green',\n    name: {\n      first: 'Clarice',\n      last: 'York',\n    },\n    company: 'SOPRANO',\n    email: 'clarice.york@soprano.ca',\n    phone: '+1 (822) 485-3017',\n    address: '428 Midwood Street, Witmer, California, 4690',\n    about:\n      'Exercitation adipisicing aute commodo commodo exercitation. Aliquip aliquip minim sit anim cillum. Cupidatat veniam adipisicing mollit duis exercitation eu consequat non nulla proident. Occaecat sunt sunt consectetur occaecat veniam consectetur do minim. Adipisicing reprehenderit eu laboris sunt minim fugiat enim est proident duis consequat laboris ea ut. Officia dolor incididunt exercitation dolore et ut veniam. Minim est incididunt ullamco quis proident velit esse et est Lorem.',\n    registered: 'Friday, October 24, 2014 8:31 AM',\n    latitude: '50.680453',\n    longitude: '-22.267809',\n    tags: ['esse', 'dolore', 'deserunt', 'labore', 'officia'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Madge Battle',\n      },\n      {\n        id: 1,\n        name: 'Francis Dunn',\n      },\n      {\n        id: 2,\n        name: 'Rosario Irwin',\n      },\n    ],\n    greeting: 'Hello, Clarice! You have 7 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0ce47eee37facdfcc8',\n    index: 72,\n    guid: 'f7880df6-e31a-42ff-971a-82d7ca76bc14',\n    isActive: true,\n    balance: '$2,569.05',\n    picture: 'http://placehold.it/32x32',\n    age: 22,\n    eyeColor: 'green',\n    name: {\n      first: 'Madeleine',\n      last: 'Mann',\n    },\n    company: 'PHORMULA',\n    email: 'madeleine.mann@phormula.biz',\n    phone: '+1 (839) 443-3345',\n    address: '948 McKibben Street, Wyoming, Idaho, 2596',\n    about:\n      'Amet eiusmod quis sit veniam irure eiusmod eiusmod et. Amet ex consectetur velit aliqua fugiat excepteur commodo in non do anim proident enim. Do nulla minim id cillum cillum non non proident laborum ullamco in nostrud excepteur.',\n    registered: 'Monday, September 7, 2015 9:57 AM',\n    latitude: '1.417271',\n    longitude: '14.344005',\n    tags: ['minim', 'aliqua', 'aliqua', 'velit', 'nisi'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Carole Bond',\n      },\n      {\n        id: 1,\n        name: 'Diann Vaughan',\n      },\n      {\n        id: 2,\n        name: 'Morgan Rojas',\n      },\n    ],\n    greeting: 'Hello, Madeleine! You have 10 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0c49e7bdd7ed590e84',\n    index: 73,\n    guid: '7bf69708-15f1-4d35-b71e-17c43001af61',\n    isActive: false,\n    balance: '$3,449.63',\n    picture: 'http://placehold.it/32x32',\n    age: 29,\n    eyeColor: 'green',\n    name: {\n      first: 'Riley',\n      last: 'Moses',\n    },\n    company: 'COMDOM',\n    email: 'riley.moses@comdom.co.uk',\n    phone: '+1 (855) 426-2672',\n    address: '556 Richardson Street, Grazierville, Mississippi, 7295',\n    about:\n      'Ullamco do reprehenderit duis mollit ad duis aute qui reprehenderit ipsum qui in eiusmod. Officia culpa cillum cupidatat irure ipsum id occaecat. Enim do in dolor veniam laborum dolor est reprehenderit occaecat et minim laboris. Duis sint voluptate deserunt cillum fugiat velit irure. Lorem ullamco laboris reprehenderit dolor aute tempor excepteur. In elit enim aliquip ut in. Nulla et tempor ut mollit reprehenderit dolore ullamco veniam nisi minim.',\n    registered: 'Wednesday, March 18, 2015 5:28 AM',\n    latitude: '-17.956865',\n    longitude: '60.984652',\n    tags: ['quis', 'elit', 'excepteur', 'incididunt', 'sint'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Jana Knowles',\n      },\n      {\n        id: 1,\n        name: 'Dotson Calderon',\n      },\n      {\n        id: 2,\n        name: 'Stacy Winters',\n      },\n    ],\n    greeting: 'Hello, Riley! You have 10 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0c4e5dea19708856e5',\n    index: 74,\n    guid: 'cf4a7bf9-7a0e-4810-b5f5-23dd2bea6a9a',\n    isActive: true,\n    balance: '$1,365.62',\n    picture: 'http://placehold.it/32x32',\n    age: 24,\n    eyeColor: 'brown',\n    name: {\n      first: 'Emilia',\n      last: 'Sanford',\n    },\n    company: 'AQUAZURE',\n    email: 'emilia.sanford@aquazure.us',\n    phone: '+1 (812) 451-2498',\n    address: '649 Guernsey Street, Wedgewood, Alabama, 7660',\n    about:\n      'Amet cillum esse exercitation enim tempor ut est amet ad anim. Cillum veniam exercitation sit dolor velit irure tempor anim amet quis aliquip. Aliqua dolor cupidatat culpa consequat dolor in qui est tempor aliqua dolor. Mollit tempor dolor ad nisi Lorem anim adipisicing deserunt tempor. Tempor elit eiusmod dolor reprehenderit sint consequat aliqua incididunt dolore aliqua proident exercitation officia. Et velit tempor minim voluptate. Veniam dolor labore laboris ad quis minim tempor est ad cillum nulla.',\n    registered: 'Thursday, May 5, 2016 10:20 PM',\n    latitude: '66.972869',\n    longitude: '26.31688',\n    tags: ['eiusmod', 'sit', 'occaecat', 'nostrud', 'nisi'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Desiree Norman',\n      },\n      {\n        id: 1,\n        name: 'Carlson Meadows',\n      },\n      {\n        id: 2,\n        name: 'Miranda Gutierrez',\n      },\n    ],\n    greeting: 'Hello, Emilia! You have 10 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0cbb2ae9fb9dc2c667',\n    index: 75,\n    guid: 'f814f3d7-fd66-4061-81de-1097a56ddc95',\n    isActive: false,\n    balance: '$2,546.18',\n    picture: 'http://placehold.it/32x32',\n    age: 33,\n    eyeColor: 'green',\n    name: {\n      first: 'Cristina',\n      last: 'Carver',\n    },\n    company: 'DOGNOSIS',\n    email: 'cristina.carver@dognosis.name',\n    phone: '+1 (967) 552-2825',\n    address: '293 Metrotech Courtr, Cawood, Illinois, 7748',\n    about:\n      'Incididunt nulla ut velit in tempor pariatur sit ipsum dolor do laborum elit nostrud ullamco. Quis voluptate minim qui eu enim consectetur. In duis excepteur aute nostrud exercitation proident.',\n    registered: 'Saturday, November 14, 2015 9:50 AM',\n    latitude: '66.369831',\n    longitude: '-113.48546',\n    tags: ['do', 'laborum', 'non', 'velit', 'sunt'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Dianna Armstrong',\n      },\n      {\n        id: 1,\n        name: 'Gena Stafford',\n      },\n      {\n        id: 2,\n        name: 'Clare Allison',\n      },\n    ],\n    greeting: 'Hello, Cristina! You have 10 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0c6311ae4dab4a3f34',\n    index: 76,\n    guid: '13d0bb42-7310-486c-9717-a91fe51873e9',\n    isActive: false,\n    balance: '$2,712.28',\n    picture: 'http://placehold.it/32x32',\n    age: 31,\n    eyeColor: 'green',\n    name: {\n      first: 'Rosa',\n      last: 'Cook',\n    },\n    company: 'MATRIXITY',\n    email: 'rosa.cook@matrixity.info',\n    phone: '+1 (937) 505-2696',\n    address: '119 Madison Place, Dola, Rhode Island, 7030',\n    about:\n      'Veniam laborum mollit dolor nostrud anim ex duis eiusmod ex. Nostrud excepteur laborum officia eu eiusmod aute ea aute ea irure adipisicing. Ex consectetur laboris ex nisi ex esse ea sit cupidatat cupidatat anim labore nostrud Lorem. Esse quis consectetur eiusmod officia sunt cupidatat esse ullamco esse eiusmod tempor enim laborum nulla. Esse occaecat Lorem amet laboris laborum reprehenderit eu eiusmod excepteur qui officia. Nisi irure reprehenderit adipisicing dolor ipsum pariatur sint pariatur.',\n    registered: 'Tuesday, September 29, 2015 7:15 PM',\n    latitude: '47.166257',\n    longitude: '48.962919',\n    tags: ['sint', 'reprehenderit', 'aute', 'velit', 'excepteur'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Nellie Mooney',\n      },\n      {\n        id: 1,\n        name: 'Bridget Rocha',\n      },\n      {\n        id: 2,\n        name: 'Rosie Neal',\n      },\n    ],\n    greeting: 'Hello, Rosa! You have 9 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0c3f6b67c114a34891',\n    index: 77,\n    guid: 'a72c60f4-ea12-47ca-a738-dfc886a23fb3',\n    isActive: false,\n    balance: '$3,863.37',\n    picture: 'http://placehold.it/32x32',\n    age: 37,\n    eyeColor: 'brown',\n    name: {\n      first: 'Hallie',\n      last: 'Cherry',\n    },\n    company: 'MAXIMIND',\n    email: 'hallie.cherry@maximind.io',\n    phone: '+1 (883) 445-2642',\n    address: '816 Bridgewater Street, Worcester, New Mexico, 3552',\n    about:\n      'Ut id cillum mollit excepteur sunt adipisicing sint do nostrud velit nisi Lorem. Incididunt amet tempor aliqua ad. Consequat veniam non exercitation veniam occaecat eu reprehenderit excepteur. In dolor ex sunt deserunt cupidatat in consequat est commodo excepteur ea. Eu ex qui ea exercitation proident est cillum aliqua pariatur amet in anim deserunt.',\n    registered: 'Wednesday, December 16, 2015 1:09 AM',\n    latitude: '-22.963385',\n    longitude: '-18.88522',\n    tags: ['ad', 'tempor', 'adipisicing', 'ea', 'consequat'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Karla Waters',\n      },\n      {\n        id: 1,\n        name: 'Salinas Duran',\n      },\n      {\n        id: 2,\n        name: 'Juliette Bell',\n      },\n    ],\n    greeting: 'Hello, Hallie! You have 6 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0caf58b7c09ccbbfe0',\n    index: 78,\n    guid: 'a2136e10-0d46-4e2a-9d45-1ad4a7fb6150',\n    isActive: false,\n    balance: '$1,715.46',\n    picture: 'http://placehold.it/32x32',\n    age: 37,\n    eyeColor: 'green',\n    name: {\n      first: 'Hill',\n      last: 'Adams',\n    },\n    company: 'UNI',\n    email: 'hill.adams@uni.com',\n    phone: '+1 (887) 533-2728',\n    address: '341 Union Avenue, Tyro, Marshall Islands, 6939',\n    about:\n      'Lorem excepteur cupidatat dolor voluptate eu et reprehenderit id nisi eiusmod tempor. Occaecat et reprehenderit tempor est reprehenderit magna elit eu do pariatur laborum dolore fugiat do. Occaecat dolor mollit ea sunt ex ea sint eu culpa irure enim nostrud. Ipsum eu anim elit quis officia anim do laborum velit sunt tempor in. Quis id veniam laborum sint in dolor do.',\n    registered: 'Thursday, August 20, 2015 6:41 PM',\n    latitude: '49.668798',\n    longitude: '48.122152',\n    tags: ['deserunt', 'labore', 'ea', 'reprehenderit', 'dolore'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Dixie Reyes',\n      },\n      {\n        id: 1,\n        name: 'Randall Mason',\n      },\n      {\n        id: 2,\n        name: 'Morrison Church',\n      },\n    ],\n    greeting: 'Hello, Hill! You have 7 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0c120ddc3a2597b83c',\n    index: 79,\n    guid: '5d601f0c-923c-41f2-86ec-2794c25ba07d',\n    isActive: true,\n    balance: '$1,368.60',\n    picture: 'http://placehold.it/32x32',\n    age: 26,\n    eyeColor: 'blue',\n    name: {\n      first: 'Megan',\n      last: 'Grant',\n    },\n    company: 'PURIA',\n    email: 'megan.grant@puria.tv',\n    phone: '+1 (867) 456-2370',\n    address: '688 Jewel Street, Stagecoach, Nebraska, 5430',\n    about:\n      'Reprehenderit et aliquip sunt nisi aliquip minim ut. Nostrud veniam velit laboris sit consectetur occaecat incididunt nulla officia adipisicing labore commodo qui anim. Sunt sunt mollit Lorem et do magna magna occaecat ea esse sit deserunt deserunt non. Est aliqua cupidatat veniam laboris amet officia ex consequat ullamco fugiat tempor laborum. Irure minim veniam deserunt est mollit. Do elit ipsum ea laborum magna amet id qui ea non veniam. Laboris Lorem ullamco dolore ad dolor anim tempor sint nisi reprehenderit proident tempor.',\n    registered: 'Wednesday, September 10, 2014 7:56 PM',\n    latitude: '62.666152',\n    longitude: '-103.092817',\n    tags: ['officia', 'sit', 'veniam', 'consequat', 'aliqua'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Rush Klein',\n      },\n      {\n        id: 1,\n        name: 'Bruce Bryan',\n      },\n      {\n        id: 2,\n        name: 'Vicki Griffith',\n      },\n    ],\n    greeting: 'Hello, Megan! You have 6 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0c923ee8af5787fc95',\n    index: 80,\n    guid: '27f1d835-7fe3-4ace-8f1c-e9d834d58b51',\n    isActive: true,\n    balance: '$1,120.98',\n    picture: 'http://placehold.it/32x32',\n    age: 22,\n    eyeColor: 'brown',\n    name: {\n      first: 'Kathie',\n      last: 'Adkins',\n    },\n    company: 'ZANILLA',\n    email: 'kathie.adkins@zanilla.net',\n    phone: '+1 (827) 443-2787',\n    address: '225 Stillwell Avenue, Clayville, Pennsylvania, 2403',\n    about:\n      'Cillum proident cupidatat consectetur aliqua amet ad. Dolor magna anim id aliquip deserunt occaecat do sunt ad est laborum consequat non esse. Nisi magna voluptate sunt magna exercitation officia cupidatat exercitation minim eu Lorem et. Occaecat ex velit fugiat reprehenderit veniam nulla. Consequat laboris eu reprehenderit dolore ea ut anim culpa ipsum ullamco. Amet pariatur dolor dolor non cillum enim elit id. Aute magna dolor ea ea fugiat.',\n    registered: 'Wednesday, January 8, 2014 9:01 AM',\n    latitude: '-57.35919',\n    longitude: '16.081565',\n    tags: ['mollit', 'ut', 'velit', 'eu', 'ea'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Martha Webb',\n      },\n      {\n        id: 1,\n        name: 'Quinn Hampton',\n      },\n      {\n        id: 2,\n        name: 'Phelps Reilly',\n      },\n    ],\n    greeting: 'Hello, Kathie! You have 9 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0c0f013070624983d3',\n    index: 81,\n    guid: 'd20f5d74-7e69-4a38-8afc-f9eafd9eb9b8',\n    isActive: true,\n    balance: '$2,486.01',\n    picture: 'http://placehold.it/32x32',\n    age: 28,\n    eyeColor: 'green',\n    name: {\n      first: 'Reid',\n      last: 'Moon',\n    },\n    company: 'UPLINX',\n    email: 'reid.moon@uplinx.org',\n    phone: '+1 (974) 588-2358',\n    address: '437 Wythe Place, Bergoo, Maine, 2688',\n    about:\n      'Proident sit nostrud adipisicing fugiat laborum adipisicing commodo est. Eu voluptate dolor ad consequat cillum tempor excepteur. Veniam sit ullamco velit aliquip nulla nisi magna sunt commodo officia tempor mollit. Velit occaecat occaecat culpa in duis dolor enim aute incididunt ipsum adipisicing excepteur adipisicing in. Mollit duis incididunt sit deserunt tempor ullamco sit. Nisi et aliquip aliquip nisi ad cillum deserunt amet Lorem id minim in. Nisi ullamco labore consequat deserunt voluptate sunt nulla commodo quis dolore et do sunt dolor.',\n    registered: 'Wednesday, November 5, 2014 8:41 PM',\n    latitude: '-57.701702',\n    longitude: '98.460257',\n    tags: ['culpa', 'dolore', 'sunt', 'duis', 'sint'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Christina Brennan',\n      },\n      {\n        id: 1,\n        name: 'Joan Key',\n      },\n      {\n        id: 2,\n        name: 'Terrie Colon',\n      },\n    ],\n    greeting: 'Hello, Reid! You have 6 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0cd7d10e075f923c32',\n    index: 82,\n    guid: 'eff18055-8039-4733-8e71-0e8161a9a37f',\n    isActive: true,\n    balance: '$1,703.03',\n    picture: 'http://placehold.it/32x32',\n    age: 27,\n    eyeColor: 'green',\n    name: {\n      first: 'Myra',\n      last: 'Cooper',\n    },\n    company: 'LOTRON',\n    email: 'myra.cooper@lotron.me',\n    phone: '+1 (833) 490-3199',\n    address: '454 Argyle Road, Tilleda, West Virginia, 4341',\n    about:\n      'Dolor sint commodo est excepteur sunt labore consequat cillum et minim. Id proident id officia aute. Aliquip exercitation nulla esse ad id do adipisicing occaecat ipsum veniam veniam dolor. Voluptate tempor qui dolor ullamco consequat consequat cupidatat nisi elit et non qui non adipisicing. Excepteur consequat minim laborum minim nostrud mollit anim exercitation minim duis ullamco. Minim minim fugiat qui voluptate dolor dolore voluptate non consectetur nulla commodo exercitation do non. Ad commodo sit excepteur adipisicing do ex sunt minim laborum dolore non do elit in.',\n    registered: 'Friday, September 30, 2016 1:21 AM',\n    latitude: '12.698327',\n    longitude: '98.957272',\n    tags: ['et', 'esse', 'sint', 'incididunt', 'esse'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Angelia Roth',\n      },\n      {\n        id: 1,\n        name: 'Vasquez Cole',\n      },\n      {\n        id: 2,\n        name: 'Tanner Hayes',\n      },\n    ],\n    greeting: 'Hello, Myra! You have 10 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0c79029337f04c4f74',\n    index: 83,\n    guid: '10fb3103-bb73-42c0-8fac-3fe42121176e',\n    isActive: false,\n    balance: '$3,028.72',\n    picture: 'http://placehold.it/32x32',\n    age: 33,\n    eyeColor: 'green',\n    name: {\n      first: 'Mccarty',\n      last: 'Workman',\n    },\n    company: 'TURNABOUT',\n    email: 'mccarty.workman@turnabout.ca',\n    phone: '+1 (839) 409-3408',\n    address: '138 Rutledge Street, Tivoli, South Dakota, 9041',\n    about:\n      'Culpa laborum ea magna nulla ipsum velit excepteur incididunt occaecat sit. Ullamco laborum voluptate dolor est proident ex culpa. Ex est sunt aliquip culpa in adipisicing mollit irure magna exercitation.',\n    registered: 'Thursday, December 18, 2014 10:46 AM',\n    latitude: '3.78797',\n    longitude: '-146.349265',\n    tags: ['ut', 'pariatur', 'ad', 'voluptate', 'qui'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Skinner Webster',\n      },\n      {\n        id: 1,\n        name: 'Atkins James',\n      },\n      {\n        id: 2,\n        name: 'Enid Meyer',\n      },\n    ],\n    greeting: 'Hello, Mccarty! You have 9 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0c642e9641a7bfbcee',\n    index: 84,\n    guid: 'a774c4b8-b1d2-42c3-837a-52bce2aa7a94',\n    isActive: false,\n    balance: '$2,539.93',\n    picture: 'http://placehold.it/32x32',\n    age: 34,\n    eyeColor: 'blue',\n    name: {\n      first: 'Davenport',\n      last: 'Small',\n    },\n    company: 'ISOTRACK',\n    email: 'davenport.small@isotrack.biz',\n    phone: '+1 (909) 521-2228',\n    address: '646 Fleet Walk, Dale, Texas, 3140',\n    about:\n      'Non magna officia veniam velit nostrud elit. Nulla ad cupidatat quis aliquip ut. Adipisicing labore sint nostrud eu veniam sunt dolor consequat pariatur commodo consectetur magna sunt. Tempor dolor consectetur deserunt in quis id proident occaecat sunt. Est minim anim proident occaecat culpa ex minim mollit ea. Enim deserunt tempor ea eu nulla sunt veniam ad. Laborum cillum dolor proident voluptate id sint ut voluptate cillum anim incididunt laboris.',\n    registered: 'Friday, May 1, 2015 11:13 AM',\n    latitude: '-49.904277',\n    longitude: '-35.151297',\n    tags: ['anim', 'labore', 'Lorem', 'anim', 'cillum'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Emerson Gilmore',\n      },\n      {\n        id: 1,\n        name: 'Castillo Wright',\n      },\n      {\n        id: 2,\n        name: 'Marva Stone',\n      },\n    ],\n    greeting: 'Hello, Davenport! You have 10 unread messages.',\n    favoriteFruit: 'strawberry',\n  },\n  {\n    _id: '580ddf0cf681ca1388d97783',\n    index: 85,\n    guid: 'b5860a9d-45ff-47ef-bd87-e43adc9dc8d6',\n    isActive: true,\n    balance: '$1,578.95',\n    picture: 'http://placehold.it/32x32',\n    age: 29,\n    eyeColor: 'brown',\n    name: {\n      first: 'Reyes',\n      last: 'Dotson',\n    },\n    company: 'GRACKER',\n    email: 'reyes.dotson@gracker.co.uk',\n    phone: '+1 (909) 410-2034',\n    address: '739 Junius Street, Nutrioso, Missouri, 6051',\n    about:\n      'Esse magna Lorem enim nostrud quis sit minim et do elit. Culpa proident ipsum dolore aute do exercitation tempor eu. Reprehenderit ullamco sunt ad anim aliqua proident deserunt commodo dolor ad quis cillum cupidatat. Ea sint id aute adipisicing do anim minim exercitation labore id ullamco duis do sit. Laboris do in sunt esse anim cillum anim nulla eu do consequat aliquip culpa amet. Ipsum velit reprehenderit minim velit incididunt enim duis ut aliquip.',\n    registered: 'Wednesday, February 5, 2014 11:01 AM',\n    latitude: '-11.383582',\n    longitude: '102.513196',\n    tags: ['occaecat', 'consequat', 'ipsum', 'elit', 'voluptate'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Baker Bennett',\n      },\n      {\n        id: 1,\n        name: 'Franklin Nelson',\n      },\n      {\n        id: 2,\n        name: 'Wilda Hill',\n      },\n    ],\n    greeting: 'Hello, Reyes! You have 7 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0cc99c7d2e5622dbb5',\n    index: 86,\n    guid: '0a1d6c96-621e-4fe5-9f0f-ccba26458cf1',\n    isActive: false,\n    balance: '$1,760.99',\n    picture: 'http://placehold.it/32x32',\n    age: 25,\n    eyeColor: 'green',\n    name: {\n      first: 'Ratliff',\n      last: 'Kinney',\n    },\n    company: 'YURTURE',\n    email: 'ratliff.kinney@yurture.us',\n    phone: '+1 (962) 417-2906',\n    address: '832 Duryea Court, Moscow, New Hampshire, 7275',\n    about:\n      'Sint commodo ullamco proident ullamco esse elit Lorem anim veniam sunt veniam nulla elit. Tempor nulla culpa ut occaecat tempor elit aliqua ipsum. Anim nisi reprehenderit pariatur officia aute elit fugiat amet est incididunt. Irure excepteur id cillum exercitation esse officia dolor in amet id nostrud. Incididunt consectetur culpa tempor officia veniam aute eu incididunt duis tempor incididunt ex nisi irure. Tempor proident aute aliquip in aliqua Lorem cillum consequat exercitation et sint nulla minim. Cillum magna ut aliqua eu qui tempor culpa laborum amet magna ullamco.',\n    registered: 'Tuesday, April 29, 2014 6:13 AM',\n    latitude: '-13.301568',\n    longitude: '-112.255058',\n    tags: ['labore', 'sit', 'excepteur', 'laboris', 'nulla'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Ingrid Rutledge',\n      },\n      {\n        id: 1,\n        name: 'Simpson Barlow',\n      },\n      {\n        id: 2,\n        name: 'Lottie Hickman',\n      },\n    ],\n    greeting: 'Hello, Ratliff! You have 6 unread messages.',\n    favoriteFruit: 'banana',\n  },\n  {\n    _id: '580ddf0c461fe67eb5044e47',\n    index: 87,\n    guid: '4f264353-60c0-4324-af56-34d2f28e718a',\n    isActive: true,\n    balance: '$1,034.62',\n    picture: 'http://placehold.it/32x32',\n    age: 21,\n    eyeColor: 'blue',\n    name: {\n      first: 'Bettye',\n      last: 'Jenkins',\n    },\n    company: 'LUNCHPOD',\n    email: 'bettye.jenkins@lunchpod.name',\n    phone: '+1 (873) 530-2152',\n    address: '577 Oliver Street, Gallina, Hawaii, 2623',\n    about:\n      'Consectetur eiusmod aute ad duis nisi minim dolore ad do deserunt occaecat voluptate cupidatat. Sunt exercitation cillum deserunt veniam cillum. Lorem anim dolor occaecat elit amet. Magna reprehenderit laboris enim occaecat eiusmod Lorem duis sint nulla quis exercitation occaecat ipsum. Laborum Lorem magna ullamco enim ad id. Pariatur exercitation nisi cupidatat incididunt ipsum magna cillum laborum. Laboris exercitation excepteur adipisicing Lorem duis id ipsum fugiat nostrud labore culpa consequat ad.',\n    registered: 'Sunday, May 1, 2016 11:30 AM',\n    latitude: '-2.873736',\n    longitude: '108.897468',\n    tags: ['aliqua', 'sunt', 'ex', 'duis', 'commodo'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Leonard Kelley',\n      },\n      {\n        id: 1,\n        name: 'Penny Watson',\n      },\n      {\n        id: 2,\n        name: 'Roxanne French',\n      },\n    ],\n    greeting: 'Hello, Bettye! You have 5 unread messages.',\n    favoriteFruit: 'apple',\n  },\n  {\n    _id: '580ddf0cf9dae7fe5522c648',\n    index: 88,\n    guid: 'b47a7f45-3805-44d7-b455-67038c5466e8',\n    isActive: true,\n    balance: '$2,489.68',\n    picture: 'http://placehold.it/32x32',\n    age: 35,\n    eyeColor: 'blue',\n    name: {\n      first: 'Barr',\n      last: 'Pearson',\n    },\n    company: 'QNEKT',\n    email: 'barr.pearson@qnekt.info',\n    phone: '+1 (914) 541-3874',\n    address: '186 Robert Street, Ona, Georgia, 8717',\n    about:\n      'Anim ullamco mollit adipisicing sit tempor aute eiusmod adipisicing cupidatat laborum tempor reprehenderit pariatur. Reprehenderit ullamco aliqua laboris Lorem. Exercitation magna pariatur mollit ea ullamco et nostrud commodo laboris dolore. Esse do cupidatat pariatur esse in labore do et cillum reprehenderit incididunt. Ad mollit adipisicing proident culpa occaecat tempor et elit esse occaecat fugiat consectetur occaecat occaecat. Et adipisicing esse labore ullamco proident laboris consequat enim aliqua. Eu laboris et in voluptate.',\n    registered: 'Friday, September 5, 2014 6:22 PM',\n    latitude: '55.604021',\n    longitude: '-152.171415',\n    tags: ['occaecat', 'culpa', 'do', 'id', 'qui'],\n    range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n    friends: [\n      {\n        id: 0,\n        name: 'Kimberley Mckinney',\n      },\n      {\n        id: 1,\n        name: 'Mosley Gardner',\n      },\n      {\n        id: 2,\n        name: 'Gay Garner',\n      },\n    ],\n    greeting: 'Hello, Barr! You have 6 unread messages.',\n    favoriteFruit: 'apple',\n  },\n];\n\nexport const circularData = { bigArray };\ncircularData.c = circularData;\n"
  },
  {
    "path": "extension/test/perf/send.spec.js",
    "content": "import { bigArray, bigString, circularData } from './data.js';\nimport { listenMessage } from '../utils/inject.js';\n\nfunction test(title, data, maxTime = 100) {\n  it('should send ' + title, async () => {\n    const start = new Date();\n    await listenMessage(() => {\n      window.__REDUX_DEVTOOLS_EXTENSION__.send(\n        { type: 'TEST_ACTION', data },\n        data,\n      );\n    });\n    const ms = new Date() - start;\n    // console.log(ms);\n    expect(ms).toBeLessThan(maxTime);\n  });\n}\n\ndescribe('Perf', () => {\n  test('a huge string', bigString);\n  test('a huge array', bigArray);\n  test('an object with circular references', circularData);\n});\n"
  },
  {
    "path": "extension/test/setup.js",
    "content": "import { jest } from '@jest/globals';\nimport * as chrome from 'sinon-chrome';\n\nglobal.chrome = chrome;\nimport '@testing-library/jest-dom';\n\njest.setTimeout(50000);\n"
  },
  {
    "path": "extension/test/utils/e2e.js",
    "content": "import webdriver from 'selenium-webdriver';\n\nexport const delay = (time) =>\n  new Promise((resolve) => setTimeout(resolve, time));\n\nexport const switchMonitorTests = {\n  'should switch to Log Monitor': async function (driver) {\n    await driver\n      .findElement(webdriver.By.xpath('//button[text()=\"Inspector\"]'))\n      .click();\n    await delay(500); // Wait till menu is fully opened\n    await driver\n      .findElement(webdriver.By.xpath('//button[text()=\"Log monitor\"]'))\n      .click();\n    await delay(500);\n    await driver.findElement(\n      webdriver.By.xpath(\n        '//div[div[button[text()=\"Reset\"]] and .//div[button[text()=\"Revert\"]]]',\n      ),\n    );\n    await delay(500);\n  },\n\n  'should switch to Chart Monitor': async function (driver) {\n    await driver\n      .findElement(webdriver.By.xpath('//button[text()=\"Log monitor\"]'))\n      .click();\n    await delay(500); // Wait till menu is fully opened\n    await driver\n      .findElement(webdriver.By.xpath('//button[text()=\"Chart\"]'))\n      .click();\n    await delay(500);\n    await driver.findElement(\n      webdriver.By.xpath('//*[@class=\"nodeText\" and text()=\"state\"]'),\n    );\n    await delay(500); // Wait till menu is closed\n  },\n\n  'should switch back to Inspector Monitor': async function (driver) {\n    await driver\n      .findElement(webdriver.By.xpath('//button[text()=\"Chart\"]'))\n      .click();\n    await delay(1000); // Wait till menu is fully opened\n    await driver\n      .findElement(webdriver.By.xpath('//button[text()=\"Inspector\"]'))\n      .click();\n    await delay(1500); // Wait till menu is closed\n  },\n};\n"
  },
  {
    "path": "extension/test/utils/inject.js",
    "content": "export function insertScript(str) {\n  const s = window.document.createElement('script');\n  s.appendChild(document.createTextNode(str));\n  (document.head || document.documentElement).appendChild(s);\n}\n\nexport function listenMessage(f) {\n  return new Promise((resolve) => {\n    const listener = (event) => {\n      const message = event.data;\n      window.removeEventListener('message', listener);\n      resolve(message);\n    };\n    window.addEventListener('message', listener);\n    if (f) f();\n  });\n}\n"
  },
  {
    "path": "extension/tsconfig.json",
    "content": "{\n  \"extends\": \"../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"chrome\"]\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "jest.config.js",
    "content": "module.exports = {\n  projects: ['<rootDir>/extension', '<rootDir>/packages/*'],\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"private\": true,\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.29.0\",\n    \"@changesets/cli\": \"^2.30.0\",\n    \"@eslint/js\": \"^9.39.4\",\n    \"eslint\": \"^9.39.4\",\n    \"eslint-config-prettier\": \"^10.1.8\",\n    \"eslint-plugin-jest\": \"^29.15.0\",\n    \"eslint-plugin-react\": \"^7.37.5\",\n    \"eslint-plugin-react-hooks\": \"^7.0.1\",\n    \"jest\": \"^30.3.0\",\n    \"prettier\": \"3.8.1\",\n    \"typescript\": \"~5.9.3\",\n    \"typescript-eslint\": \"^8.57.0\"\n  },\n  \"scripts\": {\n    \"format\": \"prettier --write .\",\n    \"format:check\": \"prettier --check .\",\n    \"build:all\": \"pnpm --recursive run build\",\n    \"lint:all\": \"pnpm --recursive run lint\",\n    \"test:all\": \"pnpm --recursive run test\",\n    \"clean:all\": \"pnpm --recursive run clean\",\n    \"release\": \"pnpm build:all && pnpm publish -r\"\n  },\n  \"packageManager\": \"pnpm@10.32.1\"\n}\n"
  },
  {
    "path": "packages/d3-state-visualizer/CHANGELOG.md",
    "content": "# Change Log\n\n## 3.0.0\n\n### Major Changes\n\n- 191d419: Convert d3 packages to ESM\n\n### Patch Changes\n\n- Updated dependencies [191d419]\n  - d3tooltip@4.0.0\n  - map2tree@4.0.0\n\n## 2.0.0\n\n### Major Changes\n\n- b323f77d: Upgrade D3\n  - Remove UMD build.\n  - Split `style` option into `chartStyles`, `nodeStyleOptions`, `textStyleOptions`, and `linkStyles`.\n  - The shape of the argument passed to the `onClickText` option has been updated.\n  - Rename `InputOptions` to `Options`, `Primitive` to `StyleValue`, and `NodeWithId` to `HierarchyPointNode<Node>`.\n\n### Patch Changes\n\n- Updated dependencies [b323f77d]\n- Updated dependencies [b323f77d]\n  - d3tooltip@3.0.0\n  - map2tree@3.0.0\n\n## [1.4.0](https://github.com/reduxjs/redux-devtools/compare/d3-state-visualizer@1.3.4...d3-state-visualizer@1.4.0) (2021-03-06)\n\n### Features\n\n- **d3-state-visualizer:** convert example to TypeScript ([#641](https://github.com/reduxjs/redux-devtools/issues/641)) ([300b60a](https://github.com/reduxjs/redux-devtools/commit/300b60a8b1f92a6d7c78510a1bea304490aa23be))\n- **d3-state-visualizer:** convert to TypeScript ([#640](https://github.com/reduxjs/redux-devtools/issues/640)) ([0c78a5a](https://github.com/reduxjs/redux-devtools/commit/0c78a5a9a76ee7eff37dcd8e39272d98c03e0869))\n- **redux-devtools-chart-monitor:** convert to TypeScript ([#642](https://github.com/reduxjs/redux-devtools/issues/642)) ([761baba](https://github.com/reduxjs/redux-devtools/commit/761baba0aa0f4dc672f8771f4b12bed3863557f7))\n\n## [1.3.4](https://github.com/reduxjs/redux-devtools/compare/d3-state-visualizer@1.3.3...d3-state-visualizer@1.3.4) (2020-09-07)\n\n**Note:** Version bump only for package d3-state-visualizer\n\n## 1.3.3 (2020-08-14)\n\n**Note:** Version bump only for package d3-state-visualizer\n"
  },
  {
    "path": "packages/d3-state-visualizer/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Romain Séguy\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/d3-state-visualizer/README.md",
    "content": "# d3-state-visualizer\n\nEnables real-time visualization of your application state.\n\nCreated by [@romseguy](https://github.com/romseguy) and merged from [`reduxjs/d3-state-visualizer`](https://github.com/reduxjs/d3-state-visualizer).\n\n[Demo](http://reduxjs.github.io/d3-state-visualizer)\n\n## Installation\n\n`yarn install d3-state-visualizer`\n\n## Usage\n\n```javascript\nimport { tree } from 'd3-state-visualizer';\n\nconst appState = {\n  todoStore: {\n    todos: [\n      { title: 'd3' },\n      { title: 'state' },\n      { title: 'visualizer' },\n      { title: 'tree' },\n    ],\n    completedCount: 1,\n  },\n};\n\nconst render = tree(document.getElementById('root'), {\n  state: appState,\n  id: 'treeExample',\n  size: 1000,\n  aspectRatio: 0.5,\n  isSorted: false,\n  widthBetweenNodesCoeff: 1.5,\n  heightBetweenNodesCoeff: 2,\n  chartStyles: { border: '1px solid black' },\n  tooltipOptions: { offset: { left: 30, top: 10 }, indentationSize: 2 },\n});\n\nrender();\n```\n\n## Charts API\n\nThe APIs are minimal and consists of a single function you provide with:\n\n- a DOM element\n- a plain old JS object for options.\n\n#### Tree\n\nThis chart is a bit special as it accepts either one of the two following options, but **not both**:\n\n- `tree`: a properly formed tree structure such as one generated by [map2tree](https://github.com/reduxjs/redux-devtools/tree/master/packages/map2tree) or [react2tree](https://github.com/romseguy/react2tree)\n- `state`: a plain javascript object mapping arbitrarily nested keys to values – which will be transformed into a tree structure, again using [map2tree](https://github.com/reduxjs/redux-devtools/tree/master/packages/map2tree).\n\nOther options are listed below and have reasonable default values if you want to omit them:\n\n| Option                    | Type    | Default                                                                          | Description                                                                                                                                                                                                                                                                                  |\n| ------------------------- | ------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `id`                      | String  | `'d3svg'`                                                                        | Sets the identifier of the SVG element —i.e your chart— that will be added to the DOM element you passed as first argument                                                                                                                                                                   |\n| `chartStyles`             | Object  | `{}`                                                                             | Sets the CSS style of the chart                                                                                                                                                                                                                                                              |\n| `size`                    | Number  | `500`                                                                            | Sets size of the chart in pixels                                                                                                                                                                                                                                                             |\n| `aspectRatio`             | Float   | `1.0`                                                                            | Sets the chart height to `size * aspectRatio` and [viewBox](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox) in order to preserve the aspect ratio of the chart. [Great video](https://www.youtube.com/watch?v=FCOeMy7HrBc) if you want to learn more about how SVG works |\n| `widthBetweenNodesCoeff`  | Float   | `1.0`                                                                            | Alters the horizontal space between each node                                                                                                                                                                                                                                                |\n| `heightBetweenNodesCoeff` | Float   | `1.0`                                                                            | Alters the vertical space between each node                                                                                                                                                                                                                                                  |\n| `isSorted`                | Boolean | `false`                                                                          | Sorts the chart in alphabetical order                                                                                                                                                                                                                                                        |\n| `transitionDuration`      | Number  | `750`                                                                            | Sets the duration of all the transitions used by the chart                                                                                                                                                                                                                                   |\n| `tooltipOptions`          | Object  | [here](https://github.com/reduxjs/redux-devtools/tree/master/packages/d3tooltip) | Sets the options for the [tooltip](https://github.com/reduxjs/redux-devtools/tree/master/packages/d3tooltip) that is showing up when you're hovering the nodes                                                                                                                               |\n| `rootKeyName`             | String  | `'state'`                                                                        | Sets the first node's name of the resulting tree structure. **Warning**: only works if you provide a `state` option                                                                                                                                                                          |\n| `pushMethod`              | String  | `'push'`                                                                         | Sets the method that shall be used to add array children to the tree. **Warning**: only works if you provide a `state` option                                                                                                                                                                |\n\nMore to come...\n\n## Roadmap\n\n- Threshold for large arrays so only a single node is displayed instead of all the children. That single node would be exclude from searching until selected.\n"
  },
  {
    "path": "packages/d3-state-visualizer/eslint.config.js",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTs from '../../eslint.ts.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTs(import.meta.dirname),\n  {\n    ignores: ['examples', 'lib'],\n  },\n];\n"
  },
  {
    "path": "packages/d3-state-visualizer/examples/tree/CHANGELOG.md",
    "content": "# d3-state-visualizer-tree-example\n\n## 0.1.6\n\n### Patch Changes\n\n- Updated dependencies [191d419]\n  - d3-state-visualizer@3.0.0\n  - map2tree@4.0.0\n\n## 0.1.5\n\n### Patch Changes\n\n- Updated dependencies [b323f77d]\n- Updated dependencies [b323f77d]\n  - d3-state-visualizer@2.0.0\n  - map2tree@3.0.0\n"
  },
  {
    "path": "packages/d3-state-visualizer/examples/tree/eslint.config.mjs",
    "content": "import eslintJs from '../../../../eslint.js.config.base.mjs';\nimport eslintTs from '../../../../eslint.ts.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTs(import.meta.dirname),\n  ...eslintTs(\n    import.meta.dirname,\n    ['webpack.config.ts'],\n    ['./tsconfig.webpack.json'],\n  ),\n  {\n    ignores: ['dist'],\n  },\n];\n"
  },
  {
    "path": "packages/d3-state-visualizer/examples/tree/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>State tree with d3-state-visualizer</title>\n    <style type=\"text/css\">\n      .node {\n        cursor: pointer;\n      }\n\n      .nodeCircle {\n        stroke: black;\n        stroke-width: 1.5px;\n      }\n\n      .nodeText {\n        font-family: sans-serif;\n        font-size: 10px;\n      }\n\n      .link {\n        fill: none;\n        stroke: #ccc;\n        stroke-width: 1.5px;\n      }\n\n      .tooltip {\n        font-family: Consolas, Menlo, Monaco, monospace;\n        font-size: 0.8em;\n        background: rgba(0, 0, 0, 0.5);\n        color: white;\n        padding: 10px;\n        border-radius: 5px;\n      }\n    </style>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/index.ts\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/d3-state-visualizer/examples/tree/package.json",
    "content": "{\n  \"private\": true,\n  \"name\": \"d3-state-visualizer-tree-example\",\n  \"version\": \"0.1.6\",\n  \"description\": \"Visualize your app state as a tree\",\n  \"keywords\": [\n    \"d3\",\n    \"state\",\n    \"store\",\n    \"visualization\"\n  ],\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/d3-state-visualizer/examples/tree\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"tsc && vite build\",\n    \"preview\": \"vite preview\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc\"\n  },\n  \"dependencies\": {\n    \"d3-state-visualizer\": \"workspace:^\",\n    \"map2tree\": \"workspace:^\"\n  },\n  \"devDependencies\": {\n    \"typescript\": \"~5.9.3\",\n    \"vite\": \"^8.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/d3-state-visualizer/examples/tree/src/index.ts",
    "content": "import { tree } from 'd3-state-visualizer';\n\nconst appState = {\n  todoStore: {\n    todos: [\n      { title: 'd3' },\n      { title: 'state' },\n      { title: 'visualizer' },\n      { title: 'tree' },\n    ],\n    completedCount: 1,\n    alphabeticalOrder: true,\n  },\n  someStore: {\n    someProperty: 0,\n    someObject: {\n      anotherProperty: 'value',\n      someArray: [0, 1, 2],\n    },\n  },\n};\n\nconst render = tree(document.getElementById('root')!, {\n  state: appState,\n  id: 'treeExample',\n  size: 1000,\n  aspectRatio: 0.5,\n  isSorted: false,\n  widthBetweenNodesCoeff: 1.5,\n  heightBetweenNodesCoeff: 2,\n  chartStyles: { border: '1px solid black' },\n  tooltipOptions: { offset: { left: 30, top: 10 }, indentationSize: 2 },\n});\n\nrender();\n"
  },
  {
    "path": "packages/d3-state-visualizer/examples/tree/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../../tsconfig.esm.base.json\",\n  \"compilerOptions\": {\n    \"noEmit\": true\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/d3-state-visualizer/package.json",
    "content": "{\n  \"name\": \"d3-state-visualizer\",\n  \"version\": \"3.0.0\",\n  \"description\": \"Visualize your app state with a range of reusable charts\",\n  \"keywords\": [\n    \"d3\",\n    \"state\",\n    \"store\",\n    \"tree\",\n    \"visualization\"\n  ],\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/d3-state-visualizer\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"romseguy\",\n  \"files\": [\n    \"dist\",\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": \"./lib/index.js\",\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run lint\"\n  },\n  \"dependencies\": {\n    \"@types/d3\": \"^7.4.3\",\n    \"d3\": \"^7.9.0\",\n    \"d3tooltip\": \"workspace:^\",\n    \"deepmerge\": \"^4.3.1\",\n    \"map2tree\": \"workspace:^\",\n    \"ramda\": \"^0.32.0\"\n  },\n  \"devDependencies\": {\n    \"@types/ramda\": \"^0.31.1\",\n    \"rimraf\": \"^6.1.3\",\n    \"typescript\": \"~5.9.3\"\n  }\n}\n"
  },
  {
    "path": "packages/d3-state-visualizer/src/charts/index.ts",
    "content": "export type { HierarchyPointNode } from 'd3';\nexport type { StyleValue } from 'd3tooltip';\nexport { default as tree } from './tree/tree.js';\nexport type { Node, Options } from './tree/tree.js';\n"
  },
  {
    "path": "packages/d3-state-visualizer/src/charts/tree/sortAndSerialize.ts",
    "content": "function sortObject(obj: unknown, strict?: boolean) {\n  if (obj instanceof Array) {\n    let ary;\n    if (strict) {\n      ary = obj.sort();\n    } else {\n      ary = obj;\n    }\n    return ary;\n  }\n\n  if (obj && typeof obj === 'object') {\n    const tObj: { [key: string]: unknown } = {};\n    Object.keys(obj)\n      .sort()\n      .forEach((key) => (tObj[key] = sortObject(obj[key as keyof typeof obj])));\n    return tObj;\n  }\n\n  return obj;\n}\n\nexport default function sortAndSerialize(obj: unknown) {\n  return JSON.stringify(sortObject(obj, true), undefined, 2);\n}\n"
  },
  {
    "path": "packages/d3-state-visualizer/src/charts/tree/tree.ts",
    "content": "import * as d3 from 'd3';\nimport type { D3ZoomEvent, HierarchyPointLink, HierarchyPointNode } from 'd3';\nimport { isEmpty } from 'ramda';\nimport { map2tree } from 'map2tree';\nimport type { Node } from 'map2tree';\nimport deepmerge from 'deepmerge';\nimport {\n  getTooltipString,\n  toggleChildren,\n  visit,\n  getNodeGroupByDepthCount,\n} from './utils.js';\nimport { tooltip } from 'd3tooltip';\nimport type { StyleValue } from 'd3tooltip';\n\nexport interface Options {\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  state?: {} | null;\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  tree?: Node | {};\n\n  rootKeyName: string;\n  pushMethod: 'push' | 'unshift';\n  id: string;\n  chartStyles: { [key: string]: StyleValue };\n  nodeStyleOptions: {\n    colors: {\n      default: string;\n      collapsed: string;\n      parent: string;\n    };\n    radius: number;\n  };\n  textStyleOptions: {\n    colors: {\n      default: string;\n      hover: string;\n    };\n  };\n  linkStyles: { [key: string]: StyleValue };\n  size: number;\n  aspectRatio: number;\n  initialZoom: number;\n  margin: {\n    top: number;\n    right: number;\n    bottom: number;\n    left: number;\n  };\n  isSorted: boolean;\n  heightBetweenNodesCoeff: number;\n  widthBetweenNodesCoeff: number;\n  transitionDuration: number;\n  blinkDuration: number;\n  onClickText: (datum: HierarchyPointNode<Node>) => void;\n  tooltipOptions: {\n    disabled?: boolean;\n    left?: number | undefined;\n    top?: number | undefined;\n    offset?: {\n      left: number;\n      top: number;\n    };\n    styles?: { [key: string]: StyleValue } | undefined;\n    indentationSize?: number;\n  };\n}\n\nconst defaultOptions: Options = {\n  state: undefined,\n  rootKeyName: 'state',\n  pushMethod: 'push',\n  tree: undefined,\n  id: 'd3svg',\n  chartStyles: {},\n  nodeStyleOptions: {\n    colors: {\n      default: '#ccc',\n      collapsed: 'lightsteelblue',\n      parent: 'white',\n    },\n    radius: 7,\n  },\n  textStyleOptions: {\n    colors: {\n      default: 'black',\n      hover: 'skyblue',\n    },\n  },\n  linkStyles: {\n    stroke: '#000',\n    fill: 'none',\n  },\n  size: 500,\n  aspectRatio: 1.0,\n  initialZoom: 1,\n  margin: {\n    top: 10,\n    right: 10,\n    bottom: 10,\n    left: 50,\n  },\n  isSorted: false,\n  heightBetweenNodesCoeff: 2,\n  widthBetweenNodesCoeff: 1,\n  transitionDuration: 750,\n  blinkDuration: 100,\n  onClickText: () => {\n    // noop\n  },\n  tooltipOptions: {\n    disabled: false,\n    left: undefined,\n    top: undefined,\n    offset: {\n      left: 0,\n      top: 0,\n    },\n    styles: undefined,\n  },\n} satisfies Options;\n\nexport interface InternalNode extends Node {\n  _children?: this[] | undefined;\n  id: string | number;\n}\n\ninterface NodePosition {\n  parentId: string | number | null;\n  id: string | number;\n  x: number;\n  y: number;\n}\n\nexport default function (DOMNode: HTMLElement, options: Partial<Options> = {}) {\n  const {\n    id,\n    chartStyles,\n    nodeStyleOptions,\n    textStyleOptions,\n    linkStyles,\n    size,\n    aspectRatio,\n    initialZoom,\n    margin,\n    isSorted,\n    widthBetweenNodesCoeff,\n    heightBetweenNodesCoeff,\n    transitionDuration,\n    blinkDuration,\n    state,\n    rootKeyName,\n    pushMethod,\n    tree,\n    tooltipOptions,\n    onClickText,\n  } = deepmerge(defaultOptions, options);\n\n  const width = size - margin.left - margin.right;\n  const height = size * aspectRatio - margin.top - margin.bottom;\n  const fullWidth = size;\n  const fullHeight = size * aspectRatio;\n\n  const root = d3.select(DOMNode);\n  const zoom = d3.zoom<SVGSVGElement, unknown>().scaleExtent([0.1, 3]);\n\n  const svgElement = root\n    .append('svg')\n    .attr('id', id)\n    .attr('preserveAspectRatio', 'xMinYMin slice')\n    .style('cursor', '-webkit-grab');\n\n  if (!chartStyles.width) {\n    svgElement.attr('width', fullWidth);\n  }\n\n  if (!chartStyles.width || !chartStyles.height) {\n    svgElement.attr('viewBox', `0 0 ${fullWidth} ${fullHeight}`);\n  }\n\n  for (const [key, value] of Object.entries(chartStyles)) {\n    svgElement.style(key, value);\n  }\n\n  const vis = svgElement\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    .call(zoom.scaleTo, initialZoom)\n    .call(\n      zoom.on('zoom', (event) => {\n        const { transform } = event as D3ZoomEvent<SVGSVGElement, unknown>;\n        vis.attr('transform', transform.toString());\n      }),\n    )\n    .append('g')\n    .attr(\n      'transform',\n      `translate(${margin.left + nodeStyleOptions.radius}, ${\n        margin.top\n      }) scale(${initialZoom})`,\n    );\n\n  // previousNodePositionsById stores node x and y\n  // as well as hierarchy (id / parentId);\n  // helps animating transitions\n  let previousNodePositionsById: { [nodeId: string]: NodePosition } = {\n    root: {\n      id: 'root',\n      parentId: null,\n      x: height / 2,\n      y: 0,\n    },\n  };\n\n  // traverses a map with node positions by going through the chain\n  // of parent ids; once a parent that matches the given filter is found,\n  // the parent position gets returned\n  function findParentNodePosition(\n    nodePositionsById: { [nodeId: string | number]: NodePosition },\n    nodeId: string | number,\n    filter: (nodePosition: NodePosition) => boolean,\n  ) {\n    let currentPosition = nodePositionsById[nodeId];\n    while (currentPosition) {\n      currentPosition = nodePositionsById[currentPosition.parentId!];\n      if (!currentPosition) {\n        return null;\n      }\n      if (!filter || filter(currentPosition)) {\n        return currentPosition;\n      }\n    }\n  }\n\n  return function renderChart(nextState = tree || state) {\n    let data = !tree\n      ? (map2tree(nextState, {\n          key: rootKeyName,\n          pushMethod,\n        }) as InternalNode)\n      : (nextState as InternalNode);\n\n    if (isEmpty(data) || !data.name) {\n      data = {\n        name: 'error',\n        message: 'Please provide a state map or a tree structure',\n      } as unknown as InternalNode;\n    }\n\n    let nodeIndex = 0;\n    let maxLabelLength = 0;\n\n    // nodes are assigned with string ids, which reflect their location\n    // within the hierarcy; e.g. \"root|branch|subBranch|subBranch[0]|property\"\n    // top-level elemnt always has id \"root\"\n    visit(\n      data,\n      (node) => {\n        maxLabelLength = Math.max(node.name.length, maxLabelLength);\n        node.id = node.id || 'root';\n      },\n      (node) =>\n        node.children && node.children.length > 0\n          ? node.children.map((c) => {\n              c.id = `${node.id || ''}|${c.name}`;\n              return c;\n            })\n          : null,\n    );\n\n    update();\n\n    function update() {\n      // path generator for links\n      const linkHorizontal = d3\n        .linkHorizontal<\n          {\n            source: { x: number; y: number };\n            target: { x: number; y: number };\n          },\n          { x: number; y: number }\n        >()\n        .x((d) => d.y)\n        .y((d) => d.x);\n      // set tree dimensions and spacing between branches and nodes\n      const maxNodeCountByLevel = Math.max(...getNodeGroupByDepthCount(data));\n\n      const layout = d3\n        .tree<InternalNode>()\n        .size([maxNodeCountByLevel * 25 * heightBetweenNodesCoeff, width]);\n\n      const rootNode = d3.hierarchy(data);\n      if (isSorted) {\n        rootNode.sort((a, b) =>\n          b.data.name.toLowerCase() < a.data.name.toLowerCase() ? 1 : -1,\n        );\n      }\n\n      const rootPointNode = layout(rootNode);\n      const links = rootPointNode.links();\n\n      rootPointNode.each(\n        (node) =>\n          (node.y = node.depth * (maxLabelLength * 7 * widthBetweenNodesCoeff)),\n      );\n\n      const nodes = rootPointNode.descendants();\n\n      const nodePositions = nodes.map((n) => ({\n        parentId: n.parent && n.parent.data.id,\n        id: n.data.id,\n        x: n.x,\n        y: n.y,\n      }));\n      const nodePositionsById: { [nodeId: string | number]: NodePosition } = {};\n      nodePositions.forEach((node) => (nodePositionsById[node.id] = node));\n\n      // process the node selection\n      const node = vis\n        .selectAll<SVGGElement, HierarchyPointNode<InternalNode>>('g.node')\n        .property('__oldData__', (d) => d)\n        .data(nodes, (d) => d.data.id || (d.data.id = ++nodeIndex));\n      const nodeEnter = node\n        .enter()\n        .append('g')\n        .attr('class', 'node')\n        .attr('transform', (d) => {\n          const position = findParentNodePosition(\n            nodePositionsById,\n            d.data.id,\n            (n) => !!previousNodePositionsById[n.id],\n          );\n          const previousPosition =\n            (position && previousNodePositionsById[position.id]) ||\n            previousNodePositionsById.root;\n          return `translate(${previousPosition.y},${previousPosition.x})`;\n        })\n        .style('fill', textStyleOptions.colors.default)\n        .style('cursor', 'pointer')\n        .on('mouseover', function mouseover() {\n          d3.select(this).style('fill', textStyleOptions.colors.hover);\n        })\n        .on('mouseout', function mouseout() {\n          d3.select(this).style('fill', textStyleOptions.colors.default);\n        });\n\n      if (!tooltipOptions.disabled) {\n        nodeEnter.call(\n          tooltip<\n            SVGGElement,\n            HierarchyPointNode<InternalNode>,\n            SVGGElement,\n            unknown,\n            HTMLElement,\n            unknown,\n            null,\n            undefined\n          >('tooltip', {\n            ...tooltipOptions,\n            root,\n            text: (d) => getTooltipString(d.data, tooltipOptions),\n          }),\n        );\n      }\n\n      // g inside node contains circle and text\n      // this extra wrapper helps run d3 transitions in parallel\n      const nodeEnterInnerGroup = nodeEnter.append('g');\n      nodeEnterInnerGroup\n        .append('circle')\n        .attr('class', 'nodeCircle')\n        .attr('r', 0)\n        .on('click', (event, clickedNode) => {\n          if ((event as Event).defaultPrevented) return;\n          toggleChildren(clickedNode.data);\n          update();\n        });\n\n      nodeEnterInnerGroup\n        .append('text')\n        .attr('class', 'nodeText')\n        .attr('text-anchor', 'middle')\n        .attr('transform', 'translate(0,0)')\n        .attr('dy', '.35em')\n        .style('fill-opacity', 0)\n        .text((d) => d.data.name)\n        .on('click', (_, datum) => {\n          onClickText(datum as unknown as HierarchyPointNode<Node>);\n        });\n\n      const nodeEnterAndUpdate = nodeEnter.merge(node);\n\n      // update the text to reflect whether node has children or not\n      nodeEnterAndUpdate.select('text').text((d) => d.data.name);\n\n      // change the circle fill depending on whether it has children and is collapsed\n      nodeEnterAndUpdate\n        .select('circle')\n        .style('stroke', 'black')\n        .style('stroke-width', '1.5px')\n        .style('fill', (d) =>\n          d.data._children && d.data._children.length > 0\n            ? nodeStyleOptions.colors.collapsed\n            : d.data.children && d.data.children.length > 0\n              ? nodeStyleOptions.colors.parent\n              : nodeStyleOptions.colors.default,\n        );\n\n      // transition nodes to their new position\n      const nodeUpdate = nodeEnterAndUpdate\n        .transition()\n        .duration(transitionDuration)\n        .attr('transform', (d) => `translate(${d.y},${d.x})`);\n\n      // ensure circle radius is correct\n      nodeUpdate.select('circle').attr('r', nodeStyleOptions.radius);\n\n      // fade the text in and align it\n      nodeUpdate\n        .select<SVGTextElement>('text')\n        .style('fill-opacity', 1)\n        .attr('transform', function transform(d) {\n          const x =\n            (((d.data.children ?? d.data._children)?.length ?? 0) > 0\n              ? -1\n              : 1) *\n            (this.getBBox().width / 2 + nodeStyleOptions.radius + 5);\n          return `translate(${x},0)`;\n        });\n\n      // blink updated nodes\n      nodeEnterAndUpdate\n        .filter(function flick(\n          this: SVGGElement & {\n            __oldData__?: HierarchyPointNode<InternalNode>;\n          },\n          d,\n        ) {\n          // test whether the relevant properties of d match\n          // the equivalent property of the oldData\n          // also test whether the old data exists,\n          // to catch the entering elements!\n          return (\n            !!this.__oldData__ && d.data.value !== this.__oldData__.data.value\n          );\n        })\n        .select('g')\n        .style('opacity', '0.3')\n        .transition()\n        .duration(blinkDuration)\n        .style('opacity', '1');\n\n      // transition exiting nodes to the parent's new position\n      const nodeExit = node\n        .exit<HierarchyPointNode<InternalNode>>()\n        .transition()\n        .duration(transitionDuration)\n        .attr('transform', (d) => {\n          const position = findParentNodePosition(\n            previousNodePositionsById,\n            d.data.id,\n            (n) => !!nodePositionsById[n.id],\n          );\n          const futurePosition =\n            (position && nodePositionsById[position.id]) ||\n            nodePositionsById.root;\n          return `translate(${futurePosition.y},${futurePosition.x})`;\n        })\n        .remove();\n\n      nodeExit.select('circle').attr('r', 0);\n\n      nodeExit.select('text').style('fill-opacity', 0);\n\n      // update the links\n      const link = vis\n        .selectAll<\n          SVGPathElement,\n          HierarchyPointLink<InternalNode>\n        >('path.link')\n        .data(links, (d) => d.target.data.id);\n\n      // enter any new links at the parent's previous position\n      const linkEnter = link\n        .enter()\n        .insert('path', 'g')\n        .attr('class', 'link')\n        .attr('d', (d) => {\n          const position = findParentNodePosition(\n            nodePositionsById,\n            d.target.data.id,\n            (n) => !!previousNodePositionsById[n.id],\n          );\n          const previousPosition =\n            (position && previousNodePositionsById[position.id]) ||\n            previousNodePositionsById.root;\n          return linkHorizontal({\n            source: previousPosition,\n            target: previousPosition,\n          });\n        });\n\n      for (const [key, value] of Object.entries(linkStyles)) {\n        linkEnter.style(key, value);\n      }\n\n      const linkEnterAndUpdate = linkEnter.merge(link);\n\n      // transition links to their new position\n      linkEnterAndUpdate\n        .transition()\n        .duration(transitionDuration)\n        .attr('d', linkHorizontal);\n\n      // transition exiting nodes to the parent's new position\n      link\n        .exit<HierarchyPointLink<InternalNode>>()\n        .transition()\n        .duration(transitionDuration)\n        .attr('d', (d) => {\n          const position = findParentNodePosition(\n            previousNodePositionsById,\n            d.target.data.id,\n            (n) => !!nodePositionsById[n.id],\n          );\n          const futurePosition =\n            (position && nodePositionsById[position.id]) ||\n            nodePositionsById.root;\n          return linkHorizontal({\n            source: futurePosition,\n            target: futurePosition,\n          });\n        })\n        .remove();\n\n      // delete the old data once it's no longer needed\n      nodeEnterAndUpdate.property('__oldData__', null);\n\n      // stash the old positions for transition\n      previousNodePositionsById = nodePositionsById;\n    }\n  };\n}\n\nexport type { Node };\n"
  },
  {
    "path": "packages/d3-state-visualizer/src/charts/tree/utils.ts",
    "content": "import { is, join, pipe, replace } from 'ramda';\nimport sortAndSerialize from './sortAndSerialize.js';\nimport type { InternalNode } from './tree.js';\n\nexport function collapseChildren(node: InternalNode) {\n  if (node.children) {\n    node._children = node.children;\n    node._children.forEach(collapseChildren);\n    node.children = undefined;\n  }\n}\n\nexport function expandChildren(node: InternalNode) {\n  if (node._children) {\n    node.children = node._children;\n    node.children.forEach(expandChildren);\n    node._children = undefined;\n  }\n}\n\nexport function toggleChildren(node: InternalNode) {\n  if (node.children) {\n    node._children = node.children;\n    node.children = undefined;\n  } else if (node._children) {\n    node.children = node._children;\n    node._children = undefined;\n  }\n  return node;\n}\n\nexport function visit(\n  parent: InternalNode,\n  visitFn: (parent: InternalNode) => void,\n  childrenFn: (parent: InternalNode) => InternalNode[] | null | undefined,\n) {\n  if (!parent) {\n    return;\n  }\n\n  visitFn(parent);\n\n  const children = childrenFn(parent);\n  if (children) {\n    const count = children.length;\n\n    for (let i = 0; i < count; i++) {\n      visit(children[i], visitFn, childrenFn);\n    }\n  }\n}\n\nexport function getNodeGroupByDepthCount(rootNode: InternalNode) {\n  const nodeGroupByDepthCount = [1];\n\n  const traverseFrom = function traverseFrom(node: InternalNode, depth = 0) {\n    if (!node.children || node.children.length === 0) {\n      return 0;\n    }\n\n    if (nodeGroupByDepthCount.length <= depth + 1) {\n      nodeGroupByDepthCount.push(0);\n    }\n\n    nodeGroupByDepthCount[depth + 1] += node.children.length;\n\n    node.children.forEach((childNode) => {\n      traverseFrom(childNode, depth + 1);\n    });\n  };\n\n  traverseFrom(rootNode);\n  return nodeGroupByDepthCount;\n}\n\nexport function getTooltipString(node: InternalNode, { indentationSize = 4 }) {\n  if (!is(Object, node)) return '';\n\n  const spacer = join('&nbsp;&nbsp;');\n  const cr2br = replace(/\\n/g, '<br/>');\n  const spaces2nbsp = replace(/\\s{2}/g, spacer(new Array(indentationSize)));\n  const json2html = pipe(sortAndSerialize, cr2br, spaces2nbsp);\n\n  const children = node.children || node._children;\n\n  if (typeof node.value !== 'undefined') return json2html(node.value);\n  if (typeof node.object !== 'undefined') return json2html(node.object);\n  if (children && children.length) return `childrenCount: ${children.length}`;\n  return 'empty';\n}\n"
  },
  {
    "path": "packages/d3-state-visualizer/src/index.ts",
    "content": "export { tree } from './charts/index.js';\nexport type {\n  HierarchyPointNode,\n  Node,\n  Options,\n  StyleValue,\n} from './charts/index.js';\n"
  },
  {
    "path": "packages/d3-state-visualizer/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/d3tooltip/CHANGELOG.md",
    "content": "# Change Log\n\n## 4.0.0\n\n### Major Changes\n\n- 191d419: Convert d3 packages to ESM\n\n## 3.0.1\n\n### Patch Changes\n\n- 7f5bddbd: Widen peer dependencies\n\n## 3.0.0\n\n### Major Changes\n\n- b323f77d: Upgrade D3\n  - Remove UMD build.\n  - Upgrade d3 peer dependency from v3 to v7.\n  - Remove `attr` configuration method.\n  - Rename `style` configuration method to `styles` and move to options.\n  - Move `text` configuration method to options.\n  - Remove d3 parameter as first parameter for `tooltip`.\n\n## 2.0.0\n\n- Adds ESM build (https://github.com/reduxjs/redux-devtools/pull/997) and switches the default export to a named export in order to ensure that the CommonJS output and the ESM output are [interchangeable](https://rollupjs.org/guide/en/#outputexports):\n\n```diff\n- import d3tooltip from 'd3tooltip';\n+ import { tooltip } from 'd3tooltip';\n```\n\n## [1.3.0](https://github.com/reduxjs/redux-devtools/compare/d3tooltip@1.2.3...d3tooltip@1.3.0) (2021-03-06)\n\n### Features\n\n- **d3-state-visualizer:** convert to TypeScript ([#640](https://github.com/reduxjs/redux-devtools/issues/640)) ([0c78a5a](https://github.com/reduxjs/redux-devtools/commit/0c78a5a9a76ee7eff37dcd8e39272d98c03e0869))\n- **d3tooltip:** convert to TypeScript ([#639](https://github.com/reduxjs/redux-devtools/issues/639)) ([3b580da](https://github.com/reduxjs/redux-devtools/commit/3b580dad4cb36abc395f9be139b2c3f94e872d87))\n\n## 1.2.3 (2020-08-14)\n\n**Note:** Version bump only for package d3tooltip\n"
  },
  {
    "path": "packages/d3tooltip/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 romseguy\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/d3tooltip/README.md",
    "content": "# d3tooltip\n\nThis tooltip aims for a minimal yet highly configurable API. It has a long way to go, but the essentials are there.\nIt was created by [@romseguy](https://github.com/romseguy) and merged from [`romseguy/d3tooltip`](https://github.com/romseguy/d3tooltip).\n\n## Installation\n\n`npm install d3-state-visualizer`\n\n## Quick usage\n\n```javascript\nimport * as d3 from 'd3';\nimport { tooltip } from 'd3tooltip';\n\nconst DOMNode = document.getElementById('chart');\nconst root = d3.select(DOMNode);\nconst vis = root.append('svg');\n\nconst options = {\n  offset: { left: 30, top: 10 },\n  styles: { 'min-width': '50px', 'border-radius': '5px' },\n};\n\nvis\n  .selectAll('circle')\n  .data(someData)\n  .enter()\n  .append('circle')\n  .attr('r', 10)\n  .call(\n    d3tooltip('tooltipClassName', {\n      ...options,\n      text: (d) => toStringOrHtml(d),\n    }),\n  )\n  .on('mouseover', function () {\n    d3.select(this).style('fill', 'skyblue');\n  })\n  .on('mouseout', function () {\n    d3.select(this).style('fill', 'black');\n  });\n```\n\n## API\n\n| Option   | Type               | Default             | Description                                                                                                                                                      |\n| -------- | ------------------ | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `root`   | DOM.Element        | `body`              | The tooltip will be added as a child of that element. You can also use a D3 [selection](https://github.com/mbostock/d3/wiki/Selections#d3_select).               |\n| `left`   | Number             | `undefined`         | Sets the tooltip `x` absolute position instead of the mouse `x` position, relative to the `root` element.                                                        |\n| `top`    | Number             | `undefined`         | Sets the tooltip `y` absolute position instead of the mouse `y` position, relative to the `root` element.                                                        |\n| `offset` | Object             | `{left: 0, top: 0}` | Sets the distance, starting from the cursor position, until the tooltip is rendered. **Warning**: only applicable if you don't provide a `left` or `top` option. |\n| `styles` | Object             | `{}`                | Sets the styles of the tooltip element.                                                                                                                          |\n| `text`   | String or Function | `''`                | Sets the text of the tooltip. Can be a constant `string` or a function that takes the datum and returns a `string`.                                              |\n"
  },
  {
    "path": "packages/d3tooltip/eslint.config.js",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTs from '../../eslint.ts.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTs(import.meta.dirname),\n  {\n    ignores: ['lib'],\n  },\n];\n"
  },
  {
    "path": "packages/d3tooltip/package.json",
    "content": "{\n  \"name\": \"d3tooltip\",\n  \"version\": \"4.0.0\",\n  \"description\": \"A highly configurable tooltip for d3\",\n  \"keywords\": [\n    \"d3\",\n    \"tooltip\"\n  ],\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/d3tooltip\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"romseguy\",\n  \"files\": [\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": \"./lib/index.js\",\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run lint\"\n  },\n  \"devDependencies\": {\n    \"@types/d3\": \"^7.4.3\",\n    \"d3\": \"^7.9.0\",\n    \"rimraf\": \"^6.1.3\",\n    \"typescript\": \"~5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"@types/d3\": \"^7.4.3\",\n    \"d3\": \"^7.9.0\"\n  }\n}\n"
  },
  {
    "path": "packages/d3tooltip/src/index.ts",
    "content": "import * as d3 from 'd3';\nimport type { BaseType, Selection } from 'd3';\n\nexport type StyleValue = string | number | boolean;\n\ninterface Options<\n  Datum,\n  RootGElement extends BaseType,\n  RootDatum,\n  RootPElement extends BaseType,\n  RootPDatum,\n> {\n  left: number | undefined;\n  top: number | undefined;\n  offset: {\n    left: number;\n    top: number;\n  };\n  root:\n    | Selection<RootGElement, RootDatum, RootPElement, RootPDatum>\n    | undefined;\n  styles: { [key: string]: StyleValue };\n  text: string | ((datum: Datum) => string);\n}\n\nconst defaultOptions: Options<unknown, BaseType, unknown, BaseType, unknown> = {\n  left: undefined, // mouseX\n  top: undefined, // mouseY\n  offset: { left: 0, top: 0 },\n  root: undefined,\n  styles: {},\n  text: '',\n};\n\nexport function tooltip<\n  GElement extends BaseType,\n  Datum,\n  PElement extends BaseType,\n  PDatum,\n  RootGElement extends BaseType,\n  RootDatum,\n  RootPElement extends BaseType,\n  RootPDatum,\n>(\n  className = 'tooltip',\n  options: Partial<\n    Options<Datum, RootGElement, RootDatum, RootPElement, RootPDatum>\n  > = {},\n) {\n  const { left, top, offset, root, styles, text } = {\n    ...defaultOptions,\n    ...options,\n  } as Options<Datum, RootGElement, RootDatum, RootPElement, RootPDatum>;\n\n  let el: Selection<HTMLDivElement, RootDatum, BaseType, unknown>;\n  const anchor: Selection<\n    RootGElement,\n    RootDatum,\n    RootPElement | HTMLElement,\n    RootPDatum\n  > = root || d3.select<RootGElement, RootDatum>('body');\n  const rootNode = anchor.node()!;\n\n  return function tip(selection: Selection<GElement, Datum, PElement, PDatum>) {\n    selection.on('mouseover.tip', (event, datum) => {\n      const [pointerX, pointerY] = d3.pointer(event, rootNode);\n      const [x, y] = [\n        left || pointerX + offset.left,\n        top || pointerY - offset.top,\n      ];\n\n      anchor.selectAll(`div.${className}`).remove();\n\n      el = anchor\n        .append('div')\n        .attr('class', className)\n        .style('position', 'absolute')\n        .style('z-index', 1001)\n        .style('left', `${x}px`)\n        .style('top', `${y}px`)\n        .html(typeof text === 'function' ? () => text(datum) : () => text);\n\n      for (const [key, value] of Object.entries(styles)) {\n        el.style(key, value);\n      }\n    });\n\n    selection.on('mousemove.tip', (event, datum) => {\n      const [pointerX, pointerY] = d3.pointer(event, rootNode);\n      const [x, y] = [\n        left || pointerX + offset.left,\n        top || pointerY - offset.top,\n      ];\n\n      el.style('left', `${x}px`)\n        .style('top', `${y}px`)\n        .html(typeof text === 'function' ? () => text(datum) : () => text);\n    });\n\n    selection.on('mouseout.tip', () => el.remove());\n  };\n}\n"
  },
  {
    "path": "packages/d3tooltip/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/map2tree/CHANGELOG.md",
    "content": "# Change Log\n\n## 4.0.0\n\n### Major Changes\n\n- 191d419: Convert d3 packages to ESM\n\n## 3.0.0\n\n### Major Changes\n\n- b323f77d: Remove UMD build.\n\n## 2.0.0\n\n- Adds ESM build (https://github.com/reduxjs/redux-devtools/pull/997) and switches the default export to a named export in order to ensure that the CommonJS output and the ESM output are [interchangeable](https://rollupjs.org/guide/en/#outputexports):\n\n```diff\n- import map2tree from 'map2tree';\n+ import { map2tree } from 'map2tree';\n```\n\n## [1.5.0](https://github.com/reduxjs/redux-devtools/compare/map2tree@1.4.2...map2tree@1.5.0) (2021-03-06)\n\n### Features\n\n- **d3-state-visualizer:** convert to TypeScript ([#640](https://github.com/reduxjs/redux-devtools/issues/640)) ([0c78a5a](https://github.com/reduxjs/redux-devtools/commit/0c78a5a9a76ee7eff37dcd8e39272d98c03e0869))\n- **d3tooltip:** convert to TypeScript ([#639](https://github.com/reduxjs/redux-devtools/issues/639)) ([3b580da](https://github.com/reduxjs/redux-devtools/commit/3b580dad4cb36abc395f9be139b2c3f94e872d87))\n- **map2tree:** convert to TypeScript ([#638](https://github.com/reduxjs/redux-devtools/issues/638)) ([3b027f4](https://github.com/reduxjs/redux-devtools/commit/3b027f400e0e326596eedc2ee17ab45a8383080d))\n\n## 1.4.2 (2020-08-14)\n\n### Bug Fixes\n\n- **map2tree:** consolidate immutable version ([#538](https://github.com/reduxjs/redux-devtools/issues/538)) ([999ed2a](https://github.com/reduxjs/redux-devtools/commit/999ed2ad8b4a09eddd55c2a944f5488ecce6bc7b))\n"
  },
  {
    "path": "packages/map2tree/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Romain Séguy\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/map2tree/README.md",
    "content": "A pure function to convert a map into a tree structure. Created by [@romseguy](https://github.com/romseguy) and merged from [`romseguy/map2tree`](https://github.com/romseguy/map2tree).\n\nThe following opinions must be taken into account since the primary use case of this library is [redux-devtools-chart-monitor](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-chart-monitor):\n\n- Objects and arrays deeply nested within collections are not converted into a tree structure. See `someNestedObject` and `someNestedArray` in the [output](https://github.com/romseguy/map2tree#output) below, or the [corresponding test](https://github.com/romseguy/map2tree/blob/master/test/map2tree.js#L140).\n- Provides support for [Immutable.js](https://github.com/facebook/immutable-js) data structures (only List and Map though).\n\n# Usage\n\n```javascript\nmap2tree(\n  someMap,\n  (options = {\n    key: 'state', // the name you want for as the root node of the output tree\n    pushMethod: 'push', // use 'unshift' to change the order children nodes are added\n  }),\n);\n```\n\n# Input\n\n```javascript\nconst someMap = {\n  someReducer: {\n    todos: [\n      { title: 'map', someNestedObject: { foo: 'bar' } },\n      { title: 'to', someNestedArray: ['foo', 'bar'] },\n      { title: 'tree' },\n      { title: 'map2tree' },\n    ],\n    completedCount: 1,\n  },\n  otherReducer: {\n    foo: 0,\n    bar: { key: 'value' },\n  },\n};\n```\n\n# Output\n\n```javascript\n{\n  name: `${options.key}`,\n  children: [\n    {\n      name: 'someReducer',\n      children: [\n        {\n          name: 'todos',\n          children: [\n            {\n              name: 'todo[0]',\n              object: {\n                title: 'map',\n                someNestedObject: {foo: 'bar'}\n              }\n            },\n            {\n              name: 'todo[1]',\n              object: {\n                title: 'to',\n                someNestedArray: ['foo', 'bar']\n              }\n            },\n            // ...\n          ]\n        },\n        // ...\n      ]\n    },\n    {\n      name: 'otherReducer',\n      children: [\n        {\n          name: 'foo',\n          value: 0\n        },\n        {\n          name: 'bar',\n          object: {\n            key: 'value'\n          }\n        }\n      ]\n    }\n  ]\n}\n```\n"
  },
  {
    "path": "packages/map2tree/eslint.config.js",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTs from '../../eslint.ts.config.base.mjs';\nimport eslintTsJest from '../../eslint.ts.jest.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTs(import.meta.dirname),\n  ...eslintTsJest(import.meta.dirname),\n  {\n    ignores: ['jest.config.ts', 'lib'],\n  },\n];\n"
  },
  {
    "path": "packages/map2tree/jest.config.ts",
    "content": "import { createDefaultEsmPreset, type JestConfigWithTsJest } from 'ts-jest';\n\nconst presetConfig = createDefaultEsmPreset({\n  tsconfig: 'tsconfig.test.json',\n});\n\nconst jestConfig: JestConfigWithTsJest = {\n  ...presetConfig,\n  moduleNameMapper: {\n    '^(\\\\.{1,2}/.*)\\\\.js$': '$1',\n  },\n};\n\nexport default jestConfig;\n"
  },
  {
    "path": "packages/map2tree/package.json",
    "content": "{\n  \"name\": \"map2tree\",\n  \"version\": \"4.0.0\",\n  \"description\": \"Utility for mapping maps to trees\",\n  \"keywords\": [\n    \"map2tree\",\n    \"map-to-tree\",\n    \"mapToTree\",\n    \"map\",\n    \"tree\"\n  ],\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/map2tree\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"romseguy\",\n  \"files\": [\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": \"./lib/index.js\",\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"test\": \"node --experimental-vm-modules node_modules/jest/bin/jest.js\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run lint && pnpm run test\"\n  },\n  \"dependencies\": {\n    \"lodash-es\": \"^4.17.23\"\n  },\n  \"devDependencies\": {\n    \"@types/jest\": \"^30.0.0\",\n    \"@types/lodash-es\": \"^4.17.12\",\n    \"immutable\": \"^5.1.5\",\n    \"jest\": \"^30.3.0\",\n    \"rimraf\": \"^6.1.3\",\n    \"ts-jest\": \"^29.4.6\",\n    \"typescript\": \"~5.9.3\"\n  }\n}\n"
  },
  {
    "path": "packages/map2tree/src/index.ts",
    "content": "import { isArray, isPlainObject, mapValues } from 'lodash-es';\n\nexport interface Node {\n  name: string;\n  children?: this[];\n  object?: unknown;\n  value?: unknown;\n}\n\nfunction visit(\n  parent: Node,\n  visitFn: (parent: Node) => void,\n  childrenFn: (parent: Node) => Node[] | undefined | null,\n) {\n  if (!parent) return;\n\n  visitFn(parent);\n\n  const children = childrenFn(parent);\n  if (children) {\n    const count = children.length;\n    for (let i = 0; i < count; i++) {\n      visit(children[i], visitFn, childrenFn);\n    }\n  }\n}\n\nfunction getNode(tree: Node, key: string): Node | null {\n  let node = null;\n\n  visit(\n    tree,\n    (d) => {\n      if (d.name === key) {\n        node = d;\n      }\n    },\n    (d) => d.children,\n  );\n\n  return node;\n}\n\nexport function map2tree(\n  root: unknown,\n  options: { key?: string; pushMethod?: 'push' | 'unshift' } = {},\n  tree: Node = { name: options.key || 'state', children: [] },\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n): Node | {} {\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  if (!isPlainObject(root) && root && !(root as { toJS: () => {} }).toJS) {\n    return {};\n  }\n\n  const { key: rootNodeKey = 'state', pushMethod = 'push' } = options;\n  const currentNode = getNode(tree, rootNodeKey);\n\n  if (currentNode === null) {\n    return {};\n  }\n\n  mapValues(\n    // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n    root && (root as { toJS: () => {} }).toJS\n      ? // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n        (root as { toJS: () => {} }).toJS()\n      : // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n        (root as {}),\n    // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n    (maybeImmutable: { toJS?: () => {} }, key) => {\n      const value =\n        maybeImmutable && maybeImmutable.toJS\n          ? maybeImmutable.toJS()\n          : maybeImmutable;\n      const newNode: Node = { name: key };\n\n      if (isArray(value)) {\n        newNode.children = [];\n\n        for (let i = 0; i < value.length; i++) {\n          newNode.children[pushMethod]({\n            name: `${key}[${i}]`,\n            [isPlainObject(value[i]) ? 'object' : 'value']: value[i],\n          });\n        }\n      } else if (isPlainObject(value)) {\n        newNode.children = [];\n      } else {\n        newNode.value = value;\n      }\n\n      currentNode.children![pushMethod](newNode);\n\n      map2tree(value, { key, pushMethod }, tree);\n    },\n  );\n\n  return tree;\n}\n"
  },
  {
    "path": "packages/map2tree/test/map2tree.spec.ts",
    "content": "import { map2tree, Node } from '../src/index.js';\nimport * as immutable from 'immutable';\n\ntest('# rootNodeKey', () => {\n  const map = {};\n  const options = { key: 'foo' };\n\n  expect((map2tree(map, options) as Node).name).toBe('foo');\n});\n\ndescribe('# shallow map', () => {\n  test('## null', () => {\n    const map = {\n      a: null,\n    };\n\n    const expected = {\n      name: 'state',\n      children: [{ name: 'a', value: null }],\n    };\n\n    expect(map2tree(map)).toEqual(expected);\n    expect(map2tree(immutable.fromJS(map))).toEqual(expected);\n  });\n\n  test('## value', () => {\n    const map = {\n      a: 'foo',\n      b: 'bar',\n    };\n\n    const expected = {\n      name: 'state',\n      children: [\n        { name: 'a', value: 'foo' },\n        { name: 'b', value: 'bar' },\n      ],\n    };\n\n    expect(map2tree(map)).toEqual(expected);\n    expect(map2tree(immutable.fromJS(map))).toEqual(expected);\n  });\n\n  test('## object', () => {\n    const map = {\n      a: { aa: 'foo' },\n    };\n\n    const expected = {\n      name: 'state',\n      children: [{ name: 'a', children: [{ name: 'aa', value: 'foo' }] }],\n    };\n\n    expect(map2tree(map)).toEqual(expected);\n    expect(map2tree(immutable.fromJS(map))).toEqual(expected);\n  });\n\n  test('## immutable Map', () => {\n    const map = {\n      a: immutable.fromJS({ aa: 'foo', ab: 'bar' }),\n    };\n\n    const expected = {\n      name: 'state',\n      children: [\n        {\n          name: 'a',\n          children: [\n            { name: 'aa', value: 'foo' },\n            { name: 'ab', value: 'bar' },\n          ],\n        },\n      ],\n    };\n\n    expect(map2tree(map)).toEqual(expected);\n  });\n});\n\ndescribe('# deep map', () => {\n  test('## null', () => {\n    const map = {\n      a: { aa: null },\n    };\n\n    const expected = {\n      name: 'state',\n      children: [\n        {\n          name: 'a',\n          children: [\n            {\n              name: 'aa',\n              value: null,\n            },\n          ],\n        },\n      ],\n    };\n\n    expect(map2tree(map)).toEqual(expected);\n    expect(map2tree(immutable.fromJS(map))).toEqual(expected);\n  });\n\n  test('## object', () => {\n    const map = {\n      a: { aa: { aaa: 'foo' } },\n    };\n\n    const expected = {\n      name: 'state',\n      children: [\n        {\n          name: 'a',\n          children: [\n            {\n              name: 'aa',\n              children: [{ name: 'aaa', value: 'foo' }],\n            },\n          ],\n        },\n      ],\n    };\n\n    expect(map2tree(map)).toEqual(expected);\n    expect(map2tree(immutable.fromJS(map))).toEqual(expected);\n  });\n});\n\ndescribe('# array map', () => {\n  const map = {\n    a: [1, 2],\n  };\n\n  test('## push', () => {\n    const expected = {\n      name: 'state',\n      children: [\n        {\n          name: 'a',\n          children: [\n            { name: 'a[0]', value: 1 },\n            { name: 'a[1]', value: 2 },\n          ],\n        },\n      ],\n    };\n\n    expect(map2tree(map)).toEqual(expected);\n    expect(map2tree(immutable.fromJS(map))).toEqual(expected);\n  });\n\n  test('## unshift', () => {\n    const options = { pushMethod: 'unshift' as const };\n    const expected = {\n      name: 'state',\n      children: [\n        {\n          name: 'a',\n          children: [\n            { name: 'a[1]', value: 2 },\n            { name: 'a[0]', value: 1 },\n          ],\n        },\n      ],\n    };\n\n    expect(map2tree(map, options)).toEqual(expected);\n    expect(map2tree(immutable.fromJS(map), options)).toEqual(expected);\n  });\n\n  test('## null', () => {\n    const map = {\n      a: [null],\n    };\n\n    const expected = {\n      name: 'state',\n      children: [\n        {\n          name: 'a',\n          children: [{ name: 'a[0]', value: null }],\n        },\n      ],\n    };\n\n    expect(map2tree(map)).toEqual(expected);\n    expect(map2tree(immutable.fromJS(map))).toEqual(expected);\n  });\n});\n\ndescribe('# collection map', () => {\n  test('## value', () => {\n    const map = {\n      a: [{ aa: 1 }, { aa: 2 }],\n    };\n\n    const expected = {\n      name: 'state',\n      children: [\n        {\n          name: 'a',\n          children: [\n            { name: 'a[0]', object: { aa: 1 } },\n            { name: 'a[1]', object: { aa: 2 } },\n          ],\n        },\n      ],\n    };\n\n    expect(map2tree(map)).toEqual(expected);\n    expect(map2tree(immutable.fromJS(map))).toEqual(expected);\n  });\n\n  test('## object', () => {\n    const map = {\n      a: [{ aa: { aaa: 'foo' } }],\n    };\n\n    const expected = {\n      name: 'state',\n      children: [\n        {\n          name: 'a',\n          children: [{ name: 'a[0]', object: { aa: { aaa: 'foo' } } }],\n        },\n      ],\n    };\n\n    expect(map2tree(map)).toEqual(expected);\n    expect(map2tree(immutable.fromJS(map))).toEqual(expected);\n  });\n});\n"
  },
  {
    "path": "packages/map2tree/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/map2tree/tsconfig.test.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"jest\"]\n  },\n  \"include\": [\"src\", \"test\"]\n}\n"
  },
  {
    "path": "packages/react-base16-styling/CHANGELOG.md",
    "content": "# Change Log\n\n## 0.10.0\n\n### Minor Changes\n\n- bbb1a40: Convert React packages to ESM\n\n## 0.9.0\n\n- Adds ESM build (https://github.com/reduxjs/redux-devtools/pull/997).\n\n## [0.8.0](https://github.com/reduxjs/redux-devtools/compare/react-base16-styling@0.7.0...react-base16-styling@0.8.0) (2020-09-07)\n\n### Bug Fixes\n\n- **react-base16-styling:** fix Styling type ([#602](https://github.com/reduxjs/redux-devtools/issues/602)) ([e7304b5](https://github.com/reduxjs/redux-devtools/commit/e7304b5853a572b53429809ed8ac4b7a198c90f8))\n\n### Features\n\n- **redux-devtools-inspector:** convert to TypeScript ([#623](https://github.com/reduxjs/redux-devtools/issues/623)) ([c7b0c7a](https://github.com/reduxjs/redux-devtools/commit/c7b0c7aa6e09f46a36b382ae3ec8e38bd48aeb28))\n- **redux-devtools-serialize:** convert to TypeScript ([#621](https://github.com/reduxjs/redux-devtools/issues/621)) ([d586f19](https://github.com/reduxjs/redux-devtools/commit/d586f1955a3648883107f8c981ee17eeb4c013a3))\n\n## 0.7.0 (2020-08-14)\n\n- feat(react-base16-styling)!: add invertTheme helper (#565) ([92d16e4](https://github.com/reduxjs/redux-devtools/commit/92d16e4f56fbeaf06966afd9024ed4b58ba98ecb)), closes [#565](https://github.com/reduxjs/redux-devtools/issues/565)\n\n### BREAKING CHANGES\n\n- rename previous invertTheme to invertBase16Theme\n"
  },
  {
    "path": "packages/react-base16-styling/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 Alexander Kuznetsov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/react-base16-styling/README.md",
    "content": "# react-base16-styling [![Latest Stable Version](https://img.shields.io/npm/v/react-base16-styling.svg)](https://www.npmjs.com/package/react-base16-styling)\n\nReact styling with base16 color scheme support\n\nInspired by [react-themeable](https://github.com/markdalgleish/react-themeable), this utility provides flexible theming for your component with [base16](https://github.com/chriskempson/base16) theme support.\n\n## Install\n\n```\nyarn add react-base16-styling\n```\n\n## Usage\n\n```jsx\nimport { createStyling } from 'react-base16-styling';\nimport base16Themes from './base16Themes';\n\nfunction getStylingFromBase16(base16Theme) {\n  return {\n    myComponent: {\n      backgroundColor: base16Theme.base00,\n    },\n\n    myComponentToggleColor({ style, className }, clickCount) {\n      return {\n        style: {\n          ...style,\n          backgroundColor: clickCount % 2 ? 'red' : 'blue',\n        },\n      };\n    },\n  };\n}\n\nconst createStylingFromTheme = createStyling(getStylingFromBase16, {\n  defaultBase16: base16Themes.solarized,\n  base16Themes,\n});\n\nclass MyComponent extends Component {\n  state = { clickCount: 0 };\n  render() {\n    const { theme } = this.props;\n    const { clickCount } = this.state;\n\n    const styling = createStylingFromTheme(theme);\n\n    return (\n      <div {...styling('myComponent')}>\n        <a onClick={() => this.setState({ clickCount: clickCount + 1 })}>\n          Click Me\n        </a>\n        <div {...styling('myComponentToggleColor', clickCount)}>\n          {clickCount}\n        </div>\n      </div>\n    );\n  }\n}\n```\n\n## `createStyling`\n\n```js\nfunction(getStylingFromBase16, defaultStylingOptions, themeOrStyling)\n```\n\n| Argument                | Signature                         | Description                                                                                                                                                        |\n| ----------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `getStylingFromBase16`  | `function(base16Theme)`           | creates object with default stylings for your component, using provided base16 theme.                                                                              |\n| `defaultStylingOptions` | `{ defaultBase16, base16Themes }` | optional parameters, allow to set default `base16` theme and additional `base16` themes for component.                                                             |\n| `themeOrStyling`        | `string` or `object`              | `base16` theme name, `base16` theme object or styling object. Theme name can have a modifier: `\"themeName:inverted\"` to invert theme colors (see [[#invertTheme]]) |\n\nStyling object values could be: - objects (treated as style definitions) - strings (class names) - functions (they may be provided with additional parameters and should return object { style, className })\n\n## `getBase16Theme`\n\n```js\nfunction(themeOrStyling, base16Themes)\n```\n\nHelper method that returns `base16` theme object if `themeOrStyling` is `base16` theme name or theme object.\n\n## `invertBase16Theme`\n\n```js\nfunction(base16Theme)\n```\n\nHelper method that inverts `base16` theme colors, creating light theme out of dark one or vice versa.\n\n## `invertTheme`\n\n```js\nfunction(theme)\n```\n\nHelper method that inverts a theme or styling object to be passed into the `themeOrStyling` parameter of [createStyling](#createstyling).\n"
  },
  {
    "path": "packages/react-base16-styling/eslint.config.js",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTs from '../../eslint.ts.config.base.mjs';\nimport eslintTsJest from '../../eslint.ts.jest.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTs(import.meta.dirname),\n  ...eslintTsJest(import.meta.dirname),\n  {\n    ignores: ['jest.config.ts', 'lib'],\n  },\n];\n"
  },
  {
    "path": "packages/react-base16-styling/jest.config.ts",
    "content": "import { createDefaultEsmPreset, type JestConfigWithTsJest } from 'ts-jest';\n\nconst presetConfig = createDefaultEsmPreset({\n  tsconfig: 'tsconfig.test.json',\n});\n\nconst jestConfig: JestConfigWithTsJest = {\n  ...presetConfig,\n  moduleNameMapper: {\n    '^(\\\\.{1,2}/.*)\\\\.js$': '$1',\n  },\n};\n\nexport default jestConfig;\n"
  },
  {
    "path": "packages/react-base16-styling/package.json",
    "content": "{\n  \"name\": \"react-base16-styling\",\n  \"version\": \"0.10.0\",\n  \"description\": \"React styling with base16 color scheme support\",\n  \"keywords\": [\n    \"react\",\n    \"theme\",\n    \"base16\",\n    \"styling\"\n  ],\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/react-base16-styling\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Alexander <alexkuz@gmail.com> (http://kuzya.org/)\",\n  \"files\": [\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": \"./lib/index.js\",\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"test\": \"node --experimental-vm-modules node_modules/jest/bin/jest.js\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run lint && pnpm run test\"\n  },\n  \"dependencies\": {\n    \"@types/lodash\": \"^4.17.24\",\n    \"color\": \"^5.0.3\",\n    \"csstype\": \"^3.2.3\",\n    \"lodash-es\": \"^4.17.23\"\n  },\n  \"devDependencies\": {\n    \"@types/color\": \"^4.2.0\",\n    \"@types/jest\": \"^30.0.0\",\n    \"@types/lodash-es\": \"^4.17.12\",\n    \"jest\": \"^30.3.0\",\n    \"jest-environment-jsdom\": \"^30.3.0\",\n    \"rimraf\": \"^6.1.3\",\n    \"ts-jest\": \"^29.4.6\",\n    \"typescript\": \"~5.9.3\"\n  }\n}\n"
  },
  {
    "path": "packages/react-base16-styling/src/colorConverters.ts",
    "content": "export type Color = [number, number, number];\n\nexport function yuv2rgb(yuv: Color): Color {\n  const y = yuv[0],\n    u = yuv[1],\n    v = yuv[2];\n  let r, g, b;\n\n  r = y * 1 + u * 0 + v * 1.13983;\n  g = y * 1 + u * -0.39465 + v * -0.5806;\n  b = y * 1 + u * 2.02311 + v * 0;\n\n  r = Math.min(Math.max(0, r), 1);\n  g = Math.min(Math.max(0, g), 1);\n  b = Math.min(Math.max(0, b), 1);\n\n  return [r * 255, g * 255, b * 255];\n}\n\nexport function rgb2yuv(rgb: Color): Color {\n  const r = rgb[0] / 255,\n    g = rgb[1] / 255,\n    b = rgb[2] / 255;\n\n  const y = r * 0.299 + g * 0.587 + b * 0.114;\n  const u = r * -0.14713 + g * -0.28886 + b * 0.436;\n  const v = r * 0.615 + g * -0.51499 + b * -0.10001;\n\n  return [y, u, v];\n}\n"
  },
  {
    "path": "packages/react-base16-styling/src/index.ts",
    "content": "import Color from 'color';\nimport * as CSS from 'csstype';\nimport { curry } from 'lodash-es';\nimport type { CurriedFunction3 } from 'lodash';\nimport { Color as ColorTuple, yuv2rgb, rgb2yuv } from './colorConverters.js';\nimport {\n  Styling,\n  StylingConfig,\n  StylingFunction,\n  StylingValue,\n  StylingValueFunction,\n  Theme,\n} from './types.js';\nimport { base16Themes as base16 } from './themes/index.js';\nimport type { Base16Theme } from './themes/index.js';\n\nconst DEFAULT_BASE16 = base16.default;\n\nconst BASE16_KEYS = Object.keys(DEFAULT_BASE16);\n\n// we need a correcting factor, so that a dark, but not black background color\n// converts to bright enough inversed color\nconst flip = (x: number) => (x < 0.25 ? 1 : x < 0.5 ? 0.9 - x : 1.1 - x);\n\nconst invertColor = (hexString: string) => {\n  const color = Color(hexString);\n  const [y, u, v] = rgb2yuv(color.array() as ColorTuple);\n  const flippedYuv: ColorTuple = [flip(y), u, v];\n  const rgb = yuv2rgb(flippedYuv);\n  return Color.rgb(rgb).hex();\n};\n\nconst merger = (styling: Partial<Styling>) => {\n  return (prevStyling: Partial<Styling>) => ({\n    className: [prevStyling.className, styling.className]\n      .filter(Boolean)\n      .join(' '),\n    style: { ...(prevStyling.style || {}), ...(styling.style || {}) },\n  });\n};\n\nconst mergeStyling = (\n  customStyling: StylingValue,\n  defaultStyling: StylingValue,\n): StylingValue | undefined => {\n  if (customStyling === undefined) {\n    return defaultStyling;\n  }\n  if (defaultStyling === undefined) {\n    return customStyling;\n  }\n\n  const customType = typeof customStyling;\n  const defaultType = typeof defaultStyling;\n\n  switch (customType) {\n    case 'string':\n      switch (defaultType) {\n        case 'string':\n          return [defaultStyling, customStyling].filter(Boolean).join(' ');\n        case 'object':\n          return merger({\n            className: customStyling as string,\n            style: defaultStyling as CSS.Properties<string | number>,\n          });\n        case 'function':\n          return (styling: Styling, ...args: unknown[]) =>\n            merger({\n              className: customStyling as string,\n            })((defaultStyling as StylingValueFunction)(styling, ...args));\n      }\n      break;\n    case 'object':\n      switch (defaultType) {\n        case 'string':\n          return merger({\n            className: defaultStyling as string,\n            style: customStyling as CSS.Properties<string | number>,\n          });\n        case 'object':\n          return {\n            ...(defaultStyling as CSS.Properties<string | number>),\n            ...(customStyling as CSS.Properties<string | number>),\n          };\n        case 'function':\n          return (styling: Styling, ...args: unknown[]) =>\n            merger({\n              style: customStyling as CSS.Properties<string | number>,\n            })((defaultStyling as StylingValueFunction)(styling, ...args));\n      }\n      break;\n    case 'function':\n      switch (defaultType) {\n        case 'string':\n          return (styling, ...args) =>\n            (customStyling as StylingValueFunction)(\n              merger(styling)({\n                className: defaultStyling as string,\n              }),\n              ...args,\n            );\n        case 'object':\n          return (styling, ...args) =>\n            (customStyling as StylingValueFunction)(\n              merger(styling)({\n                style: defaultStyling as CSS.Properties<string | number>,\n              }),\n              ...args,\n            );\n        case 'function':\n          return (styling, ...args) =>\n            (customStyling as StylingValueFunction)(\n              (defaultStyling as StylingValueFunction)(\n                styling,\n                ...args,\n              ) as Styling,\n              ...args,\n            );\n      }\n  }\n};\n\nconst mergeStylings = (\n  customStylings: StylingConfig,\n  defaultStylings: StylingConfig,\n): StylingConfig => {\n  const keys = Object.keys(defaultStylings);\n  for (const key in customStylings) {\n    if (!keys.includes(key)) keys.push(key);\n  }\n\n  return keys.reduce(\n    (mergedStyling, key) => (\n      (mergedStyling[key as keyof StylingConfig] = mergeStyling(\n        customStylings[key] as StylingValue,\n        defaultStylings[key] as StylingValue,\n      ) as StylingValue),\n      mergedStyling\n    ),\n    {} as StylingConfig,\n  );\n};\n\nconst getStylingByKeys = (\n  mergedStyling: StylingConfig,\n  keys: (string | false | undefined) | (string | false | undefined)[],\n  ...args: unknown[]\n): Styling => {\n  if (keys === null) {\n    return mergedStyling as unknown as Styling;\n  }\n\n  if (!Array.isArray(keys)) {\n    keys = [keys];\n  }\n\n  const styles = keys\n    .map((key) => mergedStyling[key as string])\n    .filter(Boolean);\n\n  const props = styles.reduce<Styling>(\n    (obj, s) => {\n      if (typeof s === 'string') {\n        obj.className = [obj.className, s].filter(Boolean).join(' ');\n      } else if (typeof s === 'object') {\n        obj.style = { ...obj.style, ...s };\n      } else if (typeof s === 'function') {\n        obj = { ...obj, ...s(obj, ...args) };\n      }\n\n      return obj;\n    },\n    { className: '', style: {} },\n  );\n\n  if (!props.className) {\n    delete props.className;\n  }\n\n  if (Object.keys(props.style!).length === 0) {\n    delete props.style;\n  }\n\n  return props;\n};\n\nexport const invertBase16Theme = (base16Theme: Base16Theme): Base16Theme =>\n  Object.keys(base16Theme).reduce(\n    (t, key) => (\n      (t[key as keyof Base16Theme] = /^base/.test(key)\n        ? invertColor(base16Theme[key as keyof Base16Theme])\n        : key === 'scheme'\n          ? base16Theme[key] + ':inverted'\n          : base16Theme[key as keyof Base16Theme]),\n      t\n    ),\n    {} as Base16Theme,\n  );\n\ninterface Options {\n  defaultBase16?: Base16Theme;\n  base16Themes?: { [themeName: string]: Base16Theme };\n}\n\nexport const createStyling: CurriedFunction3<\n  (base16Theme: Base16Theme) => StylingConfig,\n  Options | undefined,\n  Theme | undefined,\n  StylingFunction\n> = curry<\n  (base16Theme: Base16Theme) => StylingConfig,\n  Options | undefined,\n  Theme | undefined,\n  StylingFunction\n>(\n  (\n    getStylingFromBase16: (base16Theme: Base16Theme) => StylingConfig,\n    options: Options = {},\n    themeOrStyling: Theme = {},\n    ...args\n  ): StylingFunction => {\n    const { defaultBase16 = DEFAULT_BASE16, base16Themes = null } = options;\n\n    const base16Theme = getBase16Theme(themeOrStyling, base16Themes);\n    if (base16Theme) {\n      themeOrStyling = {\n        ...base16Theme,\n        ...(themeOrStyling as Base16Theme | StylingConfig),\n      };\n    }\n\n    const theme = BASE16_KEYS.reduce(\n      (t, key) => (\n        (t[key as keyof Base16Theme] =\n          (themeOrStyling as Base16Theme)[key as keyof Base16Theme] ||\n          defaultBase16[key as keyof Base16Theme]),\n        t\n      ),\n      {} as Base16Theme,\n    );\n\n    const customStyling = Object.keys(themeOrStyling).reduce(\n      (s, key) =>\n        !BASE16_KEYS.includes(key)\n          ? ((s[key] = (themeOrStyling as StylingConfig)[key]), s)\n          : s,\n      {} as StylingConfig,\n    );\n\n    const defaultStyling = getStylingFromBase16(theme);\n\n    const mergedStyling = mergeStylings(customStyling, defaultStyling);\n\n    return curry(getStylingByKeys, 2)(mergedStyling, ...args);\n  },\n  3,\n);\n\nconst isStylingConfig = (theme: Theme): theme is StylingConfig =>\n  !!(theme as StylingConfig).extend;\n\nexport const getBase16Theme = (\n  theme: Theme,\n  base16Themes?: { [themeName: string]: Base16Theme } | null,\n): Base16Theme | undefined => {\n  if (theme && isStylingConfig(theme) && theme.extend) {\n    theme = theme.extend as string | Base16Theme;\n  }\n\n  if (typeof theme === 'string') {\n    const [themeName, modifier] = theme.split(':');\n    if (base16Themes) {\n      theme = base16Themes[themeName];\n    } else {\n      theme = base16[themeName as keyof typeof base16] as Base16Theme;\n    }\n    if (modifier === 'inverted') {\n      theme = invertBase16Theme(theme);\n    }\n  }\n\n  return theme && Object.prototype.hasOwnProperty.call(theme, 'base00')\n    ? (theme as Base16Theme)\n    : undefined;\n};\n\nexport const invertTheme = (theme: Theme | undefined): Theme | undefined => {\n  if (typeof theme === 'string') {\n    return `${theme}:inverted`;\n  }\n\n  if (theme && isStylingConfig(theme) && theme.extend) {\n    if (typeof theme.extend === 'string') {\n      return { ...theme, extend: `${theme.extend}:inverted` };\n    }\n\n    return {\n      ...theme,\n      extend: invertBase16Theme(theme.extend as Base16Theme),\n    };\n  }\n\n  if (theme) {\n    return invertBase16Theme(theme as Base16Theme);\n  }\n\n  return theme;\n};\n\nexport type { Base16Theme };\nexport { base16 as base16Themes };\nexport * from './types.js';\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/apathy.ts",
    "content": "export default {\n  scheme: 'apathy',\n  author: 'jannik siebert (https://github.com/janniks)',\n  base00: '#031A16',\n  base01: '#0B342D',\n  base02: '#184E45',\n  base03: '#2B685E',\n  base04: '#5F9C92',\n  base05: '#81B5AC',\n  base06: '#A7CEC8',\n  base07: '#D2E7E4',\n  base08: '#3E9688',\n  base09: '#3E7996',\n  base0A: '#3E4C96',\n  base0B: '#883E96',\n  base0C: '#963E4C',\n  base0D: '#96883E',\n  base0E: '#4C963E',\n  base0F: '#3E965B',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/ashes.ts",
    "content": "export default {\n  scheme: 'ashes',\n  author: 'jannik siebert (https://github.com/janniks)',\n  base00: '#1C2023',\n  base01: '#393F45',\n  base02: '#565E65',\n  base03: '#747C84',\n  base04: '#ADB3BA',\n  base05: '#C7CCD1',\n  base06: '#DFE2E5',\n  base07: '#F3F4F5',\n  base08: '#C7AE95',\n  base09: '#C7C795',\n  base0A: '#AEC795',\n  base0B: '#95C7AE',\n  base0C: '#95AEC7',\n  base0D: '#AE95C7',\n  base0E: '#C795AE',\n  base0F: '#C79595',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/atelier-dune.ts",
    "content": "export default {\n  scheme: 'atelier dune',\n  author:\n    'bram de haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune)',\n  base00: '#20201d',\n  base01: '#292824',\n  base02: '#6e6b5e',\n  base03: '#7d7a68',\n  base04: '#999580',\n  base05: '#a6a28c',\n  base06: '#e8e4cf',\n  base07: '#fefbec',\n  base08: '#d73737',\n  base09: '#b65611',\n  base0A: '#cfb017',\n  base0B: '#60ac39',\n  base0C: '#1fad83',\n  base0D: '#6684e1',\n  base0E: '#b854d4',\n  base0F: '#d43552',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/atelier-forest.ts",
    "content": "export default {\n  scheme: 'atelier forest',\n  author:\n    'bram de haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/forest)',\n  base00: '#1b1918',\n  base01: '#2c2421',\n  base02: '#68615e',\n  base03: '#766e6b',\n  base04: '#9c9491',\n  base05: '#a8a19f',\n  base06: '#e6e2e0',\n  base07: '#f1efee',\n  base08: '#f22c40',\n  base09: '#df5320',\n  base0A: '#d5911a',\n  base0B: '#5ab738',\n  base0C: '#00ad9c',\n  base0D: '#407ee7',\n  base0E: '#6666ea',\n  base0F: '#c33ff3',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/atelier-heath.ts",
    "content": "export default {\n  scheme: 'atelier heath',\n  author:\n    'bram de haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/heath)',\n  base00: '#1b181b',\n  base01: '#292329',\n  base02: '#695d69',\n  base03: '#776977',\n  base04: '#9e8f9e',\n  base05: '#ab9bab',\n  base06: '#d8cad8',\n  base07: '#f7f3f7',\n  base08: '#ca402b',\n  base09: '#a65926',\n  base0A: '#bb8a35',\n  base0B: '#379a37',\n  base0C: '#159393',\n  base0D: '#516aec',\n  base0E: '#7b59c0',\n  base0F: '#cc33cc',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/atelier-lakeside.ts",
    "content": "export default {\n  scheme: 'atelier lakeside',\n  author:\n    'bram de haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/lakeside/)',\n  base00: '#161b1d',\n  base01: '#1f292e',\n  base02: '#516d7b',\n  base03: '#5a7b8c',\n  base04: '#7195a8',\n  base05: '#7ea2b4',\n  base06: '#c1e4f6',\n  base07: '#ebf8ff',\n  base08: '#d22d72',\n  base09: '#935c25',\n  base0A: '#8a8a0f',\n  base0B: '#568c3b',\n  base0C: '#2d8f6f',\n  base0D: '#257fad',\n  base0E: '#5d5db1',\n  base0F: '#b72dd2',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/atelier-seaside.ts",
    "content": "export default {\n  scheme: 'atelier seaside',\n  author:\n    'bram de haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/seaside/)',\n  base00: '#131513',\n  base01: '#242924',\n  base02: '#5e6e5e',\n  base03: '#687d68',\n  base04: '#809980',\n  base05: '#8ca68c',\n  base06: '#cfe8cf',\n  base07: '#f0fff0',\n  base08: '#e6193c',\n  base09: '#87711d',\n  base0A: '#c3c322',\n  base0B: '#29a329',\n  base0C: '#1999b3',\n  base0D: '#3d62f5',\n  base0E: '#ad2bee',\n  base0F: '#e619c3',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/bespin.ts",
    "content": "export default {\n  scheme: 'bespin',\n  author: 'jan t. sott',\n  base00: '#28211c',\n  base01: '#36312e',\n  base02: '#5e5d5c',\n  base03: '#666666',\n  base04: '#797977',\n  base05: '#8a8986',\n  base06: '#9d9b97',\n  base07: '#baae9e',\n  base08: '#cf6a4c',\n  base09: '#cf7d34',\n  base0A: '#f9ee98',\n  base0B: '#54be0d',\n  base0C: '#afc4db',\n  base0D: '#5ea6ea',\n  base0E: '#9b859d',\n  base0F: '#937121',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/brewer.ts",
    "content": "export default {\n  scheme: 'brewer',\n  author: 'timothée poisot (http://github.com/tpoisot)',\n  base00: '#0c0d0e',\n  base01: '#2e2f30',\n  base02: '#515253',\n  base03: '#737475',\n  base04: '#959697',\n  base05: '#b7b8b9',\n  base06: '#dadbdc',\n  base07: '#fcfdfe',\n  base08: '#e31a1c',\n  base09: '#e6550d',\n  base0A: '#dca060',\n  base0B: '#31a354',\n  base0C: '#80b1d3',\n  base0D: '#3182bd',\n  base0E: '#756bb1',\n  base0F: '#b15928',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/bright.ts",
    "content": "export default {\n  scheme: 'bright',\n  author: 'chris kempson (http://chriskempson.com)',\n  base00: '#000000',\n  base01: '#303030',\n  base02: '#505050',\n  base03: '#b0b0b0',\n  base04: '#d0d0d0',\n  base05: '#e0e0e0',\n  base06: '#f5f5f5',\n  base07: '#ffffff',\n  base08: '#fb0120',\n  base09: '#fc6d24',\n  base0A: '#fda331',\n  base0B: '#a1c659',\n  base0C: '#76c7b7',\n  base0D: '#6fb3d2',\n  base0E: '#d381c3',\n  base0F: '#be643c',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/chalk.ts",
    "content": "export default {\n  scheme: 'chalk',\n  author: 'chris kempson (http://chriskempson.com)',\n  base00: '#151515',\n  base01: '#202020',\n  base02: '#303030',\n  base03: '#505050',\n  base04: '#b0b0b0',\n  base05: '#d0d0d0',\n  base06: '#e0e0e0',\n  base07: '#f5f5f5',\n  base08: '#fb9fb1',\n  base09: '#eda987',\n  base0A: '#ddb26f',\n  base0B: '#acc267',\n  base0C: '#12cfc0',\n  base0D: '#6fc2ef',\n  base0E: '#e1a3ee',\n  base0F: '#deaf8f',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/codeschool.ts",
    "content": "export default {\n  scheme: 'codeschool',\n  author: 'brettof86',\n  base00: '#232c31',\n  base01: '#1c3657',\n  base02: '#2a343a',\n  base03: '#3f4944',\n  base04: '#84898c',\n  base05: '#9ea7a6',\n  base06: '#a7cfa3',\n  base07: '#b5d8f6',\n  base08: '#2a5491',\n  base09: '#43820d',\n  base0A: '#a03b1e',\n  base0B: '#237986',\n  base0C: '#b02f30',\n  base0D: '#484d79',\n  base0E: '#c59820',\n  base0F: '#c98344',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/colors.ts",
    "content": "export default {\n  scheme: 'colors',\n  author: 'mrmrs (http://clrs.cc)',\n  base00: '#111111',\n  base01: '#333333',\n  base02: '#555555',\n  base03: '#777777',\n  base04: '#999999',\n  base05: '#bbbbbb',\n  base06: '#dddddd',\n  base07: '#ffffff',\n  base08: '#ff4136',\n  base09: '#ff851b',\n  base0A: '#ffdc00',\n  base0B: '#2ecc40',\n  base0C: '#7fdbff',\n  base0D: '#0074d9',\n  base0E: '#b10dc9',\n  base0F: '#85144b',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/default.ts",
    "content": "export default {\n  scheme: 'default',\n  author: 'chris kempson (http://chriskempson.com)',\n  base00: '#181818',\n  base01: '#282828',\n  base02: '#383838',\n  base03: '#585858',\n  base04: '#b8b8b8',\n  base05: '#d8d8d8',\n  base06: '#e8e8e8',\n  base07: '#f8f8f8',\n  base08: '#ab4642',\n  base09: '#dc9656',\n  base0A: '#f7ca88',\n  base0B: '#a1b56c',\n  base0C: '#86c1b9',\n  base0D: '#7cafc2',\n  base0E: '#ba8baf',\n  base0F: '#a16946',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/eighties.ts",
    "content": "export default {\n  scheme: 'eighties',\n  author: 'chris kempson (http://chriskempson.com)',\n  base00: '#2d2d2d',\n  base01: '#393939',\n  base02: '#515151',\n  base03: '#747369',\n  base04: '#a09f93',\n  base05: '#d3d0c8',\n  base06: '#e8e6df',\n  base07: '#f2f0ec',\n  base08: '#f2777a',\n  base09: '#f99157',\n  base0A: '#ffcc66',\n  base0B: '#99cc99',\n  base0C: '#66cccc',\n  base0D: '#6699cc',\n  base0E: '#cc99cc',\n  base0F: '#d27b53',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/embers.ts",
    "content": "export default {\n  scheme: 'embers',\n  author: 'jannik siebert (https://github.com/janniks)',\n  base00: '#16130F',\n  base01: '#2C2620',\n  base02: '#433B32',\n  base03: '#5A5047',\n  base04: '#8A8075',\n  base05: '#A39A90',\n  base06: '#BEB6AE',\n  base07: '#DBD6D1',\n  base08: '#826D57',\n  base09: '#828257',\n  base0A: '#6D8257',\n  base0B: '#57826D',\n  base0C: '#576D82',\n  base0D: '#6D5782',\n  base0E: '#82576D',\n  base0F: '#825757',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/flat.ts",
    "content": "export default {\n  scheme: 'flat',\n  author: 'chris kempson (http://chriskempson.com)',\n  base00: '#2C3E50',\n  base01: '#34495E',\n  base02: '#7F8C8D',\n  base03: '#95A5A6',\n  base04: '#BDC3C7',\n  base05: '#e0e0e0',\n  base06: '#f5f5f5',\n  base07: '#ECF0F1',\n  base08: '#E74C3C',\n  base09: '#E67E22',\n  base0A: '#F1C40F',\n  base0B: '#2ECC71',\n  base0C: '#1ABC9C',\n  base0D: '#3498DB',\n  base0E: '#9B59B6',\n  base0F: '#be643c',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/google.ts",
    "content": "export default {\n  scheme: 'google',\n  author: 'seth wright (http://sethawright.com)',\n  base00: '#1d1f21',\n  base01: '#282a2e',\n  base02: '#373b41',\n  base03: '#969896',\n  base04: '#b4b7b4',\n  base05: '#c5c8c6',\n  base06: '#e0e0e0',\n  base07: '#ffffff',\n  base08: '#CC342B',\n  base09: '#F96A38',\n  base0A: '#FBA922',\n  base0B: '#198844',\n  base0C: '#3971ED',\n  base0D: '#3971ED',\n  base0E: '#A36AC7',\n  base0F: '#3971ED',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/grayscale.ts",
    "content": "export default {\n  scheme: 'grayscale',\n  author: 'alexandre gavioli (https://github.com/alexx2/)',\n  base00: '#101010',\n  base01: '#252525',\n  base02: '#464646',\n  base03: '#525252',\n  base04: '#ababab',\n  base05: '#b9b9b9',\n  base06: '#e3e3e3',\n  base07: '#f7f7f7',\n  base08: '#7c7c7c',\n  base09: '#999999',\n  base0A: '#a0a0a0',\n  base0B: '#8e8e8e',\n  base0C: '#868686',\n  base0D: '#686868',\n  base0E: '#747474',\n  base0F: '#5e5e5e',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/greenscreen.ts",
    "content": "export default {\n  scheme: 'green screen',\n  author: 'chris kempson (http://chriskempson.com)',\n  base00: '#001100',\n  base01: '#003300',\n  base02: '#005500',\n  base03: '#007700',\n  base04: '#009900',\n  base05: '#00bb00',\n  base06: '#00dd00',\n  base07: '#00ff00',\n  base08: '#007700',\n  base09: '#009900',\n  base0A: '#007700',\n  base0B: '#00bb00',\n  base0C: '#005500',\n  base0D: '#009900',\n  base0E: '#00bb00',\n  base0F: '#005500',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/harmonic.ts",
    "content": "export default {\n  scheme: 'harmonic16',\n  author: 'jannik siebert (https://github.com/janniks)',\n  base00: '#0b1c2c',\n  base01: '#223b54',\n  base02: '#405c79',\n  base03: '#627e99',\n  base04: '#aabcce',\n  base05: '#cbd6e2',\n  base06: '#e5ebf1',\n  base07: '#f7f9fb',\n  base08: '#bf8b56',\n  base09: '#bfbf56',\n  base0A: '#8bbf56',\n  base0B: '#56bf8b',\n  base0C: '#568bbf',\n  base0D: '#8b56bf',\n  base0E: '#bf568b',\n  base0F: '#bf5656',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/hopscotch.ts",
    "content": "export default {\n  scheme: 'hopscotch',\n  author: 'jan t. sott',\n  base00: '#322931',\n  base01: '#433b42',\n  base02: '#5c545b',\n  base03: '#797379',\n  base04: '#989498',\n  base05: '#b9b5b8',\n  base06: '#d5d3d5',\n  base07: '#ffffff',\n  base08: '#dd464c',\n  base09: '#fd8b19',\n  base0A: '#fdcc59',\n  base0B: '#8fc13e',\n  base0C: '#149b93',\n  base0D: '#1290bf',\n  base0E: '#c85e7c',\n  base0F: '#b33508',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/index.ts",
    "content": "import { default as threezerotwofour } from './threezerotwofour.js';\nimport { default as apathy } from './apathy.js';\nimport { default as ashes } from './ashes.js';\nimport { default as atelierDune } from './atelier-dune.js';\nimport { default as atelierForest } from './atelier-forest.js';\nimport { default as atelierHeath } from './atelier-heath.js';\nimport { default as atelierLakeside } from './atelier-lakeside.js';\nimport { default as atelierSeaside } from './atelier-seaside.js';\nimport { default as bespin } from './bespin.js';\nimport { default as brewer } from './brewer.js';\nimport { default as bright } from './bright.js';\nimport { default as chalk } from './chalk.js';\nimport { default as codeschool } from './codeschool.js';\nimport { default as colors } from './colors.js';\nimport { default as defaultTheme } from './default.js';\nimport { default as eighties } from './eighties.js';\nimport { default as embers } from './embers.js';\nimport { default as flat } from './flat.js';\nimport { default as google } from './google.js';\nimport { default as grayscale } from './grayscale.js';\nimport { default as greenscreen } from './greenscreen.js';\nimport { default as harmonic } from './harmonic.js';\nimport { default as hopscotch } from './hopscotch.js';\nimport { default as isotope } from './isotope.js';\nimport { default as marrakesh } from './marrakesh.js';\nimport { default as mocha } from './mocha.js';\nimport { default as monokai } from './monokai.js';\nimport { default as nicinabox } from './nicinabox.js';\nimport { default as ocean } from './ocean.js';\nimport { default as paraiso } from './paraiso.js';\nimport { default as pop } from './pop.js';\nimport { default as railscasts } from './railscasts.js';\nimport { default as shapeshifter } from './shapeshifter.js';\nimport { default as solarized } from './solarized.js';\nimport { default as summerfruit } from './summerfruit.js';\nimport { default as tomorrow } from './tomorrow.js';\nimport { default as tube } from './tube.js';\nimport { default as twilight } from './twilight.js';\n\nexport interface Base16Theme {\n  scheme: string;\n  author: string;\n  base00: string;\n  base01: string;\n  base02: string;\n  base03: string;\n  base04: string;\n  base05: string;\n  base06: string;\n  base07: string;\n  base08: string;\n  base09: string;\n  base0A: string;\n  base0B: string;\n  base0C: string;\n  base0D: string;\n  base0E: string;\n  base0F: string;\n}\n\nexport const base16Themes = {\n  threezerotwofour,\n  apathy,\n  ashes,\n  atelierDune,\n  atelierForest,\n  atelierHeath,\n  atelierLakeside,\n  atelierSeaside,\n  bespin,\n  brewer,\n  bright,\n  chalk,\n  codeschool,\n  colors,\n  default: defaultTheme,\n  eighties,\n  embers,\n  flat,\n  google,\n  grayscale,\n  greenscreen,\n  harmonic,\n  hopscotch,\n  isotope,\n  marrakesh,\n  mocha,\n  monokai,\n  nicinabox,\n  ocean,\n  paraiso,\n  pop,\n  railscasts,\n  shapeshifter,\n  solarized,\n  summerfruit,\n  tomorrow,\n  tube,\n  twilight,\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/isotope.ts",
    "content": "export default {\n  scheme: 'isotope',\n  author: 'jan t. sott',\n  base00: '#000000',\n  base01: '#404040',\n  base02: '#606060',\n  base03: '#808080',\n  base04: '#c0c0c0',\n  base05: '#d0d0d0',\n  base06: '#e0e0e0',\n  base07: '#ffffff',\n  base08: '#ff0000',\n  base09: '#ff9900',\n  base0A: '#ff0099',\n  base0B: '#33ff00',\n  base0C: '#00ffff',\n  base0D: '#0066ff',\n  base0E: '#cc00ff',\n  base0F: '#3300ff',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/marrakesh.ts",
    "content": "export default {\n  scheme: 'marrakesh',\n  author: 'alexandre gavioli (http://github.com/alexx2/)',\n  base00: '#201602',\n  base01: '#302e00',\n  base02: '#5f5b17',\n  base03: '#6c6823',\n  base04: '#86813b',\n  base05: '#948e48',\n  base06: '#ccc37a',\n  base07: '#faf0a5',\n  base08: '#c35359',\n  base09: '#b36144',\n  base0A: '#a88339',\n  base0B: '#18974e',\n  base0C: '#75a738',\n  base0D: '#477ca1',\n  base0E: '#8868b3',\n  base0F: '#b3588e',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/mocha.ts",
    "content": "export default {\n  scheme: 'mocha',\n  author: 'chris kempson (http://chriskempson.com)',\n  base00: '#3B3228',\n  base01: '#534636',\n  base02: '#645240',\n  base03: '#7e705a',\n  base04: '#b8afad',\n  base05: '#d0c8c6',\n  base06: '#e9e1dd',\n  base07: '#f5eeeb',\n  base08: '#cb6077',\n  base09: '#d28b71',\n  base0A: '#f4bc87',\n  base0B: '#beb55b',\n  base0C: '#7bbda4',\n  base0D: '#8ab3b5',\n  base0E: '#a89bb9',\n  base0F: '#bb9584',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/monokai.ts",
    "content": "export default {\n  scheme: 'monokai',\n  author: 'wimer hazenberg (http://www.monokai.nl)',\n  base00: '#272822',\n  base01: '#383830',\n  base02: '#49483e',\n  base03: '#75715e',\n  base04: '#a59f85',\n  base05: '#f8f8f2',\n  base06: '#f5f4f1',\n  base07: '#f9f8f5',\n  base08: '#f92672',\n  base09: '#fd971f',\n  base0A: '#f4bf75',\n  base0B: '#a6e22e',\n  base0C: '#a1efe4',\n  base0D: '#66d9ef',\n  base0E: '#ae81ff',\n  base0F: '#cc6633',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/nicinabox.ts",
    "content": "export default {\n  scheme: 'nicinabox',\n  author: 'nicinabox (http://github.com/nicinabox)',\n  base00: '#2A2F3A',\n  base01: '#3C444F',\n  base02: '#4F5A65',\n  base03: '#BEBEBE',\n  base04: '#b0b0b0', // based on ocean theme\n  base05: '#d0d0d0', // based on ocean theme\n  base06: '#FFFFFF',\n  base07: '#f5f5f5', // based on ocean theme\n  base08: '#fb9fb1', // based on ocean theme\n  base09: '#FC6D24',\n  base0A: '#ddb26f', // based on ocean theme\n  base0B: '#A1C659',\n  base0C: '#12cfc0', // based on ocean theme\n  base0D: '#6FB3D2',\n  base0E: '#D381C3',\n  base0F: '#deaf8f', // based on ocean theme\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/ocean.ts",
    "content": "export default {\n  scheme: 'ocean',\n  author: 'chris kempson (http://chriskempson.com)',\n  base00: '#2b303b',\n  base01: '#343d46',\n  base02: '#4f5b66',\n  base03: '#65737e',\n  base04: '#a7adba',\n  base05: '#c0c5ce',\n  base06: '#dfe1e8',\n  base07: '#eff1f5',\n  base08: '#bf616a',\n  base09: '#d08770',\n  base0A: '#ebcb8b',\n  base0B: '#a3be8c',\n  base0C: '#96b5b4',\n  base0D: '#8fa1b3',\n  base0E: '#b48ead',\n  base0F: '#ab7967',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/paraiso.ts",
    "content": "export default {\n  scheme: 'paraiso',\n  author: 'jan t. sott',\n  base00: '#2f1e2e',\n  base01: '#41323f',\n  base02: '#4f424c',\n  base03: '#776e71',\n  base04: '#8d8687',\n  base05: '#a39e9b',\n  base06: '#b9b6b0',\n  base07: '#e7e9db',\n  base08: '#ef6155',\n  base09: '#f99b15',\n  base0A: '#fec418',\n  base0B: '#48b685',\n  base0C: '#5bc4bf',\n  base0D: '#06b6ef',\n  base0E: '#815ba4',\n  base0F: '#e96ba8',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/pop.ts",
    "content": "export default {\n  scheme: 'pop',\n  author: 'chris kempson (http://chriskempson.com)',\n  base00: '#000000',\n  base01: '#202020',\n  base02: '#303030',\n  base03: '#505050',\n  base04: '#b0b0b0',\n  base05: '#d0d0d0',\n  base06: '#e0e0e0',\n  base07: '#ffffff',\n  base08: '#eb008a',\n  base09: '#f29333',\n  base0A: '#f8ca12',\n  base0B: '#37b349',\n  base0C: '#00aabb',\n  base0D: '#0e5a94',\n  base0E: '#b31e8d',\n  base0F: '#7a2d00',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/railscasts.ts",
    "content": "export default {\n  scheme: 'railscasts',\n  author: 'ryan bates (http://railscasts.com)',\n  base00: '#2b2b2b',\n  base01: '#272935',\n  base02: '#3a4055',\n  base03: '#5a647e',\n  base04: '#d4cfc9',\n  base05: '#e6e1dc',\n  base06: '#f4f1ed',\n  base07: '#f9f7f3',\n  base08: '#da4939',\n  base09: '#cc7833',\n  base0A: '#ffc66d',\n  base0B: '#a5c261',\n  base0C: '#519f50',\n  base0D: '#6d9cbe',\n  base0E: '#b6b3eb',\n  base0F: '#bc9458',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/shapeshifter.ts",
    "content": "export default {\n  scheme: 'shapeshifter',\n  author: 'tyler benziger (http://tybenz.com)',\n  base00: '#000000',\n  base01: '#040404',\n  base02: '#102015',\n  base03: '#343434',\n  base04: '#555555',\n  base05: '#ababab',\n  base06: '#e0e0e0',\n  base07: '#f9f9f9',\n  base08: '#e92f2f',\n  base09: '#e09448',\n  base0A: '#dddd13',\n  base0B: '#0ed839',\n  base0C: '#23edda',\n  base0D: '#3b48e3',\n  base0E: '#f996e2',\n  base0F: '#69542d',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/solarized.ts",
    "content": "export default {\n  scheme: 'solarized',\n  author: 'ethan schoonover (http://ethanschoonover.com/solarized)',\n  base00: '#002b36',\n  base01: '#073642',\n  base02: '#586e75',\n  base03: '#657b83',\n  base04: '#839496',\n  base05: '#93a1a1',\n  base06: '#eee8d5',\n  base07: '#fdf6e3',\n  base08: '#dc322f',\n  base09: '#cb4b16',\n  base0A: '#b58900',\n  base0B: '#859900',\n  base0C: '#2aa198',\n  base0D: '#268bd2',\n  base0E: '#6c71c4',\n  base0F: '#d33682',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/summerfruit.ts",
    "content": "export default {\n  scheme: 'summerfruit',\n  author: 'christopher corley (http://cscorley.github.io/)',\n  base00: '#151515',\n  base01: '#202020',\n  base02: '#303030',\n  base03: '#505050',\n  base04: '#B0B0B0',\n  base05: '#D0D0D0',\n  base06: '#E0E0E0',\n  base07: '#FFFFFF',\n  base08: '#FF0086',\n  base09: '#FD8900',\n  base0A: '#ABA800',\n  base0B: '#00C918',\n  base0C: '#1faaaa',\n  base0D: '#3777E6',\n  base0E: '#AD00A1',\n  base0F: '#cc6633',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/threezerotwofour.ts",
    "content": "export default {\n  scheme: 'threezerotwofour',\n  author: 'jan t. sott (http://github.com/idleberg)',\n  base00: '#090300',\n  base01: '#3a3432',\n  base02: '#4a4543',\n  base03: '#5c5855',\n  base04: '#807d7c',\n  base05: '#a5a2a2',\n  base06: '#d6d5d4',\n  base07: '#f7f7f7',\n  base08: '#db2d20',\n  base09: '#e8bbd0',\n  base0A: '#fded02',\n  base0B: '#01a252',\n  base0C: '#b5e4f4',\n  base0D: '#01a0e4',\n  base0E: '#a16a94',\n  base0F: '#cdab53',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/tomorrow.ts",
    "content": "export default {\n  scheme: 'tomorrow',\n  author: 'chris kempson (http://chriskempson.com)',\n  base00: '#1d1f21',\n  base01: '#282a2e',\n  base02: '#373b41',\n  base03: '#969896',\n  base04: '#b4b7b4',\n  base05: '#c5c8c6',\n  base06: '#e0e0e0',\n  base07: '#ffffff',\n  base08: '#cc6666',\n  base09: '#de935f',\n  base0A: '#f0c674',\n  base0B: '#b5bd68',\n  base0C: '#8abeb7',\n  base0D: '#81a2be',\n  base0E: '#b294bb',\n  base0F: '#a3685a',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/tube.ts",
    "content": "export default {\n  scheme: 'london tube',\n  author: 'jan t. sott',\n  base00: '#231f20',\n  base01: '#1c3f95',\n  base02: '#5a5758',\n  base03: '#737171',\n  base04: '#959ca1',\n  base05: '#d9d8d8',\n  base06: '#e7e7e8',\n  base07: '#ffffff',\n  base08: '#ee2e24',\n  base09: '#f386a1',\n  base0A: '#ffd204',\n  base0B: '#00853e',\n  base0C: '#85cebc',\n  base0D: '#009ddc',\n  base0E: '#98005d',\n  base0F: '#b06110',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/themes/twilight.ts",
    "content": "export default {\n  scheme: 'twilight',\n  author: 'david hart (http://hart-dev.com)',\n  base00: '#1e1e1e',\n  base01: '#323537',\n  base02: '#464b50',\n  base03: '#5f5a60',\n  base04: '#838184',\n  base05: '#a7a7a7',\n  base06: '#c3c3c3',\n  base07: '#ffffff',\n  base08: '#cf6a4c',\n  base09: '#cda869',\n  base0A: '#f9ee98',\n  base0B: '#8f9d6a',\n  base0C: '#afc4db',\n  base0D: '#7587a6',\n  base0E: '#9b859d',\n  base0F: '#9b703f',\n};\n"
  },
  {
    "path": "packages/react-base16-styling/src/types.ts",
    "content": "import * as CSS from 'csstype';\nimport type { Base16Theme } from './themes/index.js';\n\nexport interface Styling {\n  className?: string;\n  style?: CSS.Properties<string | number>;\n}\n\nexport type StylingValueFunction = (\n  styling: Styling,\n  ...rest: unknown[]\n) => Partial<Styling>;\n\nexport type StylingValue =\n  | string\n  | CSS.Properties<string | number>\n  | StylingValueFunction;\n\nexport type StylingConfig = {\n  // Should actually only be string | Base16Theme\n  extend?: string | Base16Theme | StylingValue;\n} & {\n  // Should actually only be StylingValue\n  [name: string]: StylingValue | string | Base16Theme;\n};\n\nexport type Theme = string | Base16Theme | StylingConfig;\n\nexport type StylingFunction = (\n  keys: (string | false | undefined) | (string | false | undefined)[],\n  ...rest: unknown[]\n) => Styling;\n"
  },
  {
    "path": "packages/react-base16-styling/test/index.test.ts",
    "content": "import {\n  createStyling,\n  invertBase16Theme,\n  getBase16Theme,\n} from '../src/index.js';\nimport { base16Themes, Base16Theme } from '../src/themes/index.js';\nimport { Styling, StylingConfig } from '../src/types.js';\n\nconst base16Theme = {\n  scheme: 'myscheme',\n  author: 'me',\n  base00: '#000000',\n  base01: '#222222',\n  base02: '#444444',\n  base03: '#666666',\n  base04: '#999999',\n  base05: '#bbbbbb',\n  base06: '#dddddd',\n  base07: '#ffffff',\n  base08: '#ff0000',\n  base09: '#ff9900',\n  base0A: '#ffff00',\n  base0B: '#999900',\n  base0C: '#009999',\n  base0D: '#009900',\n  base0E: '#9999ff',\n  base0F: '#ff0099',\n};\n\nconst invertedBase16Theme = {\n  scheme: 'myscheme:inverted',\n  author: 'me',\n  base00: '#FFFFFF',\n  base01: '#FFFFFF',\n  base02: '#A2A1A2',\n  base03: '#807F80',\n  base04: '#807F80',\n  base05: '#5E5D5E',\n  base06: '#3C3B3C',\n  base07: '#1A191A',\n  base08: '#FF4D4D',\n  base09: '#CB6500',\n  base0A: '#545400',\n  base0B: '#A2A20A',\n  base0C: '#0FA8A8',\n  base0D: '#32CB32',\n  base0E: '#6868CE',\n  base0F: '#FF2AC3',\n};\n\nconst apathyInverted = {\n  author: 'jannik siebert (https://github.com/janniks)',\n  base00: '#EFFFFF',\n  base01: '#E3FFFF',\n  base02: '#DAFFFF',\n  base03: '#67A49A',\n  base04: '#66A399',\n  base05: '#51857C',\n  base06: '#3C635D',\n  base07: '#2A3F3C',\n  base08: '#2F8779',\n  base09: '#4E89A6',\n  base0A: '#8391DB',\n  base0B: '#B167BF',\n  base0C: '#C8707E',\n  base0D: '#A7994F',\n  base0E: '#469038',\n  base0F: '#3A9257',\n  scheme: 'apathy:inverted',\n};\n\nconst getStylingFromBase16 = (base16: Base16Theme): StylingConfig => ({\n  testClass: 'testClass',\n  testStyle: {\n    color: base16.base00,\n  },\n  testFunc: ({ style }, arg) => ({\n    className: `testClass--${arg as string}`,\n    style: {\n      ...style,\n      width: 0,\n      color: base16.base00,\n    },\n  }),\n  baseStyle: {\n    color: 'red',\n  },\n  additionalStyle: {\n    border: 0,\n  },\n  testFuncNoStyle: (_, arg) => ({\n    className: `testClass--${arg as string}`,\n  }),\n});\n\ntest('invertTheme', () => {\n  expect(invertBase16Theme(base16Theme)).toEqual(invertedBase16Theme);\n});\n\ntest('getBase16Theme', () => {\n  expect(getBase16Theme('apathy')).toEqual(base16Themes.apathy);\n  expect(getBase16Theme({ extend: 'apathy' })).toEqual(base16Themes.apathy);\n  expect(getBase16Theme('apathy:inverted')).toEqual(apathyInverted);\n  expect(getBase16Theme({})).toBeUndefined();\n});\n\ntest('createStyling (default)', () => {\n  const styling = createStyling(getStylingFromBase16, {\n    defaultBase16: base16Themes.apathy,\n  });\n  const defaultStyling = styling(undefined);\n\n  expect(defaultStyling('testClass')).toEqual({ className: 'testClass' });\n  expect(defaultStyling('testStyle')).toEqual({\n    style: { color: base16Themes.apathy.base00 },\n  });\n  expect(defaultStyling('testFunc', 'mod')).toEqual({\n    className: 'testClass--mod',\n    style: {\n      width: 0,\n      color: base16Themes.apathy.base00,\n    },\n  });\n});\n\ntest('createStyling (custom)', () => {\n  const styling = createStyling(getStylingFromBase16, {\n    defaultBase16: base16Themes.apathy,\n  });\n  let customStyling = styling({\n    testClass: 'customClass',\n    testStyle: { height: 0 },\n    testFunc: (styling: Styling, arg) => ({\n      className: `${styling.className!} customClass--${arg as string}`,\n      style: {\n        ...styling.style,\n        border: 0,\n      },\n    }),\n    testFuncNoStyle: (styling: Styling, arg) => ({\n      className: `${styling.className!} customClass--${arg as string}`,\n      style: {\n        ...styling.style,\n        border: 0,\n      },\n    }),\n  });\n\n  expect(customStyling('testClass')).toEqual({\n    className: 'testClass customClass',\n  });\n  expect(customStyling('testStyle')).toEqual({\n    style: { color: base16Themes.apathy.base00, height: 0 },\n  });\n  expect(customStyling('testFunc', 'mod')).toEqual({\n    className: 'testClass--mod customClass--mod',\n    style: {\n      width: 0,\n      color: base16Themes.apathy.base00,\n      border: 0,\n    },\n  });\n  expect(customStyling('testFuncNoStyle', 'mod')).toEqual({\n    className: 'testClass--mod customClass--mod',\n    style: {\n      border: 0,\n    },\n  });\n\n  customStyling = styling({\n    testClass: () => ({\n      className: 'customClass',\n    }),\n    testStyle: () => ({\n      style: {\n        border: 0,\n      },\n    }),\n  });\n\n  expect(customStyling('testClass')).toEqual({ className: 'customClass' });\n  expect(customStyling('testStyle')).toEqual({ style: { border: 0 } });\n});\n\ntest('createStyling (multiple)', () => {\n  const styling = createStyling(getStylingFromBase16, {\n    defaultBase16: base16Themes.apathy,\n  });\n  let customStyling = styling({\n    baseStyle: ({ style }) => ({ style: { ...style, color: 'blue' } }),\n  });\n\n  expect(customStyling(['baseStyle', 'additionalStyle'])).toEqual({\n    style: {\n      color: 'blue',\n      border: 0,\n    },\n  });\n\n  customStyling = styling({\n    additionalStyle: ({ style }) => ({ style: { ...style, border: 1 } }),\n  });\n\n  expect(customStyling(['baseStyle', 'additionalStyle'])).toEqual({\n    style: {\n      color: 'red',\n      border: 1,\n    },\n  });\n});\n"
  },
  {
    "path": "packages/react-base16-styling/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/react-base16-styling/tsconfig.test.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"jest\"]\n  },\n  \"include\": [\"src\", \"test\"]\n}\n"
  },
  {
    "path": "packages/react-dock/CHANGELOG.md",
    "content": "# Change Log\n\n## 0.8.0\n\n### Minor Changes\n\n- 6830118: Add React 19 to peer deps\n\n## 0.7.0\n\n### Minor Changes\n\n- bbb1a40: Convert React packages to ESM\n\n## 0.6.0\n\n### Minor Changes\n\n- 8a7eae4: Add React 18 to peerDependencies range\n\n## 0.5.0\n\n- Adds ESM build (https://github.com/reduxjs/redux-devtools/pull/997) and switches the default export to a named export in order to ensure that the CommonJS output and the ESM output are [interchangeable](https://rollupjs.org/guide/en/#outputexports):\n\n```diff\n- import Dock from 'react-dock';\n+ import { Dock } from 'react-dock';\n```\n\n## [0.4.0](https://github.com/reduxjs/redux-devtools/compare/react-dock@0.3.0...react-dock@0.4.0) (2021-03-06)\n\n### Features\n\n- update peer dependencies to allow react@^17 ([#703](https://github.com/reduxjs/redux-devtools/issues/703)) ([2aaa9c1](https://github.com/reduxjs/redux-devtools/commit/2aaa9c10a383e3a7ab20b3ab14639781fd7bb2eb))\n\n## 0.3.0 (2020-09-07)\n\n### Features\n\n- **react-dock:** allow ReactNode children in types ([#610](https://github.com/reduxjs/redux-devtools/issues/610)) ([9000e36](https://github.com/reduxjs/redux-devtools/commit/9000e369cd4ecd21d2f3e32f0112bd332eb8b631))\n- **react-dock:** convert to TypeScript ([#607](https://github.com/reduxjs/redux-devtools/issues/607)) ([78ded9e](https://github.com/reduxjs/redux-devtools/commit/78ded9e0ca5ced5f6ae4e6d4474fa133b6d081b9))\n- **redux-devtools-inspector:** convert to TypeScript ([#623](https://github.com/reduxjs/redux-devtools/issues/623)) ([c7b0c7a](https://github.com/reduxjs/redux-devtools/commit/c7b0c7aa6e09f46a36b382ae3ec8e38bd48aeb28))\n"
  },
  {
    "path": "packages/react-dock/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Alexander Kuznetsov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/react-dock/README.md",
    "content": "# react-dock\n\nResizable dockable react component.\n\n#### Demo\n\n[http://alexkuz.github.io/react-dock/demo/](http://alexkuz.github.io/react-dock/demo/)\n\n#### Install\n\n```\n$ npm i -S react-dock\n```\n\n#### Example\n\n```jsx\nrender() {\n  return (\n    <Dock position='right' isVisible={this.state.isVisible}>\n      {/* you can pass a function as a child here */}\n      <div onClick={() => this.setState({ isVisible: !this.state.isVisible })}>X</div>\n    </Dock>\n  );\n}\n```\n\n#### Dock Props\n\n| Prop Name       | Description                                                                                                                                                                                                                                                                       |\n| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| position        | Side to dock (`left`, `right`, `top` or `bottom`). Default is `left`.                                                                                                                                                                                                             |\n| fluid           | If `true`, resize dock proportionally on window resize.                                                                                                                                                                                                                           |\n| size            | Size of dock panel (width or height, depending on `position`). If this prop is set, `Dock` is considered as a controlled component, so you need to use `onSizeChange` to track dock resizing. Value is a fraction of window width/height, if `fluid` is true, or pixels otherwise |\n| defaultSize     | Default size of dock panel (used for uncontrolled `Dock` component)                                                                                                                                                                                                               |\n| isVisible       | If `true`, dock is visible                                                                                                                                                                                                                                                        |\n| dimMode         | If `none` - content is not dimmed, if `transparent` - pointer events are disabled (so you can click through it), if `opaque` - click on dim area closes the dock. Default is `opaque`                                                                                             |\n| duration        | Animation duration. Should be synced with transition animation in style properties                                                                                                                                                                                                |\n| dimStyle        | Style for dim area                                                                                                                                                                                                                                                                |\n| dockStyle       | Style for dock                                                                                                                                                                                                                                                                    |\n| zIndex          | Z-index for wrapper                                                                                                                                                                                                                                                               |\n| onVisibleChange | Fires when `Dock` wants to change `isVisible` (when opaque dim is clicked, in particular)                                                                                                                                                                                         |\n| onSizeChange    | Fires when `Dock` wants to change `size`                                                                                                                                                                                                                                          |\n| children        | Dock content - react elements or function that returns an element. Function receives an object with these state values: `{ position, isResizing, size, isVisible }`                                                                                                               |\n"
  },
  {
    "path": "packages/react-dock/demo/CHANGELOG.md",
    "content": "# react-dock-demo\n\n## 0.1.7\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - react-dock@0.8.0\n\n## 0.1.6\n\n### Patch Changes\n\n- Updated dependencies [bbb1a40]\n  - react-dock@0.7.0\n\n## 0.1.5\n\n### Patch Changes\n\n- Updated dependencies [8a7eae4]\n  - react-dock@0.6.0\n"
  },
  {
    "path": "packages/react-dock/demo/eslint.config.mjs",
    "content": "import eslintJs from '../../../eslint.js.config.base.mjs';\nimport eslintTs from '../../../eslint.ts.react.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTs(\n    import.meta.dirname,\n    ['./src/**/*.ts', './src/**/*.tsx'],\n    ['./tsconfig.app.json'],\n  ),\n  ...eslintTs(\n    import.meta.dirname,\n    ['vite.config.ts'],\n    ['./tsconfig.node.json'],\n  ),\n  {\n    ignores: ['dist'],\n  },\n];\n"
  },
  {
    "path": "packages/react-dock/demo/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>React Dock</title>\n    <link\n      href=\"http://fonts.googleapis.com/css?family=Noto+Sans|Roboto:400,300,500\"\n      rel=\"stylesheet\"\n      type=\"text/css\"\n    />\n    <link\n      href=\"//maxcdn.bootstrapcdn.com/bootswatch/3.3.5/paper/bootstrap.min.css\"\n      rel=\"stylesheet\"\n    />\n  </head>\n  <body>\n    <a\n      href=\"https://github.com/reduxjs/redux-devtools/tree/main/packages/react-dock\"\n      ><img\n        style=\"z-index: 999999999; position: fixed; top: 0; left: 0; border: 0\"\n        src=\"https://camo.githubusercontent.com/121cd7cbdc3e4855075ea8b558508b91ac463ac2/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f6c6566745f677265656e5f3030373230302e706e67\"\n        alt=\"Fork me on GitHub\"\n        data-canonical-src=\"https://s3.amazonaws.com/github/ribbons/forkme_left_green_007200.png\"\n    /></a>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/index.tsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/react-dock/demo/package.json",
    "content": "{\n  \"private\": true,\n  \"name\": \"react-dock-demo\",\n  \"version\": \"0.1.7\",\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"tsc -b && vite build\",\n    \"preview\": \"vite preview\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc\"\n  },\n  \"dependencies\": {\n    \"@emotion/styled\": \"^11.14.1\",\n    \"react\": \"^19.2.4\",\n    \"react-bootstrap\": \"^2.10.10\",\n    \"react-dock\": \"workspace:^\",\n    \"react-dom\": \"^19.2.4\",\n    \"react-icons\": \"^5.6.0\",\n    \"react-is\": \"^19.2.4\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^24.12.0\",\n    \"@types/react\": \"^19.2.14\",\n    \"@types/react-dom\": \"^19.2.3\",\n    \"@vitejs/plugin-react\": \"^6.0.0\",\n    \"typescript\": \"~5.9.3\",\n    \"vite\": \"^8.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/react-dock/demo/src/App.tsx",
    "content": "import React, { Component } from 'react';\nimport { Button, Form } from 'react-bootstrap';\nimport { BsX } from 'react-icons/bs';\nimport styled from '@emotion/styled';\n\nimport { Dock } from 'react-dock';\n\nconst Root = styled.div`\n  font-size: 16px;\n  color: #999;\n  height: 100vh;\n`;\n\nconst Main = styled.div`\n  width: 100%;\n  height: 150%;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  padding-top: 30vh;\n`;\n\nconst DockContent = styled.div`\n  width: 100%;\n  height: 100%;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  flex-direction: column;\n`;\n\nconst Remove = styled(BsX)`\n  position: absolute;\n  z-index: 1;\n  right: 10px;\n  top: 10px;\n  cursor: pointer;\n`;\n\nconst positions = ['left', 'top', 'right', 'bottom'] as const;\nconst dimModes = ['transparent', 'none', 'opaque'] as const;\n\ninterface State {\n  positionIdx: number;\n  dimModeIdx: number;\n  isVisible: boolean;\n  fluid: boolean;\n  customAnimation: boolean;\n  slow: boolean;\n  size: number;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport default class App extends Component<{}, State> {\n  state: State = {\n    positionIdx: 0,\n    dimModeIdx: 0,\n    isVisible: true,\n    fluid: true,\n    customAnimation: false,\n    slow: false,\n    size: 0.25,\n  };\n\n  render() {\n    const duration = this.state.slow ? 2000 : 200;\n    const dur = duration / 1000;\n    const transitions = ['left', 'top', 'width', 'height']\n      .map((p) => `${p} ${dur}s cubic-bezier(0, 1.5, 0.5, 1)`)\n      .join(',');\n\n    return (\n      <Root>\n        <Main>\n          <h1>Main Content</h1>\n          <div>\n            <div>\n              Position: {positions[this.state.positionIdx]}\n              <Button\n                onClick={this.handlePositionClick}\n                style={{ marginLeft: '20px' }}\n              >\n                Change\n              </Button>\n            </div>\n            <div>\n              Dim Mode: {dimModes[this.state.dimModeIdx]}\n              <Button\n                onClick={this.handleDimModeClick}\n                style={{ marginLeft: '20px' }}\n              >\n                Change\n              </Button>\n            </div>\n            <Form.Check\n              label=\"is visible\"\n              checked={this.state.isVisible}\n              onChange={() =>\n                this.setState({\n                  isVisible: !this.state.isVisible,\n                })\n              }\n            />\n\n            <Form.Check\n              label=\"custom animation\"\n              checked={this.state.customAnimation}\n              onChange={() =>\n                this.setState({\n                  customAnimation: !this.state.customAnimation,\n                })\n              }\n            />\n\n            <Form.Check\n              label=\"slow\"\n              checked={this.state.slow}\n              onChange={() =>\n                this.setState({\n                  slow: !this.state.slow,\n                })\n              }\n            />\n\n            <Form.Check\n              label=\"fluid\"\n              checked={this.state.fluid}\n              onChange={() =>\n                this.setState({\n                  fluid: !this.state.fluid,\n                })\n              }\n            />\n          </div>\n        </Main>\n        <Dock\n          position={positions[this.state.positionIdx]}\n          size={this.state.size}\n          dimMode={dimModes[this.state.dimModeIdx]}\n          isVisible={this.state.isVisible}\n          onVisibleChange={this.handleVisibleChange}\n          onSizeChange={this.handleSizeChange}\n          fluid={this.state.fluid}\n          dimStyle={{ background: 'rgba(0, 0, 100, 0.2)' }}\n          dockStyle={\n            this.state.customAnimation ? { transition: transitions } : null\n          }\n          dockHiddenStyle={\n            this.state.customAnimation\n              ? {\n                  transition: [\n                    transitions,\n                    `opacity 0.01s linear ${dur}s`,\n                  ].join(','),\n                }\n              : null\n          }\n          duration={duration}\n        >\n          {({ position, isResizing }) => (\n            <DockContent>\n              <h1>Dock Content</h1>\n              <div>Position: {position}</div>\n              <div>Resizing: {isResizing ? 'true' : 'false'}</div>\n              <Remove onClick={() => this.setState({ isVisible: false })} />\n            </DockContent>\n          )}\n        </Dock>\n      </Root>\n    );\n  }\n\n  handleVisibleChange = (isVisible: boolean) => {\n    this.setState({ isVisible });\n  };\n\n  handleSizeChange = (size: number) => {\n    this.setState({ size });\n  };\n\n  handlePositionClick = () => {\n    this.setState({ positionIdx: (this.state.positionIdx + 1) % 4 });\n  };\n\n  handleDimModeClick = () => {\n    this.setState({ dimModeIdx: (this.state.dimModeIdx + 1) % 3 });\n  };\n}\n"
  },
  {
    "path": "packages/react-dock/demo/src/index.tsx",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport App from './App.js';\n\nconst root = ReactDOM.createRoot(document.getElementById('root')!);\nroot.render(<App />);\n"
  },
  {
    "path": "packages/react-dock/demo/tsconfig.app.json",
    "content": "{\n  \"extends\": \"../../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"noEmit\": true\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/react-dock/demo/tsconfig.json",
    "content": "{\n  \"files\": [],\n  \"references\": [\n    { \"path\": \"./tsconfig.app.json\" },\n    { \"path\": \"./tsconfig.node.json\" }\n  ]\n}\n"
  },
  {
    "path": "packages/react-dock/demo/tsconfig.node.json",
    "content": "{\n  \"extends\": \"../../../tsconfig.esm.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"node\"],\n    \"noEmit\": true\n  },\n  \"include\": [\"vite.config.ts\"]\n}\n"
  },
  {
    "path": "packages/react-dock/demo/vite.config.ts",
    "content": "import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\n// https://vite.dev/config/\nexport default defineConfig({\n  plugins: [react()],\n});\n"
  },
  {
    "path": "packages/react-dock/eslint.config.js",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTsReact from '../../eslint.ts.react.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTsReact(import.meta.dirname),\n  {\n    ignores: ['demo', 'lib'],\n  },\n];\n"
  },
  {
    "path": "packages/react-dock/package.json",
    "content": "{\n  \"name\": \"react-dock\",\n  \"version\": \"0.8.0\",\n  \"description\": \"Resizable dockable react component\",\n  \"keywords\": [\n    \"react\",\n    \"reactjs\",\n    \"dock\",\n    \"sidebar\"\n  ],\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Alexander <alexkuz@gmail.com> (http://kuzya.org/)\",\n  \"files\": [\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": \"./lib/index.js\",\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run lint\"\n  },\n  \"dependencies\": {\n    \"@types/lodash-es\": \"^4.17.12\",\n    \"lodash-es\": \"^4.17.23\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"^19.2.14\",\n    \"react\": \"^19.2.4\",\n    \"rimraf\": \"^6.1.3\",\n    \"typescript\": \"~5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"@types/react\": \"^16.3.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react\": \"^16.3.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/react-dock/src/Dock.tsx",
    "content": "import React, { Component, ReactNode } from 'react';\nimport { debounce } from 'lodash-es';\nimport type { DebouncedFunc } from 'lodash-es';\nimport autoprefix from './autoprefix.js';\n\ninterface Styles {\n  [key: string]: React.CSSProperties;\n}\n\nfunction autoprefixes(styles: Styles) {\n  return Object.keys(styles).reduce<Styles>(\n    (obj, key) => ((obj[key] = autoprefix(styles[key])), obj),\n    {},\n  );\n}\n\nconst styles = autoprefixes({\n  wrapper: {\n    position: 'fixed',\n    width: 0,\n    height: 0,\n    top: 0,\n    left: 0,\n  },\n\n  dim: {\n    position: 'fixed',\n    left: 0,\n    right: 0,\n    top: 0,\n    bottom: 0,\n    zIndex: 0,\n    background: 'rgba(0, 0, 0, 0.2)',\n    opacity: 1,\n  },\n\n  dimAppear: {\n    opacity: 0,\n  },\n\n  dimTransparent: {\n    pointerEvents: 'none',\n  },\n\n  dimHidden: {\n    opacity: 0,\n  },\n\n  dock: {\n    position: 'fixed',\n    zIndex: 1,\n    boxShadow: '0 0 4px rgba(0, 0, 0, 0.3)',\n    background: 'white',\n    left: 0,\n    top: 0,\n    width: '100%',\n    height: '100%',\n  },\n\n  dockHidden: {\n    opacity: 0,\n  },\n\n  dockResizing: {\n    transition: 'none',\n  },\n\n  dockContent: {\n    width: '100%',\n    height: '100%',\n    overflow: 'auto',\n  },\n\n  resizer: {\n    position: 'absolute',\n    zIndex: 2,\n    opacity: 0,\n  },\n});\n\nfunction getTransitions(duration: number) {\n  return ['left', 'top', 'width', 'height'].map(\n    (p) => `${p} ${duration / 1000}s ease-out`,\n  );\n}\n\nfunction getDockStyles(\n  { fluid, dockStyle, dockHiddenStyle, duration, position, isVisible }: Props,\n  { size, isResizing, fullWidth, fullHeight }: State,\n) {\n  let posStyle;\n  const absSize = fluid ? `${size * 100}%` : `${size}px`;\n\n  function getRestSize(fullSize: number) {\n    return fluid ? `${100 - size * 100}%` : `${fullSize - size}px`;\n  }\n\n  switch (position) {\n    case 'left':\n      posStyle = {\n        width: absSize,\n        left: isVisible ? 0 : '-' + absSize,\n      };\n      break;\n    case 'right':\n      posStyle = {\n        left: isVisible ? getRestSize(fullWidth) : fullWidth,\n        width: absSize,\n      };\n      break;\n    case 'top':\n      posStyle = {\n        top: isVisible ? 0 : '-' + absSize,\n        height: absSize,\n      };\n      break;\n    case 'bottom':\n      posStyle = {\n        top: isVisible ? getRestSize(fullHeight) : fullHeight,\n        height: absSize,\n      };\n      break;\n  }\n\n  const transitions = getTransitions(duration);\n\n  return [\n    styles.dock,\n    autoprefix({\n      transition: [\n        ...transitions,\n        !isVisible && `opacity 0.01s linear ${duration / 1000}s`,\n      ]\n        .filter((t) => t)\n        .join(','),\n    }),\n    dockStyle,\n    autoprefix(posStyle),\n    isResizing && styles.dockResizing,\n    !isVisible && styles.dockHidden,\n    !isVisible && dockHiddenStyle,\n  ];\n}\n\nfunction getDimStyles(\n  { dimMode, dimStyle, duration, isVisible }: Props,\n  { isTransitionStarted }: State,\n) {\n  return [\n    styles.dim,\n    autoprefix({\n      transition: `opacity ${duration / 1000}s ease-out`,\n    }),\n    dimStyle,\n    dimMode === 'transparent' && styles.dimTransparent,\n    !isVisible && styles.dimHidden,\n    isTransitionStarted && isVisible && styles.dimAppear,\n    isTransitionStarted && !isVisible && styles.dimDisappear,\n  ];\n}\n\nfunction getResizerStyles(position: 'left' | 'right' | 'top' | 'bottom') {\n  let resizerStyle;\n  const size = 10;\n\n  switch (position) {\n    case 'left':\n      resizerStyle = {\n        right: -size / 2,\n        width: size,\n        top: 0,\n        height: '100%',\n        cursor: 'col-resize',\n      };\n      break;\n    case 'right':\n      resizerStyle = {\n        left: -size / 2,\n        width: size,\n        top: 0,\n        height: '100%',\n        cursor: 'col-resize',\n      };\n      break;\n    case 'top':\n      resizerStyle = {\n        bottom: -size / 2,\n        height: size,\n        left: 0,\n        width: '100%',\n        cursor: 'row-resize',\n      };\n      break;\n    case 'bottom':\n      resizerStyle = {\n        top: -size / 2,\n        height: size,\n        left: 0,\n        width: '100%',\n        cursor: 'row-resize',\n      };\n      break;\n  }\n\n  return [styles.resizer, autoprefix(resizerStyle)];\n}\n\nfunction getFullSize(\n  position: 'left' | 'right' | 'top' | 'bottom',\n  fullWidth: number,\n  fullHeight: number,\n) {\n  return position === 'left' || position === 'right' ? fullWidth : fullHeight;\n}\n\ninterface Props {\n  position: 'left' | 'right' | 'top' | 'bottom';\n  zIndex: number;\n  fluid: boolean;\n  size?: number;\n  defaultSize: number;\n  dimMode: 'none' | 'transparent' | 'opaque';\n  isVisible?: boolean;\n  onVisibleChange?: (isVisible: boolean) => void;\n  onSizeChange?: (size: number) => void;\n  dimStyle?: React.CSSProperties | null;\n  dockStyle?: React.CSSProperties | null;\n  dockHiddenStyle?: React.CSSProperties | null;\n  duration: number;\n  children?:\n    | ((params: {\n        position: 'left' | 'right' | 'top' | 'bottom';\n        isResizing: boolean | undefined;\n        size: number;\n        isVisible: boolean | undefined;\n      }) => ReactNode)\n    | ReactNode;\n}\n\ninterface State {\n  isControlled: boolean;\n  size: number;\n  isDimHidden: boolean;\n  fullWidth: number;\n  fullHeight: number;\n  isTransitionStarted: boolean;\n  isWindowResizing: unknown;\n  isResizing?: boolean;\n}\n\nexport default class Dock extends Component<Props, State> {\n  state: State = {\n    isControlled: typeof this.props.size !== 'undefined',\n    size: this.props.size || this.props.defaultSize,\n    isDimHidden: !this.props.isVisible,\n    fullWidth: window.innerWidth,\n    fullHeight: window.innerHeight,\n    isTransitionStarted: false,\n    isWindowResizing: false,\n  };\n\n  static defaultProps = {\n    position: 'left',\n    zIndex: 99999999,\n    fluid: true,\n    defaultSize: 0.3,\n    dimMode: 'opaque',\n    duration: 200,\n  };\n\n  componentDidMount() {\n    window.addEventListener('touchend', this.handleMouseUp);\n    window.addEventListener('mouseup', this.handleMouseUp);\n    window.addEventListener('touchmove', this.handleMouseMove);\n    window.addEventListener('mousemove', this.handleMouseMove);\n    window.addEventListener('resize', this.handleResize);\n\n    this.updateWindowSize();\n  }\n\n  componentWillUnmount() {\n    window.removeEventListener('touchend', this.handleMouseUp);\n    window.removeEventListener('mouseup', this.handleMouseUp);\n    window.removeEventListener('touchmove', this.handleMouseMove);\n    window.removeEventListener('mousemove', this.handleMouseMove);\n    window.removeEventListener('resize', this.handleResize);\n  }\n\n  UNSAFE_componentWillReceiveProps(nextProps: Props) {\n    const isControlled = typeof nextProps.size !== 'undefined';\n\n    this.setState({ isControlled });\n\n    if (isControlled && nextProps.size && this.props.size !== nextProps.size) {\n      this.setState({ size: nextProps.size });\n    } else if (this.props.fluid !== nextProps.fluid) {\n      this.updateSize(nextProps);\n    }\n\n    if (this.props.isVisible !== nextProps.isVisible) {\n      this.setState({\n        isTransitionStarted: true,\n      });\n    }\n  }\n\n  updateSize(props: Props) {\n    const { fullWidth, fullHeight } = this.state;\n\n    this.setState({\n      size: props.fluid\n        ? this.state.size / getFullSize(props.position, fullWidth, fullHeight)\n        : getFullSize(props.position, fullWidth, fullHeight) * this.state.size,\n    });\n  }\n\n  componentDidUpdate(prevProps: Props) {\n    if (this.props.isVisible !== prevProps.isVisible) {\n      if (!this.props.isVisible) {\n        window.setTimeout(() => this.hideDim(), this.props.duration);\n      } else {\n        this.setState({ isDimHidden: false });\n      }\n\n      window.setTimeout(() => this.setState({ isTransitionStarted: false }), 0);\n    }\n  }\n\n  transitionEnd = () => {\n    this.setState({ isTransitionStarted: false });\n  };\n\n  hideDim = () => {\n    if (!this.props.isVisible) {\n      this.setState({ isDimHidden: true });\n    }\n  };\n\n  render() {\n    const { children, zIndex, dimMode, position, isVisible } = this.props;\n    const { isResizing, size, isDimHidden } = this.state;\n\n    const dimStyles = Object.assign(\n      {},\n      ...getDimStyles(this.props, this.state),\n    );\n    const dockStyles = Object.assign(\n      {},\n      ...getDockStyles(this.props, this.state),\n    );\n    const resizerStyles = Object.assign({}, ...getResizerStyles(position));\n\n    return (\n      <div style={Object.assign({}, styles.wrapper, { zIndex })}>\n        {dimMode !== 'none' && !isDimHidden && (\n          <div style={dimStyles} onClick={this.handleDimClick} />\n        )}\n        <div style={dockStyles}>\n          <div\n            style={resizerStyles}\n            onMouseDown={this.handleMouseDown}\n            onTouchStart={this.handleMouseDown}\n          />\n          <div style={styles.dockContent}>\n            {typeof children === 'function'\n              ? children({\n                  position,\n                  isResizing,\n                  size,\n                  isVisible,\n                })\n              : children}\n          </div>\n        </div>\n      </div>\n    );\n  }\n\n  handleDimClick = () => {\n    if (this.props.dimMode === 'opaque') {\n      if (this.props.onVisibleChange) this.props.onVisibleChange(false);\n    }\n  };\n\n  handleResize = () => {\n    if (window.requestAnimationFrame) {\n      window.requestAnimationFrame(this.updateWindowSize.bind(this, true));\n    } else {\n      this.updateWindowSize(true);\n    }\n  };\n\n  updateWindowSize = (windowResize?: true) => {\n    const sizeState = {\n      fullWidth: window.innerWidth,\n      fullHeight: window.innerHeight,\n    };\n\n    if (windowResize) {\n      this.setState({\n        ...sizeState,\n        isResizing: true,\n        isWindowResizing: windowResize,\n      });\n\n      this.debouncedUpdateWindowSizeEnd();\n    } else {\n      this.setState(sizeState);\n    }\n  };\n\n  updateWindowSizeEnd = () => {\n    this.setState({\n      isResizing: false,\n      isWindowResizing: false,\n    });\n  };\n\n  debouncedUpdateWindowSizeEnd: DebouncedFunc<() => void> = debounce(\n    this.updateWindowSizeEnd,\n    30,\n  );\n\n  handleWrapperLeave = () => {\n    this.setState({ isResizing: false });\n  };\n\n  handleMouseDown = () => {\n    this.setState({ isResizing: true });\n  };\n\n  handleMouseUp = () => {\n    this.setState({ isResizing: false });\n  };\n\n  handleMouseMove = (e: MouseEvent | TouchEvent) => {\n    if (!this.state.isResizing || this.state.isWindowResizing) return;\n\n    if (!(e as TouchEvent).touches) e.preventDefault();\n\n    const { position, fluid } = this.props;\n    const { fullWidth, fullHeight, isControlled } = this.state;\n    let { clientX: x, clientY: y } = e as MouseEvent;\n\n    if ((e as TouchEvent).touches) {\n      x = (e as TouchEvent).touches[0].clientX;\n      y = (e as TouchEvent).touches[0].clientY;\n    }\n\n    let size;\n\n    switch (position) {\n      case 'left':\n        size = fluid ? x / fullWidth : x;\n        break;\n      case 'right':\n        size = fluid ? (fullWidth - x) / fullWidth : fullWidth - x;\n        break;\n      case 'top':\n        size = fluid ? y / fullHeight : y;\n        break;\n      case 'bottom':\n        size = fluid ? (fullHeight - y) / fullHeight : fullHeight - y;\n        break;\n    }\n\n    if (this.props.onSizeChange) this.props.onSizeChange(size);\n\n    if (!isControlled) {\n      this.setState({ size });\n    }\n  };\n}\n"
  },
  {
    "path": "packages/react-dock/src/autoprefix.ts",
    "content": "// Same as https://github.com/SimenB/react-vendor-prefixes/blob/master/src/index.js,\n// but dumber\n\nimport { CSSProperties } from 'react';\n\nconst vendorSpecificProperties = [\n  'animation',\n  'animationDelay',\n  'animationDirection',\n  'animationDuration',\n  'animationFillMode',\n  'animationIterationCount',\n  'animationName',\n  'animationPlayState',\n  'animationTimingFunction',\n  'appearance',\n  'backfaceVisibility',\n  'backgroundClip',\n  'borderImage',\n  'borderImageSlice',\n  'boxSizing',\n  'boxShadow',\n  'contentColumns',\n  'transform',\n  'transformOrigin',\n  'transformStyle',\n  'transition',\n  'transitionDelay',\n  'transitionDuration',\n  'transitionProperty',\n  'transitionTimingFunction',\n  'perspective',\n  'perspectiveOrigin',\n  'userSelect',\n];\n\nconst prefixes = ['Moz', 'Webkit', 'ms', 'O'];\n\nfunction prefixProp<Value>(key: string, value: Value) {\n  return prefixes.reduce<{ [key: string]: Value }>(\n    (obj, pre) => (\n      (obj[pre + key[0].toUpperCase() + key.substr(1)] = value),\n      obj\n    ),\n    {},\n  );\n}\n\nexport default function autoprefix(style: CSSProperties) {\n  return Object.keys(style).reduce(\n    (obj, key) =>\n      vendorSpecificProperties.includes(key)\n        ? {\n            ...obj,\n            ...prefixProp(key, style[key as keyof CSSProperties]),\n          }\n        : obj,\n    style,\n  );\n}\n"
  },
  {
    "path": "packages/react-dock/src/index.ts",
    "content": "export { default as Dock } from './Dock.js';\n"
  },
  {
    "path": "packages/react-dock/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/react-dock/tsconfig.test.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"jest\"]\n  },\n  \"include\": [\"src\", \"test\"]\n}\n"
  },
  {
    "path": "packages/react-json-tree/CHANGELOG.md",
    "content": "# Change Log\n\n## 0.20.0\n\n### Minor Changes\n\n- 6830118: Add React 19 to peer deps\n\n## 0.19.0\n\n### Minor Changes\n\n- bbb1a40: Convert React packages to ESM\n\n### Patch Changes\n\n- Updated dependencies [bbb1a40]\n  - react-base16-styling@0.10.0\n\n## 0.18.0\n\n### Major Changes\n\n- 81926f32: Remove UNSAFE method from react-json-tree\n  - Replace `shouldExpandNode` with `shouldExpandNodeInitially`. This function is now only called when a node in the tree is first rendered, when before it would update the expanded state of the node if the results of calling `shouldExpandNode` changed between renders. There is no way to replicate the old behavior exactly, but the new behavior is the intended behavior for the use cases within Redux DevTools. Please open an issue if you need a way to programatically control the expanded state of nodes.\n  - Bump the minimum React version from `16.3.0` to `16.8.0` so that `react-json-tree` can use hooks.\n  - Tightened TypeScript prop types to use `unknown` instead of `any` where possible and make the key path array `readonly`.\n\n## 0.17.0\n\n### Minor Changes\n\n- 8a7eae4: Add React 18 to peerDependencies range\n\n## 0.16.2\n\n### Patch Changes\n\n- 4c9a890: Fix type import for Typescript versions <4.5\n\n## 0.16.0\n\n- Adds ESM build (https://github.com/reduxjs/redux-devtools/pull/997) and switches the default export to a named export in order to ensure that the CommonJS output and the ESM output are [interchangeable](https://rollupjs.org/guide/en/#outputexports):\n\n```diff\n- import JSONTree from 'react-json-tree';\n+ import { JSONTree } from 'react-json-tree';\n```\n\n## [0.15.0](https://github.com/reduxjs/redux-devtools/compare/react-json-tree@0.14.0...react-json-tree@0.15.0) (2021-03-06)\n\n### Features\n\n- update peer dependencies to allow react@^17 ([#703](https://github.com/reduxjs/redux-devtools/issues/703)) ([2aaa9c1](https://github.com/reduxjs/redux-devtools/commit/2aaa9c10a383e3a7ab20b3ab14639781fd7bb2eb))\n\n## [0.14.0](https://github.com/reduxjs/redux-devtools/compare/react-json-tree@0.13.0...react-json-tree@0.14.0) (2021-03-06)\n\n### Bug Fixes\n\n- **react-json-tree:** remove isRequired from `data` prop type ([#685](https://github.com/reduxjs/redux-devtools/issues/685)) ([d76d6c6](https://github.com/reduxjs/redux-devtools/commit/d76d6c678d3b3b304cf53c1b4b1b329e8962f7b0))\n\n### Features\n\n- **react-json-tree:** Add keyPath to getItemString ([#694](https://github.com/reduxjs/redux-devtools/issues/694)) ([85b4b0f](https://github.com/reduxjs/redux-devtools/commit/85b4b0fb04b1d6d95054d5073fa17fa61efc0df3))\n\n## [0.13.0](https://github.com/reduxjs/redux-devtools/compare/react-json-tree@0.12.1...react-json-tree@0.13.0) (2020-09-07)\n\n### Bug Fixes\n\n- **react-base16-styling:** fix Styling type ([#602](https://github.com/reduxjs/redux-devtools/issues/602)) ([e7304b5](https://github.com/reduxjs/redux-devtools/commit/e7304b5853a572b53429809ed8ac4b7a198c90f8))\n\n### Features\n\n- **react-dock:** convert to TypeScript ([#607](https://github.com/reduxjs/redux-devtools/issues/607)) ([78ded9e](https://github.com/reduxjs/redux-devtools/commit/78ded9e0ca5ced5f6ae4e6d4474fa133b6d081b9))\n- **redux-devtools:** convert counter example to TypeScript ([#616](https://github.com/reduxjs/redux-devtools/issues/616)) ([f1e3f4f](https://github.com/reduxjs/redux-devtools/commit/f1e3f4f8340dea288de5229006acf9dc1ef1cccf))\n- **redux-devtools:** convert todomvc example to TypeScript ([#618](https://github.com/reduxjs/redux-devtools/issues/618)) ([37191e4](https://github.com/reduxjs/redux-devtools/commit/37191e46e600cd9ac2839f0687efb347fc4ef7c1))\n\n## [0.12.1](https://github.com/reduxjs/redux-devtools/compare/react-json-tree@0.12.0...react-json-tree@0.12.1) (2020-08-14)\n\n### Bug Fixes\n\n- **react-json-tree:** fix react-json-tree examples ([#531](https://github.com/reduxjs/redux-devtools/issues/531)) ([0864f28](https://github.com/reduxjs/redux-devtools/commit/0864f281560dcbad1ddb2ab985e23b841771cb8c))\n"
  },
  {
    "path": "packages/react-json-tree/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Shusaku Uesugi, (c) 2016-present Alexander Kuznetsov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/react-json-tree/README.md",
    "content": "# react-json-tree\n\nReact JSON Viewer Component, Extracted from [redux-devtools](https://github.com/reduxjs/redux-devtools). Supports [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#iterable) objects, such as [Immutable.js](https://facebook.github.io/immutable-js/).\n\n![](https://img.shields.io/npm/v/react-json-tree.svg)\n\n### Usage\n\n```jsx\nimport { JSONTree } from 'react-json-tree';\n// If you're using Immutable.js: `npm i --save immutable`\nimport { Map } from 'immutable';\n\n// Inside a React component:\nconst json = {\n  array: [1, 2, 3],\n  bool: true,\n  object: {\n    foo: 'bar',\n  },\n  immutable: Map({ key: 'value' }),\n};\n\n<JSONTree data={json} />;\n```\n\n#### Result:\n\n![](https://i.ibb.co/0KSYRJg/example-result.png)\n\nCheck out [examples](examples) directory for more details.\n\n### Theming\n\nThis component now uses [react-base16-styling](https://github.com/reduxjs/redux-devtools/tree/main/packages/react-base16-styling) module, which allows to customize component via `theme` property, which can be the following:\n\n- [base16](https://github.com/chriskempson/base16) theme data. [The example theme data can be found here](https://github.com/gaearon/redux-devtools/tree/75322b15ee7ba03fddf10ac3399881e302848874/src/react/themes).\n- object that contains style objects, strings (that treated as classnames) or functions. A function is used to extend its first argument `{ style, className }` and should return an object with the same structure. Other arguments depend on particular context (and should be described here). See [createStylingFromTheme.js](https://github.com/reduxjs/redux-devtools/blob/main/packages/react-json-tree/src/createStylingFromTheme.ts) for the list of styling object keys. Also, this object can extend `base16` theme via `extend` property.\n\nEvery theme has a light version, which is enabled with `invertTheme` prop.\n\n```jsx\nconst theme = {\n  scheme: 'monokai',\n  author: 'wimer hazenberg (http://www.monokai.nl)',\n  base00: '#272822',\n  base01: '#383830',\n  base02: '#49483e',\n  base03: '#75715e',\n  base04: '#a59f85',\n  base05: '#f8f8f2',\n  base06: '#f5f4f1',\n  base07: '#f9f8f5',\n  base08: '#f92672',\n  base09: '#fd971f',\n  base0A: '#f4bf75',\n  base0B: '#a6e22e',\n  base0C: '#a1efe4',\n  base0D: '#66d9ef',\n  base0E: '#ae81ff',\n  base0F: '#cc6633',\n};\n\n<div>\n  <JSONTree data={data} theme={theme} invertTheme={false} />\n</div>;\n```\n\n#### Result (Monokai theme, dark background):\n\n![](http://cl.ly/image/330o2L1J3V0h/screenshot%202015-08-26%20at%2010.48.24%20AM.png)\n\n#### Advanced Customization\n\n```jsx\n<div>\n  <JSONTree\n    data={data}\n    theme={{\n      extend: theme,\n      // underline keys for literal values\n      valueLabel: {\n        textDecoration: 'underline',\n      },\n      // switch key for objects to uppercase when object is expanded.\n      // `nestedNodeLabel` receives additional argument `expandable`\n      nestedNodeLabel: ({ style }, keyPath, nodeType, expanded) => ({\n        style: {\n          ...style,\n          textTransform: expanded ? 'uppercase' : style.textTransform,\n        },\n      }),\n    }}\n  />\n</div>\n```\n\n#### Customize Labels for Arrays, Objects, and Iterables\n\nYou can pass `getItemString` to customize the way arrays, objects, and iterable nodes are displayed (optional).\n\nBy default, it'll be:\n\n```jsx\n<JSONTree getItemString={(type, data, itemType, itemString, keyPath)\n  => <span>{itemType} {itemString}</span>}\n```\n\nBut if you pass the following:\n\n```jsx\nconst getItemString = (type, data, itemType, itemString, keyPath)\n  => (<span> // {type}</span>);\n```\n\nThen the preview of child elements now look like this:\n\n![](http://cl.ly/image/1J1a0b0T0K3c/screenshot%202015-10-07%20at%203.44.31%20PM.png)\n\n#### Customize Rendering\n\nYou can pass the following properties to customize rendered labels and values:\n\n```jsx\n<JSONTree\n  labelRenderer={([key]) => <strong>{key}</strong>}\n  valueRenderer={(raw) => <em>{raw}</em>}\n/>\n```\n\nIn this example the label and value will be rendered with `<strong>` and `<em>` wrappers respectively.\n\nFor `labelRenderer`, you can provide a full path - [see this PR](https://github.com/chibicode/react-json-tree/pull/32).\n\nTheir full signatures are:\n\n- `labelRenderer: function(keyPath, nodeType, expanded, expandable)`\n- `valueRenderer: function(valueAsString, value, ...keyPath)`\n\n#### More Options\n\n- `shouldExpandNodeInitially: function(keyPath, data, level)` - determines if node should be expanded when it first renders (root is expanded by default)\n- `hideRoot: boolean` - if `true`, the root node is hidden.\n- `sortObjectKeys: boolean | function(a, b)` - sorts object keys with compare function (optional). Isn't applied to iterable maps like `Immutable.Map`.\n- `postprocessValue: function(value)` - maps `value` to a new `value`\n- `isCustomNode: function(value)` - overrides the default object type detection and renders the value as a single value\n- `collectionLimit: number` - sets the number of nodes that will be rendered in a collection before rendering them in collapsed ranges\n- `keyPath: (string | number)[]` - overrides the initial key path for the root node (defaults to `[root]`)\n\n### Credits\n\n- All credits to [Dave Vedder](http://www.eskimospy.com/) ([veddermatic@gmail.com](mailto:veddermatic@gmail.com)), who wrote the original code as [JSONViewer](https://bitbucket.org/davevedder/react-json-viewer/).\n- Extracted from [redux-devtools](https://github.com/gaearon/redux-devtools), which contained ES6 + inline style port of [JSONViewer](https://bitbucket.org/davevedder/react-json-viewer/) by [Daniele Zannotti](http://www.github.com/dzannotti) ([dzannotti@me.com](mailto:dzannotti@me.com))\n- [Iterable support](https://github.com/gaearon/redux-devtools/pull/79) thanks to [Daniel K](https://github.com/FredyC).\n- npm package created by [Shu Uesugi](http://github.com/chibicode) ([shu@chibicode.com](mailto:shu@chibicode.com)) per [this issue](https://github.com/gaearon/redux-devtools/issues/85).\n- Improved and maintained by [Alexander Kuznetsov](https://github.com/alexkuz). The repository was merged into [`redux-devtools` monorepo](https://github.com/reduxjs/redux-devtools) from [`alexkuz/react-json-tree`](https://github.com/alexkuz/react-json-tree).\n\n### Similar Libraries\n\n- [react-treeview](https://github.com/chenglou/react-treeview)\n- [react-json-inspector](https://github.com/Lapple/react-json-inspector)\n- [react-object-inspector](https://github.com/xyc/react-object-inspector)\n- [react-json-view](https://github.com/mac-s-g/react-json-view)\n\n### License\n\nMIT\n"
  },
  {
    "path": "packages/react-json-tree/eslint.config.js",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTsReact from '../../eslint.ts.react.config.base.mjs';\nimport eslintTsReactJest from '../../eslint.ts.react.jest.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTsReact(import.meta.dirname),\n  ...eslintTsReactJest(import.meta.dirname),\n  {\n    ignores: ['examples', 'jest.config.ts', 'lib'],\n  },\n];\n"
  },
  {
    "path": "packages/react-json-tree/examples/CHANGELOG.md",
    "content": "# react-json-tree-example\n\n## 1.1.10\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - react-json-tree@0.20.0\n\n## 1.1.9\n\n### Patch Changes\n\n- Updated dependencies [bbb1a40]\n  - react-base16-styling@0.10.0\n  - react-json-tree@0.19.0\n\n## 1.1.8\n\n### Patch Changes\n\n- Updated dependencies [81926f32]\n  - react-json-tree@0.18.0\n\n## 1.1.7\n\n### Patch Changes\n\n- Updated dependencies [8a7eae4]\n  - react-json-tree@0.17.0\n"
  },
  {
    "path": "packages/react-json-tree/examples/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 Dan Abramov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/react-json-tree/examples/README.md",
    "content": "# react-hot-boilerplate\n\nThe minimal dev environment to enable live-editing React components.\n\n### Usage\n\n```\nnpm install\nnpm start\nopen http://localhost:3000\n```\n\nNow edit `src/App.js`.  \nYour changes will appear without reloading the browser like in [this video](http://vimeo.com/100010922).\n\n### Linting\n\nThis boilerplate project includes React-friendly ESLint configuration.\n\n```\nnpm run lint\n```\n\n### Using `0.0.0.0` as Host\n\nYou may want to change the host in `server.js` and `webpack.config.js` from `localhost` to `0.0.0.0` to allow access from same WiFi network. This is not enabled by default because it is reported to cause problems on Windows. This may also be useful if you're using a VM.\n\n### Missing Features\n\nThis boilerplate is purposefully simple to show the minimal configuration for React Hot Loader. For a real project, you'll want to add a separate config for production with hot reloading disabled and minification enabled. You'll also want to add a router, styles and maybe combine dev server with an existing server. This is out of scope of this boilerplate, but you may want to look into [other starter kits](https://github.com/gaearon/react-hot-loader/blob/master/docs/README.md#starter-kits).\n\n### Dependencies\n\n- React\n- Webpack\n- [webpack-dev-server](https://github.com/webpack/webpack-dev-server)\n- [babel-loader](https://github.com/babel/babel-loader)\n- [react-hot-loader](https://github.com/gaearon/react-hot-loader)\n\n### Resources\n\n- [Demo video](http://vimeo.com/100010922)\n- [react-hot-loader on Github](https://github.com/gaearon/react-hot-loader)\n- [Integrating JSX live reload into your workflow](http://gaearon.github.io/react-hot-loader/getstarted/)\n- [Troubleshooting guide](https://github.com/gaearon/react-hot-loader/blob/master/docs/Troubleshooting.md)\n- Ping dan_abramov on Twitter or #reactjs IRC\n"
  },
  {
    "path": "packages/react-json-tree/examples/eslint.config.mjs",
    "content": "import eslintJs from '../../../eslint.js.config.base.mjs';\nimport eslintTs from '../../../eslint.ts.react.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTs(\n    import.meta.dirname,\n    ['./src/**/*.ts', './src/**/*.tsx'],\n    ['./tsconfig.app.json'],\n  ),\n  ...eslintTs(\n    import.meta.dirname,\n    ['vite.config.ts'],\n    ['./tsconfig.node.json'],\n  ),\n  {\n    ignores: ['dist'],\n  },\n];\n"
  },
  {
    "path": "packages/react-json-tree/examples/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <title>Sample App</title>\n    <style>\n      body {\n        font-family:\n          SF UI Text,\n          Roboto,\n          Helvetica Neue,\n          Helvetica,\n          sans-serif;\n        font-size: 18px;\n        line-height: 1.5;\n      }\n    </style>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/index.tsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/react-json-tree/examples/package.json",
    "content": "{\n  \"private\": true,\n  \"name\": \"react-json-tree-example\",\n  \"version\": \"1.1.10\",\n  \"description\": \"React-Json-Tree example\",\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/react-json-tree/examples\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"tsc -b && vite build\",\n    \"preview\": \"vite preview\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc\"\n  },\n  \"dependencies\": {\n    \"immutable\": \"^5.1.5\",\n    \"react\": \"^19.2.4\",\n    \"react-base16-styling\": \"workspace:^\",\n    \"react-dom\": \"^19.2.4\",\n    \"react-json-tree\": \"workspace:^\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^24.12.0\",\n    \"@types/react\": \"^19.2.14\",\n    \"@types/react-dom\": \"^19.2.3\",\n    \"@vitejs/plugin-react\": \"^6.0.0\",\n    \"typescript\": \"~5.9.3\",\n    \"vite\": \"^8.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/react-json-tree/examples/src/App.tsx",
    "content": "import React from 'react';\nimport { Map } from 'immutable';\nimport { JSONTree, StylingValue } from 'react-json-tree';\n\nconst getLabelStyle: StylingValue = ({ style }, nodeType, expanded) => ({\n  style: {\n    ...style,\n    textTransform: expanded ? 'uppercase' : style!.textTransform,\n  },\n});\n\nconst getBoolStyle: StylingValue = ({ style }, nodeType) => ({\n  style: {\n    ...style,\n    border: nodeType === 'Boolean' ? '1px solid #DD3333' : style!.border,\n    borderRadius: nodeType === 'Boolean' ? 3 : style!.borderRadius,\n  },\n});\n\nconst getItemString = (type: string) => (\n  <span>\n    {' // '}\n    {type}\n  </span>\n);\n\nconst getValueLabelStyle: StylingValue = ({ style }, nodeType, keyPath) => ({\n  style: {\n    ...style,\n    color:\n      !Number.isNaN((keyPath as unknown[])[0]) &&\n      !(parseInt(keyPath as string, 10) % 2)\n        ? '#33F'\n        : style!.color,\n  },\n});\n\nconst longString =\n  'Loremipsumdolorsitamet,consecteturadipiscingelit.Namtempusipsumutfelisdignissimauctor.Maecenasodiolectus,finibusegetultricesvel,aliquamutelit.Loremipsumdolorsitamet,consecteturadipiscingelit.Namtempusipsumutfelisdignissimauctor.Maecenasodiolectus,finibusegetultricesvel,aliquamutelit.Loremipsumdolorsitamet,consecteturadipiscingelit.Namtempusipsumutfelisdignissimauctor.Maecenasodiolectus,finibusegetultricesvel,aliquamutelit.'; // eslint-disable-line max-len\n\nclass Custom {\n  value: unknown;\n\n  constructor(value: unknown) {\n    this.value = value;\n  }\n\n  get [Symbol.toStringTag]() {\n    return 'Custom';\n  }\n}\n\nconst data = {\n  array: [1, 2, 3],\n  emptyArray: [],\n  bool: true,\n  date: new Date(),\n  error: new Error(longString),\n  object: {\n    foo: {\n      bar: 'baz',\n      nested: {\n        moreNested: {\n          evenMoreNested: {\n            veryNested: {\n              insanelyNested: {\n                ridiculouslyDeepValue: 'Hello',\n              },\n            },\n          },\n        },\n      },\n    },\n    baz: undefined,\n    func: function User() {\n      // noop\n    },\n  },\n  emptyObject: {},\n  symbol: Symbol('value'),\n  // eslint-disable-next-line new-cap\n  immutable: Map<any, any>([\n    ['key', 'value'],\n    [{ objectKey: 'value' }, { objectKey: 'value' }],\n  ]),\n  map: new window.Map<any, any>([\n    ['key', 'value'],\n    [0, 'value'],\n    [{ objectKey: 'value' }, { objectKey: 'value' }],\n  ]),\n  weakMap: new window.WeakMap([\n    [{ objectKey: 'value' }, { objectKey: 'value' }],\n  ]),\n  set: new window.Set(['value', 0, { objectKey: 'value' }]),\n  weakSet: new window.WeakSet([\n    { objectKey: 'value1' },\n    { objectKey: 'value2' },\n  ]),\n  hugeArray: Array.from({ length: 10000 }).map((_, i) => `item #${i}`),\n  customProfile: {\n    avatar: new Custom('placehold.it/50x50'),\n    name: new Custom('Name'),\n  },\n  longString,\n};\n\nconst theme = {\n  scheme: 'monokai',\n  author: 'wimer hazenberg (http://www.monokai.nl)',\n  base00: '#272822',\n  base01: '#383830',\n  base02: '#49483e',\n  base03: '#75715e',\n  base04: '#a59f85',\n  base05: '#f8f8f2',\n  base06: '#f5f4f1',\n  base07: '#f9f8f5',\n  base08: '#f92672',\n  base09: '#fd971f',\n  base0A: '#f4bf75',\n  base0B: '#a6e22e',\n  base0C: '#a1efe4',\n  base0D: '#66d9ef',\n  base0E: '#ae81ff',\n  base0F: '#cc6633',\n};\n\nconst App = () => (\n  <div>\n    <JSONTree data={data} theme={theme} invertTheme />\n    <br />\n    <h3>Dark Theme</h3>\n    <JSONTree data={data} theme={theme} invertTheme={false} />\n    <br />\n    <h3>Hidden Root</h3>\n    <JSONTree data={data} theme={theme} hideRoot />\n    <br />\n    <h3>Base16 Greenscreen Theme</h3>\n    <JSONTree data={data} theme=\"greenscreen\" invertTheme={false} />\n    <h4>Inverted Theme</h4>\n    <JSONTree data={data} theme=\"greenscreen\" invertTheme />\n    <br />\n    <h3>Style Customization</h3>\n    <ul>\n      <li>\n        Label changes between uppercase/lowercase based on the expanded state.\n      </li>\n      <li>Array keys are styled based on their parity.</li>\n      <li>\n        The labels of objects, arrays, and iterables are customized as &quot;//\n        type&quot;.\n      </li>\n      <li>See code for details.</li>\n    </ul>\n    <div>\n      <JSONTree\n        data={data}\n        theme={{\n          extend: theme,\n          nestedNodeLabel: getLabelStyle,\n          value: getBoolStyle,\n          valueLabel: getValueLabelStyle,\n        }}\n        getItemString={getItemString}\n      />\n    </div>\n    <h3>More Fine Grained Rendering</h3>\n    <p>\n      Pass <code>labelRenderer</code> or <code>valueRenderer</code>.\n    </p>\n    <div>\n      <JSONTree\n        data={data}\n        theme={theme}\n        labelRenderer={([raw]) => <span>(({raw})):</span>}\n        valueRenderer={(raw) => (\n          <em>\n            <span role=\"img\" aria-label=\"mellow\">\n              😐\n            </span>{' '}\n            {raw as string}{' '}\n            <span role=\"img\" aria-label=\"mellow\">\n              😐\n            </span>\n          </em>\n        )}\n      />\n    </div>\n    <p>\n      Sort object keys with <code>sortObjectKeys</code> prop.\n    </p>\n    <div>\n      <JSONTree data={data} theme={theme} sortObjectKeys />\n    </div>\n    <p>Collapsed root node</p>\n    <div>\n      <JSONTree\n        data={data}\n        theme={theme}\n        shouldExpandNodeInitially={() => false}\n      />\n    </div>\n  </div>\n);\n\nexport default App;\n"
  },
  {
    "path": "packages/react-json-tree/examples/src/index.tsx",
    "content": "import { createRoot } from 'react-dom/client';\nimport React from 'react';\nimport App from './App.js';\n\nconst root = createRoot(document.getElementById('root')!);\nroot.render(<App />);\n"
  },
  {
    "path": "packages/react-json-tree/examples/tsconfig.app.json",
    "content": "{\n  \"extends\": \"../../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"noEmit\": true\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/react-json-tree/examples/tsconfig.json",
    "content": "{\n  \"files\": [],\n  \"references\": [\n    { \"path\": \"./tsconfig.app.json\" },\n    { \"path\": \"./tsconfig.node.json\" }\n  ]\n}\n"
  },
  {
    "path": "packages/react-json-tree/examples/tsconfig.node.json",
    "content": "{\n  \"extends\": \"../../../tsconfig.esm.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"node\"],\n    \"noEmit\": true\n  },\n  \"include\": [\"vite.config.ts\"]\n}\n"
  },
  {
    "path": "packages/react-json-tree/examples/vite.config.ts",
    "content": "import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\n// https://vite.dev/config/\nexport default defineConfig({\n  plugins: [react()],\n});\n"
  },
  {
    "path": "packages/react-json-tree/jest.config.ts",
    "content": "import { createDefaultEsmPreset, type JestConfigWithTsJest } from 'ts-jest';\n\nconst presetConfig = createDefaultEsmPreset({\n  tsconfig: 'tsconfig.test.json',\n});\n\nconst jestConfig: JestConfigWithTsJest = {\n  ...presetConfig,\n  moduleNameMapper: {\n    '^(\\\\.{1,2}/.*)\\\\.js$': '$1',\n  },\n};\n\nexport default jestConfig;\n"
  },
  {
    "path": "packages/react-json-tree/package.json",
    "content": "{\n  \"name\": \"react-json-tree\",\n  \"version\": \"0.20.0\",\n  \"description\": \"React JSON Viewer Component, Extracted from redux-devtools\",\n  \"keywords\": [\n    \"react\",\n    \"json viewer\"\n  ],\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/react-json-tree\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Shu Uesugi <shu@chibicode.com> (http://github.com/chibicode)\",\n  \"contributors\": [\n    \"Alexander Kuznetsov <alexkuz@gmail.com> (http://kuzya.org/)\",\n    \"Dave Vedder <veddermatic@gmail.com> (http://www.eskimospy.com/)\",\n    \"Daniele Zannotti <dzannotti@me.com> (http://www.github.com/dzannotti)\",\n    \"Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)\"\n  ],\n  \"files\": [\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": \"./lib/index.js\",\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"test\": \"node --experimental-vm-modules node_modules/jest/bin/jest.js\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run lint && pnpm run test\"\n  },\n  \"dependencies\": {\n    \"@types/lodash\": \"^4.17.24\",\n    \"react-base16-styling\": \"workspace:^\"\n  },\n  \"devDependencies\": {\n    \"@types/jest\": \"^30.0.0\",\n    \"@types/react\": \"^19.2.14\",\n    \"jest\": \"^30.3.0\",\n    \"react\": \"^19.2.4\",\n    \"rimraf\": \"^6.1.3\",\n    \"ts-jest\": \"^29.4.6\",\n    \"typescript\": \"~5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"@types/react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/react-json-tree/src/ItemRange.tsx",
    "content": "import React, { useCallback, useState } from 'react';\nimport JSONArrow from './JSONArrow.js';\nimport type { CircularCache, CommonInternalProps } from './types.js';\n\ninterface Props extends CommonInternalProps {\n  data: unknown;\n  nodeType: string;\n  from: number;\n  to: number;\n  renderChildNodes: (props: Props, from: number, to: number) => React.ReactNode;\n  circularCache: CircularCache;\n  level: number;\n}\n\nexport default function ItemRange(props: Props) {\n  const { styling, from, to, renderChildNodes, nodeType } = props;\n\n  const [expanded, setExpanded] = useState<boolean>(false);\n  const handleClick = useCallback(() => {\n    setExpanded(!expanded);\n  }, [expanded]);\n\n  return expanded ? (\n    <div {...styling('itemRange', expanded)}>\n      {renderChildNodes(props, from, to)}\n    </div>\n  ) : (\n    <div {...styling('itemRange', expanded)} onClick={handleClick}>\n      <JSONArrow\n        nodeType={nodeType}\n        styling={styling}\n        expanded={false}\n        onClick={handleClick}\n        arrowStyle=\"double\"\n      />\n      {`${from} ... ${to}`}\n    </div>\n  );\n}\n"
  },
  {
    "path": "packages/react-json-tree/src/JSONArrayNode.tsx",
    "content": "import React from 'react';\nimport JSONNestedNode from './JSONNestedNode.js';\nimport type { CommonInternalProps } from './types.js';\n\n// Returns the \"n Items\" string for this node,\n// generating and caching it if it hasn't been created yet.\nfunction createItemString(data: unknown) {\n  return `${(data as unknown[]).length} ${\n    (data as unknown[]).length !== 1 ? 'items' : 'item'\n  }`;\n}\n\ninterface Props extends CommonInternalProps {\n  data: unknown;\n  nodeType: string;\n}\n\n// Configures <JSONNestedNode> to render an Array\nexport default function JSONArrayNode({ data, ...props }: Props) {\n  return (\n    <JSONNestedNode\n      {...props}\n      data={data}\n      nodeType=\"Array\"\n      nodeTypeIndicator=\"[]\"\n      createItemString={createItemString}\n      expandable={(data as unknown[]).length > 0}\n    />\n  );\n}\n"
  },
  {
    "path": "packages/react-json-tree/src/JSONArrow.tsx",
    "content": "import React from 'react';\nimport type { StylingFunction } from 'react-base16-styling';\n\ninterface Props {\n  styling: StylingFunction;\n  arrowStyle?: 'single' | 'double';\n  expanded: boolean;\n  nodeType: string;\n  onClick: React.MouseEventHandler<HTMLDivElement>;\n}\n\nexport default function JSONArrow({\n  styling,\n  arrowStyle = 'single',\n  expanded,\n  nodeType,\n  onClick,\n}: Props) {\n  return (\n    <div {...styling('arrowContainer', arrowStyle)} onClick={onClick}>\n      <div {...styling(['arrow', 'arrowSign'], nodeType, expanded, arrowStyle)}>\n        {'\\u25B6'}\n        {arrowStyle === 'double' && (\n          <div {...styling(['arrowSign', 'arrowSignInner'])}>{'\\u25B6'}</div>\n        )}\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "packages/react-json-tree/src/JSONIterableNode.tsx",
    "content": "import React from 'react';\nimport JSONNestedNode from './JSONNestedNode.js';\nimport type { CommonInternalProps } from './types.js';\n\n// Returns the \"n Items\" string for this node,\n// generating and caching it if it hasn't been created yet.\nfunction createItemString(data: any, limit: number) {\n  let count = 0;\n  let hasMore = false;\n  if (Number.isSafeInteger(data.size)) {\n    count = data.size;\n  } else {\n    // eslint-disable-next-line no-unused-vars\n    for (const entry of data) {\n      if (limit && count + 1 > limit) {\n        hasMore = true;\n        break;\n      }\n      count += 1;\n    }\n  }\n  return `${hasMore ? '>' : ''}${count} ${count !== 1 ? 'entries' : 'entry'}`;\n}\n\ninterface Props extends CommonInternalProps {\n  data: unknown;\n  nodeType: string;\n}\n\n// Configures <JSONNestedNode> to render an iterable\nexport default function JSONIterableNode(props: Props) {\n  return (\n    <JSONNestedNode\n      {...props}\n      nodeType=\"Iterable\"\n      nodeTypeIndicator=\"()\"\n      createItemString={createItemString}\n      expandable\n    />\n  );\n}\n"
  },
  {
    "path": "packages/react-json-tree/src/JSONNestedNode.tsx",
    "content": "import React, { useCallback, useState } from 'react';\nimport JSONArrow from './JSONArrow.js';\nimport getCollectionEntries from './getCollectionEntries.js';\nimport JSONNode from './JSONNode.js';\nimport ItemRange from './ItemRange.js';\nimport type { CircularCache, CommonInternalProps } from './types.js';\n\n/**\n * Renders nested values (eg. objects, arrays, lists, etc.)\n */\n\nexport interface RenderChildNodesProps extends CommonInternalProps {\n  data: unknown;\n  nodeType: string;\n  circularCache: CircularCache;\n  level: number;\n}\n\ninterface Range {\n  from: number;\n  to: number;\n}\n\ninterface Entry {\n  key: string | number;\n  value: unknown;\n}\n\nfunction isRange(rangeOrEntry: Range | Entry): rangeOrEntry is Range {\n  return (rangeOrEntry as Range).to !== undefined;\n}\n\nfunction renderChildNodes(\n  props: RenderChildNodesProps,\n  from?: number,\n  to?: number,\n) {\n  const {\n    nodeType,\n    data,\n    collectionLimit,\n    circularCache,\n    keyPath,\n    postprocessValue,\n    sortObjectKeys,\n  } = props;\n  const childNodes: React.ReactNode[] = [];\n\n  getCollectionEntries(\n    nodeType,\n    data,\n    sortObjectKeys,\n    collectionLimit,\n    from,\n    to,\n  ).forEach((entry) => {\n    if (isRange(entry)) {\n      childNodes.push(\n        <ItemRange\n          {...props}\n          key={`ItemRange--${entry.from}-${entry.to}`}\n          from={entry.from}\n          to={entry.to}\n          renderChildNodes={renderChildNodes}\n        />,\n      );\n    } else {\n      const { key, value } = entry;\n      const isCircular = circularCache.includes(value);\n\n      childNodes.push(\n        <JSONNode\n          {...props}\n          {...{ postprocessValue, collectionLimit }}\n          key={`Node--${key}`}\n          keyPath={[key, ...keyPath]}\n          value={postprocessValue(value)}\n          circularCache={[...circularCache, value]}\n          isCircular={isCircular}\n          hideRoot={false}\n        />,\n      );\n    }\n  });\n\n  return childNodes;\n}\n\ninterface Props extends CommonInternalProps {\n  data: unknown;\n  nodeType: string;\n  nodeTypeIndicator: string;\n  createItemString: (data: unknown, collectionLimit: number) => string;\n  expandable: boolean;\n}\n\nexport default function JSONNestedNode(props: Props) {\n  const {\n    circularCache = [],\n    collectionLimit,\n    createItemString,\n    data,\n    expandable,\n    getItemString,\n    hideRoot,\n    isCircular,\n    keyPath,\n    labelRenderer,\n    level = 0,\n    nodeType,\n    nodeTypeIndicator,\n    shouldExpandNodeInitially,\n    styling,\n  } = props;\n\n  const [expanded, setExpanded] = useState<boolean>(\n    // calculate individual node expansion if necessary\n    isCircular ? false : shouldExpandNodeInitially(keyPath, data, level),\n  );\n\n  const handleClick = useCallback(() => {\n    if (expandable) setExpanded(!expanded);\n  }, [expandable, expanded]);\n\n  const renderedChildren =\n    expanded || (hideRoot && level === 0)\n      ? renderChildNodes({ ...props, circularCache, level: level + 1 })\n      : null;\n\n  const itemType = (\n    <span {...styling('nestedNodeItemType', expanded)}>\n      {nodeTypeIndicator}\n    </span>\n  );\n  const renderedItemString = getItemString(\n    nodeType,\n    data,\n    itemType,\n    createItemString(data, collectionLimit),\n    keyPath,\n  );\n  const stylingArgs = [keyPath, nodeType, expanded, expandable] as const;\n\n  return hideRoot ? (\n    <li {...styling('rootNode', ...stylingArgs)}>\n      <ul {...styling('rootNodeChildren', ...stylingArgs)}>\n        {renderedChildren}\n      </ul>\n    </li>\n  ) : (\n    <li {...styling('nestedNode', ...stylingArgs)}>\n      {expandable && (\n        <JSONArrow\n          styling={styling}\n          nodeType={nodeType}\n          expanded={expanded}\n          onClick={handleClick}\n        />\n      )}\n      <label\n        {...styling(['label', 'nestedNodeLabel'], ...stylingArgs)}\n        onClick={handleClick}\n      >\n        {labelRenderer(...stylingArgs)}\n      </label>\n      <span\n        {...styling('nestedNodeItemString', ...stylingArgs)}\n        onClick={handleClick}\n      >\n        {renderedItemString}\n      </span>\n      <ul {...styling('nestedNodeChildren', ...stylingArgs)}>\n        {renderedChildren}\n      </ul>\n    </li>\n  );\n}\n"
  },
  {
    "path": "packages/react-json-tree/src/JSONNode.tsx",
    "content": "import React from 'react';\nimport objType from './objType.js';\nimport JSONObjectNode from './JSONObjectNode.js';\nimport JSONArrayNode from './JSONArrayNode.js';\nimport JSONIterableNode from './JSONIterableNode.js';\nimport JSONValueNode from './JSONValueNode.js';\nimport type { CommonInternalProps } from './types.js';\n\ninterface Props extends CommonInternalProps {\n  value: unknown;\n}\n\nexport default function JSONNode({\n  getItemString,\n  keyPath,\n  labelRenderer,\n  styling,\n  value,\n  valueRenderer,\n  isCustomNode,\n  ...rest\n}: Props) {\n  const nodeType = isCustomNode(value) ? 'Custom' : objType(value);\n\n  const simpleNodeProps = {\n    getItemString,\n    key: keyPath[0],\n    keyPath,\n    labelRenderer,\n    nodeType,\n    styling,\n    value,\n    valueRenderer,\n  };\n\n  const nestedNodeProps = {\n    ...rest,\n    ...simpleNodeProps,\n    data: value,\n    isCustomNode,\n  };\n\n  switch (nodeType) {\n    case 'Object':\n    case 'Error':\n    case 'WeakMap':\n    case 'WeakSet':\n      return <JSONObjectNode {...nestedNodeProps} />;\n    case 'Array':\n      return <JSONArrayNode {...nestedNodeProps} />;\n    case 'Iterable':\n    case 'Map':\n    case 'Set':\n      return <JSONIterableNode {...nestedNodeProps} />;\n    case 'String':\n      return (\n        <JSONValueNode\n          {...simpleNodeProps}\n          valueGetter={(raw: string) => `\"${raw}\"`}\n        />\n      );\n    case 'Number':\n      return <JSONValueNode {...simpleNodeProps} />;\n    case 'Boolean':\n      return (\n        <JSONValueNode\n          {...simpleNodeProps}\n          valueGetter={(raw) => (raw ? 'true' : 'false')}\n        />\n      );\n    case 'Date':\n      return (\n        <JSONValueNode\n          {...simpleNodeProps}\n          valueGetter={(raw) => raw.toISOString()}\n        />\n      );\n    case 'Null':\n      return <JSONValueNode {...simpleNodeProps} valueGetter={() => 'null'} />;\n    case 'Undefined':\n      return (\n        <JSONValueNode {...simpleNodeProps} valueGetter={() => 'undefined'} />\n      );\n    case 'Function':\n    case 'Symbol':\n      return (\n        <JSONValueNode\n          {...simpleNodeProps}\n          valueGetter={(raw) => raw.toString()}\n        />\n      );\n    case 'Custom':\n      return <JSONValueNode {...simpleNodeProps} />;\n    default:\n      return (\n        <JSONValueNode\n          {...simpleNodeProps}\n          valueGetter={() => `<${nodeType}>`}\n        />\n      );\n  }\n}\n"
  },
  {
    "path": "packages/react-json-tree/src/JSONObjectNode.tsx",
    "content": "import React from 'react';\nimport JSONNestedNode from './JSONNestedNode.js';\nimport type { CommonInternalProps } from './types.js';\n\n// Returns the \"n Items\" string for this node,\n// generating and caching it if it hasn't been created yet.\nfunction createItemString(data: unknown) {\n  const len = Object.getOwnPropertyNames(data).length;\n  return `${len} ${len !== 1 ? 'keys' : 'key'}`;\n}\n\ninterface Props extends CommonInternalProps {\n  data: unknown;\n  nodeType: string;\n}\n\n// Configures <JSONNestedNode> to render an Object\nexport default function JSONObjectNode({ data, ...props }: Props) {\n  return (\n    <JSONNestedNode\n      {...props}\n      data={data}\n      nodeType=\"Object\"\n      nodeTypeIndicator={props.nodeType === 'Error' ? 'Error()' : '{}'}\n      createItemString={createItemString}\n      expandable={Object.getOwnPropertyNames(data).length > 0}\n    />\n  );\n}\n"
  },
  {
    "path": "packages/react-json-tree/src/JSONValueNode.tsx",
    "content": "import React from 'react';\nimport type {\n  GetItemString,\n  Key,\n  KeyPath,\n  LabelRenderer,\n  Styling,\n  ValueRenderer,\n} from './types.js';\n\n/**\n * Renders simple values (eg. strings, numbers, booleans, etc)\n */\n\ninterface Props {\n  getItemString: GetItemString;\n  key: Key;\n  keyPath: KeyPath;\n  labelRenderer: LabelRenderer;\n  nodeType: string;\n  styling: Styling;\n  value: unknown;\n  valueRenderer: ValueRenderer;\n  valueGetter?: (value: any) => unknown;\n}\n\nexport default function JSONValueNode({\n  nodeType,\n  styling,\n  labelRenderer,\n  keyPath,\n  valueRenderer,\n  value,\n  valueGetter = (value) => value,\n}: Props) {\n  return (\n    <li {...styling('value', nodeType, keyPath)}>\n      <label {...styling(['label', 'valueLabel'], nodeType, keyPath)}>\n        {labelRenderer(keyPath, nodeType, false, false)}\n      </label>\n      <span {...styling('valueText', nodeType, keyPath)}>\n        {valueRenderer(valueGetter(value), value, ...keyPath)}\n      </span>\n    </li>\n  );\n}\n"
  },
  {
    "path": "packages/react-json-tree/src/createStylingFromTheme.ts",
    "content": "import type { CurriedFunction1 } from 'lodash';\nimport { createStyling } from 'react-base16-styling';\nimport type {\n  Base16Theme,\n  StylingConfig,\n  StylingFunction,\n  Theme,\n} from 'react-base16-styling';\nimport solarized from './themes/solarized.js';\n\nconst colorMap = (theme: Base16Theme) => ({\n  BACKGROUND_COLOR: theme.base00,\n  TEXT_COLOR: theme.base07,\n  STRING_COLOR: theme.base0B,\n  DATE_COLOR: theme.base0B,\n  NUMBER_COLOR: theme.base09,\n  BOOLEAN_COLOR: theme.base09,\n  NULL_COLOR: theme.base08,\n  UNDEFINED_COLOR: theme.base08,\n  FUNCTION_COLOR: theme.base08,\n  SYMBOL_COLOR: theme.base08,\n  LABEL_COLOR: theme.base0D,\n  ARROW_COLOR: theme.base0D,\n  ITEM_STRING_COLOR: theme.base0B,\n  ITEM_STRING_EXPANDED_COLOR: theme.base03,\n});\n\ntype Color = keyof ReturnType<typeof colorMap>;\ntype Colors = {\n  [color in Color]: string;\n};\n\nconst valueColorMap = (colors: Colors) => ({\n  String: colors.STRING_COLOR,\n  Date: colors.DATE_COLOR,\n  Number: colors.NUMBER_COLOR,\n  Boolean: colors.BOOLEAN_COLOR,\n  Null: colors.NULL_COLOR,\n  Undefined: colors.UNDEFINED_COLOR,\n  Function: colors.FUNCTION_COLOR,\n  Symbol: colors.SYMBOL_COLOR,\n});\n\nconst getDefaultThemeStyling = (theme: Base16Theme): StylingConfig => {\n  const colors = colorMap(theme);\n\n  return {\n    tree: {\n      border: 0,\n      padding: 0,\n      marginTop: '0.5em',\n      marginBottom: '0.5em',\n      marginLeft: '0.125em',\n      marginRight: 0,\n      listStyle: 'none',\n      MozUserSelect: 'none',\n      WebkitUserSelect: 'none',\n      backgroundColor: colors.BACKGROUND_COLOR,\n    },\n\n    value: ({ style }, nodeType, keyPath) => ({\n      style: {\n        ...style,\n        paddingTop: '0.25em',\n        paddingRight: 0,\n        marginLeft: '0.875em',\n        WebkitUserSelect: 'text',\n        MozUserSelect: 'text',\n        wordWrap: 'break-word',\n        paddingLeft: (keyPath as unknown[]).length > 1 ? '2.125em' : '1.25em',\n        textIndent: '-0.5em',\n        wordBreak: 'break-all',\n      },\n    }),\n\n    label: {\n      display: 'inline-block',\n      color: colors.LABEL_COLOR,\n    },\n\n    valueLabel: {\n      margin: '0 0.5em 0 0',\n    },\n\n    valueText: ({ style }, nodeType) => ({\n      style: {\n        ...style,\n        color:\n          valueColorMap(colors)[\n            nodeType as keyof ReturnType<typeof valueColorMap>\n          ],\n      },\n    }),\n\n    itemRange: (styling, expanded) => ({\n      style: {\n        paddingTop: expanded ? 0 : '0.25em',\n        cursor: 'pointer',\n        color: colors.LABEL_COLOR,\n      },\n    }),\n\n    arrow: ({ style }, nodeType, expanded) => ({\n      style: {\n        ...style,\n        marginLeft: 0,\n        transition: '150ms',\n        WebkitTransition: '150ms',\n        MozTransition: '150ms',\n        WebkitTransform: expanded ? 'rotateZ(90deg)' : 'rotateZ(0deg)',\n        MozTransform: expanded ? 'rotateZ(90deg)' : 'rotateZ(0deg)',\n        transform: expanded ? 'rotateZ(90deg)' : 'rotateZ(0deg)',\n        transformOrigin: '45% 50%',\n        WebkitTransformOrigin: '45% 50%',\n        MozTransformOrigin: '45% 50%',\n        position: 'relative',\n        lineHeight: '1.1em',\n        fontSize: '0.75em',\n      },\n    }),\n\n    arrowContainer: ({ style }, arrowStyle) => ({\n      style: {\n        ...style,\n        display: 'inline-block',\n        paddingRight: '0.5em',\n        paddingLeft: arrowStyle === 'double' ? '1em' : 0,\n        cursor: 'pointer',\n      },\n    }),\n\n    arrowSign: {\n      color: colors.ARROW_COLOR,\n    },\n\n    arrowSignInner: {\n      position: 'absolute',\n      top: 0,\n      left: '-0.4em',\n    },\n\n    nestedNode: ({ style }, keyPath, nodeType, expanded, expandable) => ({\n      style: {\n        ...style,\n        position: 'relative',\n        paddingTop: '0.25em',\n        marginLeft: (keyPath as unknown[]).length > 1 ? '0.875em' : 0,\n        paddingLeft: !expandable ? '1.125em' : 0,\n      },\n    }),\n\n    rootNode: {\n      padding: 0,\n      margin: 0,\n    },\n\n    nestedNodeLabel: ({ style }, keyPath, nodeType, expanded, expandable) => ({\n      style: {\n        ...style,\n        margin: 0,\n        padding: 0,\n        WebkitUserSelect: expandable ? 'inherit' : 'text',\n        MozUserSelect: expandable ? 'inherit' : 'text',\n        cursor: expandable ? 'pointer' : 'default',\n      },\n    }),\n\n    nestedNodeItemString: ({ style }, keyPath, nodeType, expanded) => ({\n      style: {\n        ...style,\n        paddingLeft: '0.5em',\n        cursor: 'default',\n        color: expanded\n          ? colors.ITEM_STRING_EXPANDED_COLOR\n          : colors.ITEM_STRING_COLOR,\n      },\n    }),\n\n    nestedNodeItemType: {\n      marginLeft: '0.3em',\n      marginRight: '0.3em',\n    },\n\n    nestedNodeChildren: ({ style }, nodeType, expanded) => ({\n      style: {\n        ...style,\n        padding: 0,\n        margin: 0,\n        listStyle: 'none',\n        display: expanded ? 'block' : 'none',\n      },\n    }),\n\n    rootNodeChildren: {\n      padding: 0,\n      margin: 0,\n      listStyle: 'none',\n    },\n  };\n};\n\nconst createStylingFromTheme: CurriedFunction1<\n  Theme | undefined,\n  StylingFunction\n> = createStyling(getDefaultThemeStyling, {\n  defaultBase16: solarized,\n});\n\nexport default createStylingFromTheme;\n"
  },
  {
    "path": "packages/react-json-tree/src/getCollectionEntries.ts",
    "content": "import type { SortObjectKeys } from './types.js';\n\nfunction getLength(type: string, collection: unknown) {\n  if (type === 'Object') {\n    return Object.keys(collection as object).length;\n  } else if (type === 'Array') {\n    return (collection as unknown[]).length;\n  }\n\n  return Infinity;\n}\n\nfunction isIterableMap(collection: unknown) {\n  return typeof (collection as Map<unknown, unknown>).set === 'function';\n}\n\nfunction getEntries(\n  type: string,\n  collection: any,\n  sortObjectKeys: SortObjectKeys,\n  from = 0,\n  to = Infinity,\n): { entries: { key: string | number; value: unknown }[]; hasMore?: boolean } {\n  let res;\n\n  if (type === 'Object') {\n    let keys = Object.getOwnPropertyNames(collection);\n\n    if (sortObjectKeys) {\n      keys.sort(sortObjectKeys === true ? undefined : sortObjectKeys);\n    }\n\n    keys = keys.slice(from, to + 1);\n\n    res = {\n      entries: keys.map((key) => ({ key, value: collection[key] })),\n    };\n  } else if (type === 'Array') {\n    res = {\n      entries: collection\n        .slice(from, to + 1)\n        .map((val: unknown, idx: number) => ({ key: idx + from, value: val })),\n    };\n  } else {\n    let idx = 0;\n    const entries = [];\n    let done = true;\n\n    const isMap = isIterableMap(collection);\n\n    for (const item of collection) {\n      if (idx > to) {\n        done = false;\n        break;\n      }\n      if (from <= idx) {\n        if (isMap && Array.isArray(item)) {\n          if (typeof item[0] === 'string' || typeof item[0] === 'number') {\n            entries.push({ key: item[0], value: item[1] });\n          } else {\n            entries.push({\n              key: `[entry ${idx}]`,\n              value: {\n                '[key]': item[0],\n                '[value]': item[1],\n              },\n            });\n          }\n        } else {\n          entries.push({ key: idx, value: item });\n        }\n      }\n      idx++;\n    }\n\n    res = {\n      hasMore: !done,\n      entries,\n    };\n  }\n\n  return res;\n}\n\nfunction getRanges(from: number, to: number, limit: number) {\n  const ranges = [];\n  while (to - from > limit * limit) {\n    limit = limit * limit;\n  }\n  for (let i = from; i <= to; i += limit) {\n    ranges.push({ from: i, to: Math.min(to, i + limit - 1) });\n  }\n\n  return ranges;\n}\n\nexport default function getCollectionEntries(\n  type: string,\n  collection: unknown,\n  sortObjectKeys: SortObjectKeys,\n  limit: number,\n  from = 0,\n  to = Infinity,\n) {\n  const getEntriesBound = getEntries.bind(\n    null,\n    type,\n    collection,\n    sortObjectKeys,\n  );\n\n  if (!limit) {\n    return getEntriesBound().entries;\n  }\n\n  const isSubset = to < Infinity;\n  const length = Math.min(to - from, getLength(type, collection));\n\n  if (type !== 'Iterable') {\n    if (length <= limit || limit < 7) {\n      return getEntriesBound(from, to).entries;\n    }\n  } else {\n    if (length <= limit && !isSubset) {\n      return getEntriesBound(from, to).entries;\n    }\n  }\n\n  let limitedEntries;\n  if (type === 'Iterable') {\n    const { hasMore, entries } = getEntriesBound(from, from + limit - 1);\n\n    limitedEntries = hasMore\n      ? [...entries, ...getRanges(from + limit, from + 2 * limit - 1, limit)]\n      : entries;\n  } else {\n    limitedEntries = isSubset\n      ? getRanges(from, to, limit)\n      : [\n          ...getEntriesBound(0, limit - 5).entries,\n          ...getRanges(limit - 4, length - 5, limit),\n          ...getEntriesBound(length - 4, length - 1).entries,\n        ];\n  }\n\n  return limitedEntries;\n}\n"
  },
  {
    "path": "packages/react-json-tree/src/index.tsx",
    "content": "// ES6 + inline style port of JSONViewer https://bitbucket.org/davevedder/react-json-viewer/\n// all credits and original code to the author\n// Dave Vedder <veddermatic@gmail.com> http://www.eskimospy.com/\n// port by Daniele Zannotti http://www.github.com/dzannotti <dzannotti@me.com>\n\nimport React, { useMemo } from 'react';\nimport { invertTheme } from 'react-base16-styling';\nimport type { StylingValue, Theme } from 'react-base16-styling';\nimport JSONNode from './JSONNode.js';\nimport createStylingFromTheme from './createStylingFromTheme.js';\nimport type {\n  CommonExternalProps,\n  GetItemString,\n  IsCustomNode,\n  LabelRenderer,\n  ShouldExpandNodeInitially,\n} from './types.js';\n\ninterface Props extends Partial<CommonExternalProps> {\n  data: unknown;\n  theme?: Theme;\n  invertTheme?: boolean;\n}\n\nconst identity = (value: any) => value;\nconst expandRootNode: ShouldExpandNodeInitially = (keyPath, data, level) =>\n  level === 0;\nconst defaultItemString: GetItemString = (type, data, itemType, itemString) => (\n  <span>\n    {itemType} {itemString}\n  </span>\n);\nconst defaultLabelRenderer: LabelRenderer = ([label]) => <span>{label}:</span>;\nconst noCustomNode: IsCustomNode = () => false;\n\nexport function JSONTree({\n  data: value,\n  theme,\n  invertTheme: shouldInvertTheme,\n  keyPath = ['root'],\n  labelRenderer = defaultLabelRenderer,\n  valueRenderer = identity,\n  shouldExpandNodeInitially = expandRootNode,\n  hideRoot = false,\n  getItemString = defaultItemString,\n  postprocessValue = identity,\n  isCustomNode = noCustomNode,\n  collectionLimit = 50,\n  sortObjectKeys = false,\n}: Props) {\n  const styling = useMemo(\n    () =>\n      createStylingFromTheme(shouldInvertTheme ? invertTheme(theme) : theme),\n    [theme, shouldInvertTheme],\n  );\n\n  return (\n    <ul {...styling('tree')}>\n      <JSONNode\n        keyPath={hideRoot ? [] : keyPath}\n        value={postprocessValue(value)}\n        isCustomNode={isCustomNode}\n        styling={styling}\n        labelRenderer={labelRenderer}\n        valueRenderer={valueRenderer}\n        shouldExpandNodeInitially={shouldExpandNodeInitially}\n        hideRoot={hideRoot}\n        getItemString={getItemString}\n        postprocessValue={postprocessValue}\n        collectionLimit={collectionLimit}\n        sortObjectKeys={sortObjectKeys}\n      />\n    </ul>\n  );\n}\n\nexport type {\n  Key,\n  KeyPath,\n  GetItemString,\n  LabelRenderer,\n  ValueRenderer,\n  ShouldExpandNodeInitially,\n  PostprocessValue,\n  IsCustomNode,\n  SortObjectKeys,\n  Styling,\n  CommonExternalProps,\n} from './types.js';\nexport type { StylingValue };\n"
  },
  {
    "path": "packages/react-json-tree/src/objType.ts",
    "content": "export default function objType(obj: any) {\n  const type = Object.prototype.toString.call(obj).slice(8, -1);\n  if (type === 'Object' && typeof obj[Symbol.iterator] === 'function') {\n    return 'Iterable';\n  }\n\n  if (\n    type === 'Custom' &&\n    obj.constructor !== Object &&\n    obj instanceof Object\n  ) {\n    // For projects implementing objects overriding `.prototype[Symbol.toStringTag]`\n    return 'Object';\n  }\n\n  return type;\n}\n"
  },
  {
    "path": "packages/react-json-tree/src/themes/solarized.ts",
    "content": "export default {\n  scheme: 'solarized',\n  author: 'ethan schoonover (http://ethanschoonover.com/solarized)',\n  base00: '#002b36',\n  base01: '#073642',\n  base02: '#586e75',\n  base03: '#657b83',\n  base04: '#839496',\n  base05: '#93a1a1',\n  base06: '#eee8d5',\n  base07: '#fdf6e3',\n  base08: '#dc322f',\n  base09: '#cb4b16',\n  base0A: '#b58900',\n  base0B: '#859900',\n  base0C: '#2aa198',\n  base0D: '#268bd2',\n  base0E: '#6c71c4',\n  base0F: '#d33682',\n};\n"
  },
  {
    "path": "packages/react-json-tree/src/types.ts",
    "content": "import React from 'react';\nimport { StylingFunction } from 'react-base16-styling';\n\nexport type Key = string | number;\n\nexport type KeyPath = readonly (string | number)[];\n\nexport type GetItemString = (\n  nodeType: string,\n  data: unknown,\n  itemType: React.ReactNode,\n  itemString: string,\n  keyPath: KeyPath,\n) => React.ReactNode;\n\nexport type LabelRenderer = (\n  keyPath: KeyPath,\n  nodeType: string,\n  expanded: boolean,\n  expandable: boolean,\n) => React.ReactNode;\n\nexport type ValueRenderer = (\n  valueAsString: unknown,\n  value: unknown,\n  ...keyPath: KeyPath\n) => React.ReactNode;\n\nexport type ShouldExpandNodeInitially = (\n  keyPath: KeyPath,\n  data: unknown,\n  level: number,\n) => boolean;\n\nexport type PostprocessValue = (value: unknown) => unknown;\n\nexport type IsCustomNode = (value: unknown) => boolean;\n\nexport type SortObjectKeys = ((a: unknown, b: unknown) => number) | boolean;\n\nexport type Styling = StylingFunction;\n\nexport type CircularCache = unknown[];\n\nexport interface CommonExternalProps {\n  keyPath: KeyPath;\n  labelRenderer: LabelRenderer;\n  valueRenderer: ValueRenderer;\n  shouldExpandNodeInitially: ShouldExpandNodeInitially;\n  hideRoot: boolean;\n  getItemString: GetItemString;\n  postprocessValue: PostprocessValue;\n  isCustomNode: IsCustomNode;\n  collectionLimit: number;\n  sortObjectKeys: SortObjectKeys;\n}\n\nexport interface CommonInternalProps extends CommonExternalProps {\n  styling: StylingFunction;\n  circularCache?: CircularCache;\n  level?: number;\n  isCircular?: boolean;\n}\n"
  },
  {
    "path": "packages/react-json-tree/test/objType.spec.ts",
    "content": "import objType from '../src/objType.js';\n\ndescribe('objType', () => {\n  it('should determine the correct type', () => {\n    expect(objType({})).toBe('Object');\n    expect(objType([])).toBe('Array');\n    expect(objType(new Map())).toBe('Map');\n    expect(objType(new WeakMap())).toBe('WeakMap');\n    expect(objType(new Set())).toBe('Set');\n    expect(objType(new WeakSet())).toBe('WeakSet');\n    expect(objType(new Error())).toBe('Error');\n    expect(objType(new Date())).toBe('Date');\n    expect(\n      objType(() => {\n        // noop\n      }),\n    ).toBe('Function');\n    expect(objType('')).toBe('String');\n    expect(objType(true)).toBe('Boolean');\n    expect(objType(null)).toBe('Null');\n    expect(objType(undefined)).toBe('Undefined');\n    expect(objType(10)).toBe('Number');\n    expect(objType(Symbol.iterator)).toBe('Symbol');\n  });\n});\n"
  },
  {
    "path": "packages/react-json-tree/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/react-json-tree/tsconfig.test.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"jest\"]\n  },\n  \"include\": [\"src\", \"test\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools/CHANGELOG.md",
    "content": "# Change Log\n\n## 5.0.0\n\n### Major Changes\n\n- 804d6bd: Convert @redux-devtools/core to ESM\n\n### Patch Changes\n\n- Updated dependencies [3f90241]\n  - @redux-devtools/instrument@3.0.0\n\n## 4.1.1\n\n### Patch Changes\n\n- 91f21b2: Fix compatibility of createDevTools with React 19 types\n\n## 4.1.0\n\n### Minor Changes\n\n- 6830118: Add React 19 to peer deps\n\n## 4.0.0\n\n### Major Changes\n\n- decc035: Remove support for legacy context. Minimum supported react-redux version is 7.0.0 and minimum support React version is 16.8.4.\n\n## 3.14.0\n\n### Minor Changes\n\n- 6fc18ed7: Add new Redux version to peer dependencies\n\n### Patch Changes\n\n- 7f5bddbd: Widen peer dependencies\n- Updated dependencies [6fc18ed7]\n  - @redux-devtools/instrument@2.2.0\n\n## 3.13.3\n\n### Patch Changes\n\n- 42531c50: Bump versions\n- Updated dependencies [42531c50]\n  - @redux-devtools/instrument@2.1.1\n\n## 3.13.2\n\n### Patch Changes\n\n- 65205f90: Replace Action<unknown> with Action<string>\n\n## 3.13.1\n\n### Patch Changes\n\n- a55ba302: Fix peer dependencies on @redux-devtools/core\n\n## 3.13.0\n\n### Minor Changes\n\n- 8a7eae4: Add React 18 to peerDependencies range\n\n## 3.12.0\n\n### Minor Changes\n\n- 4891bf6: Add react-redux v8 to peerDependencies range\n\n## [3.9.0](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/core@3.8.0...@redux-devtools/core@3.9.0) (2021-03-06)\n\n### Features\n\n- update peer dependencies to allow react@^17 ([#703](https://github.com/reduxjs/redux-devtools/issues/703)) ([2aaa9c1](https://github.com/reduxjs/redux-devtools/commit/2aaa9c10a383e3a7ab20b3ab14639781fd7bb2eb))\n\n## 3.8.0 (2021-03-06)\n\n### Bug Fixes\n\n- **redux-devtools:** type MonitorState should extend LiftedState ([#612](https://github.com/reduxjs/redux-devtools/issues/612)) ([47af8c9](https://github.com/reduxjs/redux-devtools/commit/47af8c98ce87fa115d093e2c578a0cd48c058792))\n\n### Features\n\n- **redux-devtools:** add more exported types ([#611](https://github.com/reduxjs/redux-devtools/issues/611)) ([0f51992](https://github.com/reduxjs/redux-devtools/commit/0f51992b0bac12c1334966e8f99a66681bdae8d6))\n- **redux-devtools:** convert counter example to TypeScript ([#616](https://github.com/reduxjs/redux-devtools/issues/616)) ([f1e3f4f](https://github.com/reduxjs/redux-devtools/commit/f1e3f4f8340dea288de5229006acf9dc1ef1cccf))\n- **redux-devtools:** convert todomvc example to TypeScript ([#618](https://github.com/reduxjs/redux-devtools/issues/618)) ([37191e4](https://github.com/reduxjs/redux-devtools/commit/37191e46e600cd9ac2839f0687efb347fc4ef7c1))\n- **redux-devtools:** export more types ([#615](https://github.com/reduxjs/redux-devtools/issues/615)) ([c154405](https://github.com/reduxjs/redux-devtools/commit/c154405c6c2448743040d0d7cfa9e8463b647a14))\n- **redux-devtools-slider-monitor:** convert example to TypeScript ([#632](https://github.com/reduxjs/redux-devtools/issues/632)) ([ec75d3a](https://github.com/reduxjs/redux-devtools/commit/ec75d3a4b62d0f4b8d52a739a7727142421cc261))\n\n## 3.6.0 (2020-07-28)\n\n## 3.5.0 (2018-12-21)\n\n## [3.7.0](https://github.com/reduxjs/redux-devtools/compare/redux-devtools@3.6.1...redux-devtools@3.7.0) (2020-09-07)\n\n### Bug Fixes\n\n- **redux-devtools:** type MonitorState should extend LiftedState ([#612](https://github.com/reduxjs/redux-devtools/issues/612)) ([47af8c9](https://github.com/reduxjs/redux-devtools/commit/47af8c98ce87fa115d093e2c578a0cd48c058792))\n\n### Features\n\n- **redux-devtools:** add more exported types ([#611](https://github.com/reduxjs/redux-devtools/issues/611)) ([0f51992](https://github.com/reduxjs/redux-devtools/commit/0f51992b0bac12c1334966e8f99a66681bdae8d6))\n- **redux-devtools:** convert counter example to TypeScript ([#616](https://github.com/reduxjs/redux-devtools/issues/616)) ([f1e3f4f](https://github.com/reduxjs/redux-devtools/commit/f1e3f4f8340dea288de5229006acf9dc1ef1cccf))\n- **redux-devtools:** convert todomvc example to TypeScript ([#618](https://github.com/reduxjs/redux-devtools/issues/618)) ([37191e4](https://github.com/reduxjs/redux-devtools/commit/37191e46e600cd9ac2839f0687efb347fc4ef7c1))\n- **redux-devtools:** export more types ([#615](https://github.com/reduxjs/redux-devtools/issues/615)) ([c154405](https://github.com/reduxjs/redux-devtools/commit/c154405c6c2448743040d0d7cfa9e8463b647a14))\n\n## [3.6.1](https://github.com/reduxjs/redux-devtools/compare/redux-devtools@3.6.0...redux-devtools@3.6.1) (2020-08-14)\n\n**Note:** Version bump only for package redux-devtools\n"
  },
  {
    "path": "packages/redux-devtools/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Dan Abramov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/redux-devtools/README.md",
    "content": "# Redux DevTools\n\nA live-editing time travel environment for [Redux](https://github.com/reactjs/redux).  \n**[See Dan's React Europe talk demoing it!](http://youtube.com/watch?v=xsSnOQynTHs)**\n\n> Note that the implemention in this repository is different from [Redux DevTools Extension](https://github.com/zalmoxisus/redux-devtools-extension). Please refer to the latter for browser extension.\n\n### Table of Contents\n\n- [Features](#features)\n- [Overview](#overview)\n- [Browser Extension](#browser-extension)\n- [Setup Instructions](#setup-instructions)\n- [Custom Monitors](#custom-monitors)\n- [License](#license)\n\n[![npm version](https://img.shields.io/npm/v/redux-devtools.svg?style=flat-square)](https://www.npmjs.com/package/redux-devtools)\n[![npm downloads](https://img.shields.io/npm/dm/redux-devtools.svg?style=flat-square)](https://www.npmjs.com/package/redux-devtools)\n[![redux channel on discord](https://img.shields.io/badge/discord-redux@reactiflux-738bd7.svg?style=flat-square)](https://discord.gg/0ZcbPKXt5bWb10Ma)\n\n![](http://i.imgur.com/J4GeW0M.gif)\n\n### Features\n\n- Lets you inspect every state and action payload\n- Lets you go back in time by “cancelling” actions\n- If you change the reducer code, each “staged” action will be re-evaluated\n- If the reducers throw, you will see during which action this happened, and what the error was\n- With `persistState()` store enhancer, you can persist debug sessions across page reloads\n\n### Overview\n\nRedux DevTools is a development time package that provides power-ups for your Redux development workflow. Be careful to strip its code in production (see [walkthrough](../../docs/Walkthrough.md) for instructions)! To use Redux DevTools, you need to choose a “monitor”—a React component that will serve as a UI for the DevTools. Different tasks and workflows require different UIs, so Redux DevTools is built to be flexible in this regard. We recommend using [`LogMonitor`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-log-monitor) for inspecting the state and time travel, and wrap it in a [`DockMonitor`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-dock-monitor) to quickly move it across the screen. That said, when you’re comfortable rolling up your own setup, feel free to do this, and share it with us.\n\nIf you came here looking for what do the “Reset”, “Revert”, “Sweep” or “Commit” buttons do, check out [the `LogMonitor` documentation](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-log-monitor#features).\n\n### Browser Extension\n\nIf you don’t want to bother with installing Redux DevTools and integrating it into your project, consider using [Redux DevTools Extension](https://github.com/zalmoxisus/redux-devtools-extension) for Chrome and Firefox. It provides access to the most popular monitors, is easy to configure to filter actions, and doesn’t require installing any packages.\n\n### Setup Instructions\n\nRead the installation [walkthrough](../../docs/Walkthrough.md) for integration instructions and usage examples (`<DevTools>` component, `DevTools.instrument()`, exclude from production builds, gotchas).\n\n### Running Examples\n\nClone the project:\n\n```\ngit clone https://github.com/reduxjs/redux-devtools.git\ncd redux-devtools/packages/redux-devtools\n```\n\nRun `npm install` in the package folder:\n\n```\nnpm install\n```\n\nNow you can open an example folder and run `npm install` there:\n\n```\ncd examples/counter # or examples/todomvc\nnpm install\n```\n\nFinally, run the development server and open the page:\n\n```\nnpm start\nopen http://localhost:3000\n```\n\nTry clicking on actions in the log, or changing some code inside the reducers. You should see the action log re-evaluate the state on every code change.\n\nAlso try opening `http://localhost:3000/?debug_session=123`, click around, and then refresh. You should see that all actions have been restored from the local storage.\n\n### Custom Monitors\n\n**DevTools accepts monitor components so you can build a completely custom UI.** [`LogMonitor`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-log-monitor) and [`DockMonitor`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-dock-monitor) are just examples of what is possible.\n\n**[I challenge you to build a custom monitor for Redux DevTools!](https://github.com/reduxjs/redux-devtools/issues/3)**\n\nSome crazy ideas for custom monitors:\n\n- A slider that lets you jump between computed states just by dragging it\n- An in-app layer that shows the last N states right in the app (e.g. for animation)\n- A time machine like interface where the last N states of your app reside on different Z layers\n- Feel free to come up with and implement your own! Check [`LogMonitor`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-log-monitor) `propTypes` to see what you can do.\n\nIn fact some of these are implemented already:\n\n#### [Slider Monitor](https://github.com/reduxjs/redux-devtools/packages/redux-devtools-slider-monitor)\n\n![](https://camo.githubusercontent.com/47a3f427c9d2e0c763b74e33417b3001fe8604b6/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f662e636c2e6c792f6974656d732f3149335032323243334e3252314d3279314b33622f53637265656e2532305265636f7264696e67253230323031352d31322d3232253230617425323030372e3230253230504d2e6769663f763d3162363236376537)\n\n#### [Inspector Monitor](https://github.com/reduxjs/redux-devtools/packages/redux-devtools-inspector-monitor)\n\n![](http://i.imgur.com/fYh8fk5.gif)\n\n#### [Diff Monitor](https://github.com/whetstone/redux-devtools-diff-monitor)\n\n![](https://camo.githubusercontent.com/c2c0ba1ad82d003b5386404ae09c00763d73510c/687474703a2f2f692e696d6775722e636f6d2f72764352394f512e706e67)\n\n#### [Filterable Log Monitor](https://github.com/bvaughn/redux-devtools-filterable-log-monitor/)\n\n![redux-devtools-filterable-log-monitor](https://cloud.githubusercontent.com/assets/29597/12440009/182bb31c-beec-11e5-8fd0-bdda48e646b2.gif)\n\n#### [Chart Monitor](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-chart-monitor)\n\n![redux-devtools-chart-monitor](http://i.imgur.com/MSgvU6l.gif)\n\n#### [Filter Actions](https://github.com/zalmoxisus/redux-devtools-filter-actions)\n\n(Does not have a UI but can wrap any other monitor)\n\n<img src='http://i.imgur.com/TlqnU0J.png' width='400'>\n\n#### [Dispatch](https://github.com/YoruNoHikage/redux-devtools-dispatch)\n\n![redux-devtools-dispatch](https://cloud.githubusercontent.com/assets/969003/12874321/2c3624ec-cdd2-11e5-9856-fd7e24efb8d5.gif)\n\n#### [Redux Usage Report](https://github.com/aholachek/redux-usage-report)\n\n![redux-usage-report](https://furtive-discussion.surge.sh/redux-usage-monitor.gif)\n\n#### Keep them coming!\n\nCreate a PR to add your custom monitor.\n\n### License\n\nMIT\n"
  },
  {
    "path": "packages/redux-devtools/eslint.config.mjs",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTsReact from '../../eslint.ts.react.config.base.mjs';\nimport eslintTsReactJest from '../../eslint.ts.react.jest.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTsReact(import.meta.dirname),\n  ...eslintTsReactJest(import.meta.dirname),\n  {\n    ignores: ['examples', 'jest.config.ts', 'lib'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/CHANGELOG.md",
    "content": "# counter-redux\n\n## 0.1.13\n\n### Patch Changes\n\n- Updated dependencies [12849a4]\n- Updated dependencies [804d6bd]\n  - @redux-devtools/dock-monitor@5.0.0\n  - @redux-devtools/log-monitor@6.0.0\n  - @redux-devtools/core@5.0.0\n\n## 0.1.12\n\n### Patch Changes\n\n- Updated dependencies [91f21b2]\n  - @redux-devtools/core@4.1.1\n  - @redux-devtools/dock-monitor@4.1.1\n  - @redux-devtools/log-monitor@5.1.1\n\n## 0.1.11\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - @redux-devtools/dock-monitor@5.0.0\n  - @redux-devtools/log-monitor@6.0.0\n  - @redux-devtools/core@4.1.0\n\n## 0.1.10\n\n### Patch Changes\n\n- Updated dependencies [5cfe3e5]\n- Updated dependencies [decc035]\n  - @redux-devtools/dock-monitor@4.0.0\n  - @redux-devtools/log-monitor@5.0.0\n  - @redux-devtools/core@4.0.0\n\n## 0.1.9\n\n### Patch Changes\n\n- Updated dependencies [8a7eae4]\n  - @redux-devtools/dock-monitor@3.0.0\n  - @redux-devtools/log-monitor@4.0.0\n  - @redux-devtools/core@3.13.0\n\n## 0.1.8\n\n### Patch Changes\n\n- Updated dependencies [4891bf6]\n  - @redux-devtools/core@3.12.0\n  - @redux-devtools/dock-monitor@2.1.1\n  - @redux-devtools/log-monitor@3.1.1\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/README.md",
    "content": "# Redux DevTools Counter example\n\n## Running Example\n\nFirst, clone the project:\n\n```\ngit clone https://github.com/reduxjs/redux-devtools.git\n```\n\nThen install the dependencies in the package folder:\n\n```\ncd redux-devtools/packages/redux-devtools\nnpm install\n```\n\nInstall the dependencies in the example folder:\n\n```\ncd examples/counter\nnpm install\n```\n\nFinally, run the project:\n\n```\nnpm start\nopen http://localhost:3000\n```\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/eslint.config.mjs",
    "content": "import eslintJs from '../../../../eslint.js.config.base.mjs';\nimport eslintTs from '../../../../eslint.ts.react.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTs(import.meta.dirname),\n  ...eslintTs(\n    import.meta.dirname,\n    ['webpack.config.ts'],\n    ['./tsconfig.webpack.json'],\n  ),\n  {\n    ignores: ['dist'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/index.html",
    "content": "<html>\n  <head>\n    <title>Redux Counter Example</title>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/package.json",
    "content": "{\n  \"private\": true,\n  \"name\": \"counter-redux\",\n  \"version\": \"0.1.13\",\n  \"description\": \"Counter example for redux\",\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools/examples/counter\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"start\": \"cross-env TS_NODE_PROJECT=\\\"tsconfig.webpack.json\\\" webpack serve --open\",\n    \"build\": \"cross-env TS_NODE_PROJECT=\\\"tsconfig.webpack.json\\\" webpack\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\"\n  },\n  \"dependencies\": {\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@redux-devtools/dock-monitor\": \"workspace:^\",\n    \"@redux-devtools/log-monitor\": \"workspace:^\",\n    \"react\": \"^19.2.4\",\n    \"react-dom\": \"^19.2.4\",\n    \"react-redux\": \"^9.2.0\",\n    \"redux\": \"^5.0.1\",\n    \"redux-thunk\": \"^3.1.0\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.29.0\",\n    \"@babel/preset-env\": \"^7.29.0\",\n    \"@babel/preset-react\": \"^7.28.5\",\n    \"@babel/preset-typescript\": \"^7.28.5\",\n    \"@types/node\": \"^24.12.0\",\n    \"@types/react\": \"^19.2.14\",\n    \"@types/react-dom\": \"^19.2.3\",\n    \"@types/webpack-env\": \"^1.18.8\",\n    \"babel-loader\": \"^10.1.1\",\n    \"cross-env\": \"^10.1.0\",\n    \"fork-ts-checker-webpack-plugin\": \"^9.1.0\",\n    \"html-webpack-plugin\": \"^5.6.6\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"~5.9.3\",\n    \"webpack\": \"^5.105.4\",\n    \"webpack-cli\": \"^7.0.0\",\n    \"webpack-dev-server\": \"^5.2.3\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/src/actions/CounterActions.ts",
    "content": "import { ThunkAction } from 'redux-thunk';\nimport { INCREMENT_COUNTER, DECREMENT_COUNTER } from '../constants/ActionTypes';\nimport { CounterState } from '../reducers';\n\ninterface IncrementCounterAction {\n  type: typeof INCREMENT_COUNTER;\n}\nexport function increment(): IncrementCounterAction {\n  return {\n    type: INCREMENT_COUNTER,\n  };\n}\n\ninterface DecrementCounterAction {\n  type: typeof DECREMENT_COUNTER;\n}\nexport function decrement(): DecrementCounterAction {\n  return {\n    type: DECREMENT_COUNTER,\n  };\n}\n\nexport type CounterAction = IncrementCounterAction | DecrementCounterAction;\n\nexport function incrementIfOdd(): ThunkAction<\n  void,\n  CounterState,\n  never,\n  CounterAction\n> {\n  return (dispatch, getState) => {\n    const { counter } = getState();\n\n    if (counter % 2 === 0) {\n      return;\n    }\n\n    dispatch(increment());\n  };\n}\n\nexport function incrementAsync(): ThunkAction<\n  void,\n  CounterState,\n  never,\n  CounterAction\n> {\n  return (dispatch) => {\n    setTimeout(() => {\n      dispatch(increment());\n    }, 1000);\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/src/components/Counter.tsx",
    "content": "import React, { Component } from 'react';\n\ninterface Props {\n  increment: () => void;\n  incrementIfOdd: () => void;\n  decrement: () => void;\n  counter: number;\n}\n\nexport default class Counter extends Component<Props> {\n  render() {\n    const { increment, incrementIfOdd, decrement, counter } = this.props;\n    return (\n      <p>\n        Clicked: {counter} times <button onClick={increment}>+</button>{' '}\n        <button onClick={decrement}>-</button>{' '}\n        <button onClick={incrementIfOdd}>Increment if odd</button>\n      </p>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/src/constants/ActionTypes.ts",
    "content": "export const INCREMENT_COUNTER = 'INCREMENT_COUNTER';\nexport const DECREMENT_COUNTER = 'DECREMENT_COUNTER';\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/src/containers/CounterApp.tsx",
    "content": "import React, { Component } from 'react';\nimport { bindActionCreators, Dispatch } from 'redux';\nimport { connect } from 'react-redux';\nimport Counter from '../components/Counter';\nimport * as CounterActions from '../actions/CounterActions';\nimport { CounterAction } from '../actions/CounterActions';\nimport { CounterState } from '../reducers';\n\ninterface Props {\n  counter: number;\n  dispatch: Dispatch<CounterAction>;\n}\n\nclass CounterApp extends Component<Props> {\n  render() {\n    const { counter, dispatch } = this.props;\n    return (\n      <Counter\n        counter={counter}\n        {...bindActionCreators(CounterActions, dispatch)}\n      />\n    );\n  }\n}\n\nfunction select(state: CounterState) {\n  return {\n    counter: state.counter,\n  };\n}\n\nexport default connect(select)(CounterApp);\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/src/containers/DevTools.tsx",
    "content": "import React from 'react';\nimport { createDevTools } from '@redux-devtools/core';\nimport { LogMonitor } from '@redux-devtools/log-monitor';\nimport { DockMonitor } from '@redux-devtools/dock-monitor';\n\nexport default createDevTools(\n  <DockMonitor toggleVisibilityKey=\"ctrl-h\" changePositionKey=\"ctrl-q\">\n    <LogMonitor />\n  </DockMonitor>,\n);\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/src/containers/Root.dev.tsx",
    "content": "import React, { Component } from 'react';\nimport { Provider } from 'react-redux';\nimport { Store } from 'redux';\nimport CounterApp from './CounterApp';\nimport DevTools from './DevTools';\nimport { CounterState } from '../reducers';\nimport { CounterAction } from '../actions/CounterActions';\n\ninterface Props {\n  store: Store<CounterState, CounterAction>;\n}\n\nexport default class Root extends Component<Props> {\n  render() {\n    const { store } = this.props;\n    return (\n      <Provider store={store}>\n        <div>\n          <CounterApp />\n          <DevTools />\n        </div>\n      </Provider>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/src/containers/Root.prod.tsx",
    "content": "import React, { Component } from 'react';\nimport { Provider } from 'react-redux';\nimport { Store } from 'redux';\nimport CounterApp from './CounterApp';\nimport { CounterState } from '../reducers';\nimport { CounterAction } from '../actions/CounterActions';\n\ninterface Props {\n  store: Store<CounterState, CounterAction>;\n}\n\nexport default class Root extends Component<Props> {\n  render() {\n    const { store } = this.props;\n    return (\n      <Provider store={store}>\n        <CounterApp />\n      </Provider>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/src/containers/Root.ts",
    "content": "import { Store } from 'redux';\nimport { CounterState } from '../reducers';\nimport { CounterAction } from '../actions/CounterActions';\nimport { ComponentType } from 'react';\n\ninterface Props {\n  store: Store<CounterState, CounterAction>;\n}\nconst Root: ComponentType<Props> =\n  process.env.NODE_ENV === 'production'\n    ? // eslint-disable-next-line @typescript-eslint/no-require-imports\n      require('./Root.prod').default\n    : // eslint-disable-next-line @typescript-eslint/no-require-imports\n      require('./Root.dev').default;\nexport default Root;\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/src/index.tsx",
    "content": "import React from 'react';\nimport { createRoot } from 'react-dom/client';\nimport configureStore from './store/configureStore';\nimport Root from './containers/Root';\n\nconst store = configureStore();\n\nconst root = createRoot(document.getElementById('root')!);\nroot.render(<Root store={store} />);\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/src/reducers/counter.ts",
    "content": "import { INCREMENT_COUNTER, DECREMENT_COUNTER } from '../constants/ActionTypes';\nimport { CounterAction } from '../actions/CounterActions';\n\nexport default function counter(state = 0, action: CounterAction) {\n  switch (action.type) {\n    case INCREMENT_COUNTER:\n      return state + 1;\n    case DECREMENT_COUNTER:\n      return state - 1;\n    default:\n      return state;\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/src/reducers/index.ts",
    "content": "import { combineReducers, Reducer } from 'redux';\nimport counter from './counter';\nimport { CounterAction } from '../actions/CounterActions';\n\nconst rootReducer: Reducer<\n  CounterState,\n  CounterAction,\n  Partial<CounterState>\n> = combineReducers({\n  counter,\n}) as any;\n\nexport interface CounterState {\n  counter: number;\n}\n\nexport default rootReducer;\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/src/store/configureStore.dev.ts",
    "content": "import {\n  createStore,\n  applyMiddleware,\n  compose,\n  Reducer,\n  StoreEnhancer,\n  Middleware,\n} from 'redux';\nimport { persistState } from '@redux-devtools/core';\nimport { thunk } from 'redux-thunk';\nimport rootReducer, { CounterState } from '../reducers';\nimport DevTools from '../containers/DevTools';\nimport { CounterAction } from '../actions/CounterActions';\n\nfunction getDebugSessionKey() {\n  const matches = /[?&]debug_session=([^&#]+)\\b/.exec(window.location.href);\n  return matches && matches.length > 0 ? matches[1] : null;\n}\n\nconst enhancer: StoreEnhancer = compose(\n  applyMiddleware(thunk as unknown as Middleware),\n  DevTools.instrument(),\n  persistState(getDebugSessionKey()),\n);\n\nexport default function configureStore(initialState?: Partial<CounterState>) {\n  const store = createStore(rootReducer, initialState, enhancer);\n\n  if (module.hot) {\n    module.hot.accept('../reducers', () =>\n      store.replaceReducer(\n        // eslint-disable-next-line @typescript-eslint/no-require-imports\n        require('../reducers').default as Reducer<\n          CounterState,\n          CounterAction,\n          Partial<CounterState>\n        >,\n      ),\n    );\n  }\n\n  return store;\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/src/store/configureStore.prod.ts",
    "content": "import { createStore, applyMiddleware, Middleware } from 'redux';\nimport { thunk } from 'redux-thunk';\nimport rootReducer, { CounterState } from '../reducers';\n\nconst enhancer = applyMiddleware(thunk as unknown as Middleware);\n\nexport default function configureStore(initialState?: Partial<CounterState>) {\n  return createStore(rootReducer, initialState, enhancer);\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/src/store/configureStore.ts",
    "content": "import { Store } from 'redux';\nimport { CounterState } from '../reducers';\nimport { CounterAction } from '../actions/CounterActions';\n\nconst configureStore: (\n  initialState?: Partial<CounterState>,\n) => Store<CounterState, CounterAction> =\n  process.env.NODE_ENV === 'production'\n    ? // eslint-disable-next-line @typescript-eslint/no-require-imports\n      require('./configureStore.prod').default\n    : // eslint-disable-next-line @typescript-eslint/no-require-imports\n      require('./configureStore.dev').default;\nexport default configureStore;\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../../tsconfig.react.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"webpack-env\"]\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/tsconfig.webpack.json",
    "content": "{\n  \"extends\": \"../../../../tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"webpack-dev-server\"]\n  },\n  \"include\": [\"webpack.config.ts\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/counter/webpack.config.ts",
    "content": "import * as path from 'path';\nimport * as webpack from 'webpack';\nimport HtmlWebpackPlugin from 'html-webpack-plugin';\nimport ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';\n\nconst config: webpack.Configuration = {\n  mode: 'development',\n  entry: './src/index.tsx',\n  devtool: 'eval-source-map',\n  devServer: {\n    static: './dist',\n  },\n  plugins: [\n    new HtmlWebpackPlugin({\n      template: './index.html',\n    }),\n    new ForkTsCheckerWebpackPlugin(),\n  ],\n  output: {\n    filename: 'bundle.js',\n    path: path.join(__dirname, 'dist'),\n    clean: true,\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.(js|ts)x?$/,\n        exclude: /node_modules/,\n        use: {\n          loader: 'babel-loader',\n          options: {\n            presets: [\n              ['@babel/preset-env', { targets: 'defaults' }],\n              '@babel/preset-react',\n              '@babel/preset-typescript',\n            ],\n          },\n        },\n      },\n    ],\n  },\n  resolve: {\n    extensions: ['.js', '.jsx', '.ts', '.tsx'],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/CHANGELOG.md",
    "content": "# todomvc\n\n## 0.2.12\n\n### Patch Changes\n\n- Updated dependencies [12849a4]\n- Updated dependencies [804d6bd]\n  - @redux-devtools/dock-monitor@5.0.0\n  - @redux-devtools/log-monitor@6.0.0\n  - @redux-devtools/core@5.0.0\n\n## 0.2.11\n\n### Patch Changes\n\n- Updated dependencies [91f21b2]\n  - @redux-devtools/core@4.1.1\n  - @redux-devtools/dock-monitor@4.1.1\n  - @redux-devtools/log-monitor@5.1.1\n\n## 0.2.10\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - @redux-devtools/dock-monitor@5.0.0\n  - @redux-devtools/log-monitor@6.0.0\n  - @redux-devtools/core@4.1.0\n\n## 0.2.9\n\n### Patch Changes\n\n- Updated dependencies [5cfe3e5]\n- Updated dependencies [decc035]\n  - @redux-devtools/dock-monitor@4.0.0\n  - @redux-devtools/log-monitor@5.0.0\n  - @redux-devtools/core@4.0.0\n\n## 0.2.8\n\n### Patch Changes\n\n- Updated dependencies [8a7eae4]\n  - @redux-devtools/dock-monitor@3.0.0\n  - @redux-devtools/log-monitor@4.0.0\n  - @redux-devtools/core@3.13.0\n\n## 0.2.7\n\n### Patch Changes\n\n- Updated dependencies [4891bf6]\n  - @redux-devtools/core@3.12.0\n  - @redux-devtools/dock-monitor@2.1.1\n  - @redux-devtools/log-monitor@3.1.1\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/README.md",
    "content": "# Redux DevTools todomvc example\n\n## Running Example\n\nFirst, clone the project:\n\n```\ngit clone https://github.com/reduxjs/redux-devtools.git\n```\n\nThen install the dependencies in the package folder:\n\n```\ncd redux-devtools/packages/redux-devtools\nnpm install\n```\n\nInstall the dependencies in the example folder:\n\n```\ncd examples/todomvc\nnpm install\n```\n\nFinally, run the project:\n\n```\nnpm start\nopen http://localhost:3000\n```\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/eslint.config.mjs",
    "content": "import eslintJs from '../../../../eslint.js.config.base.mjs';\nimport eslintTs from '../../../../eslint.ts.react.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTs(import.meta.dirname),\n  ...eslintTs(\n    import.meta.dirname,\n    ['webpack.config.ts'],\n    ['./tsconfig.webpack.json'],\n  ),\n  {\n    ignores: ['dist'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/index.html",
    "content": "<html>\n  <head>\n    <title>Redux TodoMVC</title>\n  </head>\n  <body>\n    <div class=\"todoapp\" id=\"root\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/package.json",
    "content": "{\n  \"private\": true,\n  \"name\": \"todomvc\",\n  \"version\": \"0.2.12\",\n  \"description\": \"TodoMVC example for redux\",\n  \"keywords\": [\n    \"react\",\n    \"reactjs\",\n    \"hot\",\n    \"reload\",\n    \"hmr\",\n    \"live\",\n    \"edit\",\n    \"webpack\",\n    \"flux\",\n    \"todomvc\"\n  ],\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools/examples/todomvc\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"start\": \"cross-env TS_NODE_PROJECT=\\\"tsconfig.webpack.json\\\" webpack serve --open\",\n    \"build\": \"cross-env TS_NODE_PROJECT=\\\"tsconfig.webpack.json\\\" webpack\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\"\n  },\n  \"dependencies\": {\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@redux-devtools/dock-monitor\": \"workspace:^\",\n    \"@redux-devtools/log-monitor\": \"workspace:^\",\n    \"classnames\": \"^2.5.1\",\n    \"react\": \"^19.2.4\",\n    \"react-dom\": \"^19.2.4\",\n    \"react-redux\": \"^9.2.0\",\n    \"redux\": \"^5.0.1\",\n    \"todomvc-app-css\": \"^2.4.3\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.29.0\",\n    \"@babel/preset-env\": \"^7.29.0\",\n    \"@babel/preset-react\": \"^7.28.5\",\n    \"@babel/preset-typescript\": \"^7.28.5\",\n    \"@types/node\": \"^24.12.0\",\n    \"@types/react\": \"^19.2.14\",\n    \"@types/react-dom\": \"^19.2.3\",\n    \"@types/webpack-env\": \"^1.18.8\",\n    \"babel-loader\": \"^10.1.1\",\n    \"cross-env\": \"^10.1.0\",\n    \"css-loader\": \"^7.1.4\",\n    \"fork-ts-checker-webpack-plugin\": \"^9.1.0\",\n    \"html-webpack-plugin\": \"^5.6.6\",\n    \"style-loader\": \"^4.0.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"~5.9.3\",\n    \"webpack\": \"^5.105.4\",\n    \"webpack-cli\": \"^7.0.0\",\n    \"webpack-dev-server\": \"^5.2.3\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/src/actions/TodoActions.ts",
    "content": "import * as types from '../constants/ActionTypes';\n\ninterface AddTodoAction {\n  type: typeof types.ADD_TODO;\n  text: string;\n}\nexport function addTodo(text: string): AddTodoAction {\n  return {\n    type: types.ADD_TODO,\n    text,\n  };\n}\n\ninterface DeleteTodoAction {\n  type: typeof types.DELETE_TODO;\n  id: number;\n}\nexport function deleteTodo(id: number): DeleteTodoAction {\n  return {\n    type: types.DELETE_TODO,\n    id,\n  };\n}\n\ninterface EditTodoAction {\n  type: typeof types.EDIT_TODO;\n  id: number;\n  text: string;\n}\nexport function editTodo(id: number, text: string): EditTodoAction {\n  return {\n    type: types.EDIT_TODO,\n    id,\n    text,\n  };\n}\n\ninterface MarkTodoAction {\n  type: typeof types.MARK_TODO;\n  id: number;\n}\nexport function markTodo(id: number): MarkTodoAction {\n  return {\n    type: types.MARK_TODO,\n    id,\n  };\n}\n\ninterface MarkAllAction {\n  type: typeof types.MARK_ALL;\n}\nexport function markAll(): MarkAllAction {\n  return {\n    type: types.MARK_ALL,\n  };\n}\n\ninterface ClearMarkedAction {\n  type: typeof types.CLEAR_MARKED;\n}\nexport function clearMarked(): ClearMarkedAction {\n  return {\n    type: types.CLEAR_MARKED,\n  };\n}\n\nexport type TodoAction =\n  | AddTodoAction\n  | DeleteTodoAction\n  | EditTodoAction\n  | MarkTodoAction\n  | MarkAllAction\n  | ClearMarkedAction;\n\nexport interface TodoActions {\n  addTodo(this: void, text: string): AddTodoAction;\n  deleteTodo(this: void, id: number): DeleteTodoAction;\n  editTodo(this: void, id: number, text: string): EditTodoAction;\n  markTodo(this: void, id: number): MarkTodoAction;\n  markAll(this: void): MarkAllAction;\n  clearMarked(this: void): ClearMarkedAction;\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/src/components/Footer.tsx",
    "content": "import React, { Component, MouseEventHandler } from 'react';\nimport classnames from 'classnames';\nimport {\n  SHOW_ALL,\n  SHOW_MARKED,\n  SHOW_UNMARKED,\n  TodoFilter,\n} from '../constants/TodoFilters';\n\nconst FILTER_TITLES = {\n  [SHOW_ALL]: 'All',\n  [SHOW_UNMARKED]: 'Active',\n  [SHOW_MARKED]: 'Completed',\n};\n\ninterface Props {\n  markedCount: number;\n  unmarkedCount: number;\n  filter: TodoFilter;\n  onClearMarked: MouseEventHandler<HTMLButtonElement>;\n  onShow: (filter: TodoFilter) => void;\n}\n\nexport default class Footer extends Component<Props> {\n  render() {\n    return (\n      <footer className=\"footer\">\n        {this.renderTodoCount()}\n        <ul className=\"filters\">\n          {([SHOW_ALL, SHOW_UNMARKED, SHOW_MARKED] as const).map((filter) => (\n            <li key={filter}>{this.renderFilterLink(filter)}</li>\n          ))}\n        </ul>\n        {this.renderClearButton()}\n      </footer>\n    );\n  }\n\n  renderTodoCount() {\n    const { unmarkedCount } = this.props;\n    const itemWord = unmarkedCount === 1 ? 'item' : 'items';\n\n    return (\n      <span className=\"todo-count\">\n        <strong>{unmarkedCount || 'No'}</strong> {itemWord} left\n      </span>\n    );\n  }\n\n  renderFilterLink(filter: TodoFilter) {\n    const title = FILTER_TITLES[filter];\n    const { filter: selectedFilter, onShow } = this.props;\n\n    return (\n      <a\n        className={classnames({ selected: filter === selectedFilter })}\n        style={{ cursor: 'hand' }}\n        onClick={() => onShow(filter)}\n      >\n        {title}\n      </a>\n    );\n  }\n\n  renderClearButton() {\n    const { markedCount, onClearMarked } = this.props;\n    if (markedCount > 0) {\n      return (\n        <button className=\"clear-completed\" onClick={onClearMarked}>\n          Clear completed\n        </button>\n      );\n    }\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/src/components/Header.tsx",
    "content": "import React, { Component } from 'react';\nimport TodoTextInput from './TodoTextInput';\n\ninterface Props {\n  addTodo: (text: string) => void;\n}\n\nexport default class Header extends Component<Props> {\n  handleSave = (text: string) => {\n    if (text.length !== 0) {\n      this.props.addTodo(text);\n    }\n  };\n\n  render() {\n    return (\n      <header className=\"header\">\n        <h1>todos</h1>\n        <TodoTextInput\n          newTodo={true}\n          onSave={this.handleSave}\n          placeholder=\"What needs to be done?\"\n        />\n      </header>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/src/components/MainSection.tsx",
    "content": "import React, { Component, MouseEventHandler } from 'react';\nimport TodoItem from './TodoItem';\nimport Footer from './Footer';\nimport {\n  SHOW_ALL,\n  SHOW_MARKED,\n  SHOW_UNMARKED,\n  TodoFilter,\n} from '../constants/TodoFilters';\nimport { Todo } from '../reducers/todos';\nimport { TodoActions } from '../actions/TodoActions';\n\nconst TODO_FILTERS = {\n  [SHOW_ALL]: () => true,\n  [SHOW_UNMARKED]: (todo: Todo) => !todo.marked,\n  [SHOW_MARKED]: (todo: Todo) => todo.marked,\n};\n\ninterface State {\n  filter: TodoFilter;\n}\n\ninterface Props {\n  todos: Todo[];\n  actions: TodoActions;\n}\n\nexport default class MainSection extends Component<Props, State> {\n  // Keep a counter that can be used to create an html `id` attribute.\n  static mountCount = 0;\n\n  state: State = { filter: SHOW_ALL };\n  htmlFormInputId = `toggle-all-${MainSection.mountCount++}`;\n\n  handleClearMarked: MouseEventHandler<HTMLButtonElement> = () => {\n    const atLeastOneMarked = this.props.todos.some((todo) => todo.marked);\n    if (atLeastOneMarked) {\n      this.props.actions.clearMarked();\n    }\n  };\n\n  handleShow = (filter: TodoFilter) => {\n    this.setState({ filter });\n  };\n\n  render() {\n    const { todos, actions } = this.props;\n    const { filter } = this.state;\n\n    const filteredTodos = todos.filter(TODO_FILTERS[filter]);\n    const markedCount = todos.reduce(\n      (count, todo) => (todo.marked ? count + 1 : count),\n      0,\n    );\n\n    return (\n      <section className=\"main\">\n        {this.renderToggleAll(markedCount)}\n        <ul className=\"todo-list\">\n          {filteredTodos.map((todo) => (\n            <TodoItem key={todo.id} todo={todo} {...actions} />\n          ))}\n        </ul>\n        {this.renderFooter(markedCount)}\n      </section>\n    );\n  }\n\n  renderToggleAll(markedCount: number) {\n    const { todos, actions } = this.props;\n\n    if (todos.length > 0) {\n      return (\n        <div>\n          <input\n            id={this.htmlFormInputId}\n            className=\"toggle-all\"\n            type=\"checkbox\"\n            checked={markedCount === todos.length}\n            onChange={actions.markAll}\n          />\n          <label htmlFor={this.htmlFormInputId}>Mark all as complete</label>\n        </div>\n      );\n    }\n  }\n\n  renderFooter(markedCount: number) {\n    const { todos } = this.props;\n    const { filter } = this.state;\n    const unmarkedCount = todos.length - markedCount;\n\n    if (todos.length) {\n      return (\n        <Footer\n          markedCount={markedCount}\n          unmarkedCount={unmarkedCount}\n          filter={filter}\n          onClearMarked={this.handleClearMarked}\n          onShow={this.handleShow}\n        />\n      );\n    }\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/src/components/TodoItem.tsx",
    "content": "import React, { Component } from 'react';\nimport classnames from 'classnames';\nimport TodoTextInput from './TodoTextInput';\nimport { Todo } from '../reducers/todos';\n\ninterface State {\n  editing: boolean;\n}\n\ninterface Props {\n  todo: Todo;\n  addTodo: (text: string) => void;\n  deleteTodo: (id: number) => void;\n  editTodo: (id: number, text: string) => void;\n  markTodo: (id: number) => void;\n  markAll: () => void;\n  clearMarked: () => void;\n}\n\nexport default class TodoItem extends Component<Props, State> {\n  state: State = {\n    editing: false,\n  };\n\n  handleDoubleClick = () => {\n    this.setState({ editing: true });\n  };\n\n  handleSave(id: number, text: string) {\n    if (text.length === 0) {\n      this.props.deleteTodo(id);\n    } else {\n      this.props.editTodo(id, text);\n    }\n    this.setState({ editing: false });\n  }\n\n  render() {\n    const { todo, markTodo, deleteTodo } = this.props;\n\n    let element;\n    if (this.state.editing) {\n      element = (\n        <TodoTextInput\n          text={todo.text}\n          editing={this.state.editing}\n          onSave={(text) => this.handleSave(todo.id, text)}\n        />\n      );\n    } else {\n      element = (\n        <div className=\"view\">\n          <input\n            className=\"toggle\"\n            type=\"checkbox\"\n            checked={todo.marked}\n            onChange={() => markTodo(todo.id)}\n          />\n          <label onDoubleClick={this.handleDoubleClick}>{todo.text}</label>\n          <button className=\"destroy\" onClick={() => deleteTodo(todo.id)} />\n        </div>\n      );\n    }\n\n    return (\n      <li\n        className={classnames({\n          completed: todo.marked,\n          editing: this.state.editing,\n        })}\n      >\n        {element}\n      </li>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/src/components/TodoTextInput.tsx",
    "content": "import React, {\n  ChangeEventHandler,\n  Component,\n  FocusEventHandler,\n  KeyboardEventHandler,\n} from 'react';\nimport classnames from 'classnames';\n\ninterface State {\n  text: string;\n}\n\ninterface Props {\n  onSave: (text: string) => void;\n  text?: string;\n  placeholder?: string;\n  editing?: boolean;\n  newTodo?: boolean;\n}\n\nexport default class TodoTextInput extends Component<Props, State> {\n  state = {\n    text: this.props.text || '',\n  };\n\n  handleSubmit: KeyboardEventHandler<HTMLInputElement> = (e) => {\n    const text = e.currentTarget.value.trim();\n    if (e.which === 13) {\n      this.props.onSave(text);\n      if (this.props.newTodo) {\n        this.setState({ text: '' });\n      }\n    }\n  };\n\n  handleChange: ChangeEventHandler<HTMLInputElement> = (e) => {\n    this.setState({ text: e.target.value });\n  };\n\n  handleBlur: FocusEventHandler<HTMLInputElement> = (e) => {\n    if (!this.props.newTodo) {\n      this.props.onSave(e.target.value);\n    }\n  };\n\n  render() {\n    return (\n      <input\n        className={classnames({\n          edit: this.props.editing,\n          'new-todo': this.props.newTodo,\n        })}\n        type=\"text\"\n        placeholder={this.props.placeholder}\n        autoFocus={true}\n        value={this.state.text}\n        onBlur={this.handleBlur}\n        onChange={this.handleChange}\n        onKeyDown={this.handleSubmit}\n      />\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/src/constants/ActionTypes.ts",
    "content": "export const ADD_TODO = 'ADD_TODO';\nexport const DELETE_TODO = 'DELETE_TODO';\nexport const EDIT_TODO = 'EDIT_TODO';\nexport const MARK_TODO = 'MARK_TODO';\nexport const MARK_ALL = 'MARK_ALL';\nexport const CLEAR_MARKED = 'CLEAR_MARKED';\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/src/constants/TodoFilters.ts",
    "content": "export const SHOW_ALL = 'show_all';\nexport const SHOW_MARKED = 'show_marked';\nexport const SHOW_UNMARKED = 'show_unmarked';\n\nexport type TodoFilter =\n  | typeof SHOW_ALL\n  | typeof SHOW_MARKED\n  | typeof SHOW_UNMARKED;\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/src/containers/DevTools.tsx",
    "content": "import React from 'react';\nimport { createDevTools } from '@redux-devtools/core';\nimport { LogMonitor } from '@redux-devtools/log-monitor';\nimport { DockMonitor } from '@redux-devtools/dock-monitor';\n\nexport default createDevTools(\n  <DockMonitor toggleVisibilityKey=\"ctrl-h\" changePositionKey=\"ctrl-q\">\n    <LogMonitor />\n  </DockMonitor>,\n);\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/src/containers/Root.dev.tsx",
    "content": "import React, { Component } from 'react';\nimport { Provider } from 'react-redux';\nimport TodoApp from './TodoApp';\nimport DevTools from './DevTools';\nimport { Store } from 'redux';\nimport { TodoState } from '../reducers';\nimport { TodoAction } from '../actions/TodoActions';\n\ninterface Props {\n  store: Store<TodoState, TodoAction>;\n}\n\nexport default class Root extends Component<Props> {\n  render() {\n    const { store } = this.props;\n    return (\n      <Provider store={store}>\n        <div>\n          <TodoApp />\n          <DevTools />\n        </div>\n      </Provider>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/src/containers/Root.prod.tsx",
    "content": "import React, { Component } from 'react';\nimport { Provider } from 'react-redux';\nimport TodoApp from './TodoApp';\nimport { Store } from 'redux';\nimport { TodoState } from '../reducers';\nimport { TodoAction } from '../actions/TodoActions';\n\ninterface Props {\n  store: Store<TodoState, TodoAction>;\n}\n\nexport default class Root extends Component<Props> {\n  render() {\n    const { store } = this.props;\n    return (\n      <Provider store={store}>\n        <TodoApp />\n      </Provider>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/src/containers/Root.ts",
    "content": "import { Store } from 'redux';\nimport { ComponentType } from 'react';\nimport { TodoState } from '../reducers';\nimport { TodoAction } from '../actions/TodoActions';\n\ninterface Props {\n  store: Store<TodoState, TodoAction>;\n}\nconst Root: ComponentType<Props> =\n  process.env.NODE_ENV === 'production'\n    ? // eslint-disable-next-line @typescript-eslint/no-require-imports\n      require('./Root.prod').default\n    : // eslint-disable-next-line @typescript-eslint/no-require-imports\n      require('./Root.dev').default;\nexport default Root;\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/src/containers/TodoApp.tsx",
    "content": "import React, { Component } from 'react';\nimport { connect } from 'react-redux';\nimport { bindActionCreators, Dispatch } from 'redux';\nimport Header from '../components/Header';\nimport MainSection from '../components/MainSection';\nimport * as TodoActions from '../actions/TodoActions';\nimport {\n  TodoAction,\n  TodoActions as TodoActionsType,\n} from '../actions/TodoActions';\nimport { TodoState } from '../reducers';\nimport { Todo } from '../reducers/todos';\n\ninterface Props {\n  todos: Todo[];\n  actions: TodoActionsType;\n}\n\nclass TodoApp extends Component<Props> {\n  render() {\n    const { todos, actions } = this.props;\n\n    return (\n      <div>\n        <Header addTodo={actions.addTodo} />\n        <MainSection todos={todos} actions={actions} />\n      </div>\n    );\n  }\n}\n\nfunction mapState(state: TodoState) {\n  return {\n    todos: state.todos,\n  };\n}\n\nfunction mapDispatch(dispatch: Dispatch<TodoAction>) {\n  return {\n    actions: bindActionCreators(TodoActions, dispatch),\n  };\n}\n\nexport default connect(mapState, mapDispatch)(TodoApp);\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/src/index.tsx",
    "content": "import 'todomvc-app-css/index.css';\nimport React from 'react';\nimport { createRoot } from 'react-dom/client';\nimport configureStore from './store/configureStore';\nimport Root from './containers/Root';\n\nconst store = configureStore();\n\nconst root = createRoot(document.getElementById('root')!);\nroot.render(<Root store={store} />);\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/src/reducers/index.ts",
    "content": "import { combineReducers, Reducer } from 'redux';\nimport todos, { Todo } from './todos';\nimport { TodoAction } from '../actions/TodoActions';\n\nexport interface TodoState {\n  todos: Todo[];\n}\n\nconst rootReducer: Reducer<\n  TodoState,\n  TodoAction,\n  Partial<TodoState>\n> = combineReducers({\n  todos,\n}) as any;\n\nexport default rootReducer;\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/src/reducers/todos.ts",
    "content": "import {\n  ADD_TODO,\n  DELETE_TODO,\n  EDIT_TODO,\n  MARK_TODO,\n  MARK_ALL,\n  CLEAR_MARKED,\n} from '../constants/ActionTypes';\nimport { TodoAction } from '../actions/TodoActions';\n\nexport interface Todo {\n  text: string;\n  marked: boolean;\n  id: number;\n}\n\nconst initialState: Todo[] = [\n  {\n    text: 'Use Redux',\n    marked: false,\n    id: 0,\n  },\n];\n\nexport default function todos(state = initialState, action: TodoAction) {\n  switch (action.type) {\n    case ADD_TODO:\n      return [\n        {\n          id: state.length === 0 ? 0 : state[0].id + 1,\n          marked: false,\n          text: action.text,\n        },\n        ...state,\n      ];\n\n    case DELETE_TODO:\n      return state.filter((todo) => todo.id !== action.id);\n\n    case EDIT_TODO:\n      return state.map((todo) =>\n        todo.id === action.id ? { ...todo, text: action.text } : todo,\n      );\n\n    case MARK_TODO:\n      return state.map((todo) =>\n        todo.id === action.id ? { ...todo, marked: !todo.marked } : todo,\n      );\n\n    case MARK_ALL: {\n      const areAllMarked = state.every((todo) => todo.marked);\n      return state.map((todo) => ({\n        ...todo,\n        marked: !areAllMarked,\n      }));\n    }\n\n    case CLEAR_MARKED:\n      return state.filter((todo) => !todo.marked);\n\n    default:\n      return state;\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/src/store/configureStore.dev.ts",
    "content": "import { createStore, compose, StoreEnhancer } from 'redux';\nimport { persistState } from '@redux-devtools/core';\nimport rootReducer, { TodoState } from '../reducers';\nimport DevTools from '../containers/DevTools';\n\nfunction getDebugSessionKey() {\n  const matches = /[?&]debug_session=([^&#]+)\\b/.exec(window.location.href);\n  return matches && matches.length > 0 ? matches[1] : null;\n}\n\nconst enhancer: StoreEnhancer = compose(\n  DevTools.instrument(),\n  persistState(getDebugSessionKey()),\n);\n\nexport default function configureStore(initialState?: Partial<TodoState>) {\n  return createStore(rootReducer, initialState, enhancer);\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/src/store/configureStore.prod.ts",
    "content": "import { createStore } from 'redux';\nimport rootReducer, { TodoState } from '../reducers';\n\nexport default function configureStore(initialState?: Partial<TodoState>) {\n  return createStore(rootReducer, initialState);\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/src/store/configureStore.ts",
    "content": "import { Store } from 'redux';\nimport { TodoState } from '../reducers';\nimport { TodoAction } from '../actions/TodoActions';\n\nconst configureStore: (\n  initialState?: Partial<TodoState>,\n) => Store<TodoState, TodoAction> =\n  process.env.NODE_ENV === 'production'\n    ? // eslint-disable-next-line @typescript-eslint/no-require-imports\n      require('./configureStore.prod').default\n    : // eslint-disable-next-line @typescript-eslint/no-require-imports\n      require('./configureStore.dev').default;\nexport default configureStore;\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../../tsconfig.react.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"webpack-env\"]\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/tsconfig.webpack.json",
    "content": "{\n  \"extends\": \"../../../../tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"webpack-dev-server\"]\n  },\n  \"include\": [\"webpack.config.ts\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools/examples/todomvc/webpack.config.ts",
    "content": "import * as path from 'path';\nimport * as webpack from 'webpack';\nimport HtmlWebpackPlugin from 'html-webpack-plugin';\nimport ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';\n\nconst config: webpack.Configuration = {\n  mode: 'development',\n  entry: './src/index.tsx',\n  devtool: 'eval-source-map',\n  devServer: {\n    static: './dist',\n  },\n  plugins: [\n    new HtmlWebpackPlugin({\n      template: './index.html',\n    }),\n    new ForkTsCheckerWebpackPlugin(),\n  ],\n  output: {\n    filename: 'bundle.js',\n    path: path.join(__dirname, 'dist'),\n    clean: true,\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.(js|ts)x?$/,\n        exclude: /node_modules/,\n        use: {\n          loader: 'babel-loader',\n          options: {\n            presets: [\n              ['@babel/preset-env', { targets: 'defaults' }],\n              '@babel/preset-react',\n              '@babel/preset-typescript',\n            ],\n          },\n        },\n      },\n      {\n        test: /\\.css$/i,\n        use: ['style-loader', 'css-loader'],\n      },\n    ],\n  },\n  resolve: {\n    extensions: ['.js', '.jsx', '.ts', '.tsx'],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "packages/redux-devtools/jest.config.ts",
    "content": "import { createDefaultEsmPreset, type JestConfigWithTsJest } from 'ts-jest';\n\nconst presetConfig = createDefaultEsmPreset({\n  tsconfig: 'tsconfig.test.json',\n});\n\nconst jestConfig: JestConfigWithTsJest = {\n  ...presetConfig,\n  moduleNameMapper: {\n    '^(\\\\.{1,2}/.*)\\\\.js$': '$1',\n  },\n};\n\nexport default jestConfig;\n"
  },
  {
    "path": "packages/redux-devtools/package.json",
    "content": "{\n  \"name\": \"@redux-devtools/core\",\n  \"version\": \"5.0.0\",\n  \"description\": \"Redux DevTools with hot reloading and time travel\",\n  \"keywords\": [\n    \"redux\",\n    \"devtools\",\n    \"flux\",\n    \"hot reloading\",\n    \"time travel\",\n    \"live edit\"\n  ],\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/main/packages/redux-devtools\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Dan Abramov <dan.abramov@me.com> (http://github.com/gaearon)\",\n  \"files\": [\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": \"./lib/index.js\",\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"test\": \"node --experimental-vm-modules node_modules/jest/bin/jest.js\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run type-check && pnpm run lint && pnpm run test\"\n  },\n  \"dependencies\": {\n    \"@redux-devtools/instrument\": \"workspace:^\"\n  },\n  \"devDependencies\": {\n    \"@jest/globals\": \"^30.3.0\",\n    \"@types/jest\": \"^30.0.0\",\n    \"@types/node\": \"^24.12.0\",\n    \"@types/react\": \"^19.2.14\",\n    \"jest\": \"^30.3.0\",\n    \"react\": \"^19.2.4\",\n    \"react-dom\": \"^19.2.4\",\n    \"react-redux\": \"^9.2.0\",\n    \"redux\": \"^5.0.1\",\n    \"rimraf\": \"^6.1.3\",\n    \"ts-jest\": \"^29.4.6\",\n    \"typescript\": \"~5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-redux\": \"^7.0.0 || ^8.0.0 || ^9.0.0\",\n    \"redux\": \"^3.5.2 || ^4.0.0 || ^5.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools/src/createDevTools.tsx",
    "content": "import React, { Children, Component } from 'react';\nimport { connect, Provider, ReactReduxContext } from 'react-redux';\nimport {\n  instrument,\n  EnhancedStore,\n  LiftedState,\n  LiftedStore,\n  Options,\n  InstrumentExt,\n} from '@redux-devtools/instrument';\nimport { Action, StoreEnhancer } from 'redux';\n\nfunction logError(type: string) {\n  if (type === 'NoStore') {\n    console.error(\n      'Redux DevTools could not render. You must pass the Redux store ' +\n        'to <DevTools> either as a \"store\" prop or by wrapping it in a ' +\n        '<Provider store={store}>.',\n    );\n  } else {\n    console.error(\n      'Redux DevTools could not render. Did you forget to include ' +\n        'DevTools.instrument() in your store enhancer chain before ' +\n        'using createStore()?',\n    );\n  }\n}\n\nexport interface Props<S, A extends Action<string>, MonitorState> {\n  store?: EnhancedStore<S, A, MonitorState>;\n}\n\nexport type Monitor<\n  S,\n  A extends Action<string>,\n  MonitorProps extends LiftedState<S, A, MonitorState>,\n  MonitorState,\n  MonitorAction extends Action<string>,\n> = React.ReactElement<\n  MonitorProps,\n  React.ComponentType<MonitorProps & LiftedState<S, A, MonitorState>> & {\n    update(\n      monitorProps: MonitorProps,\n      state: MonitorState | undefined,\n      action: MonitorAction,\n    ): MonitorState;\n  }\n>;\n\nexport interface DevToolsInstance<\n  S,\n  A extends Action<string>,\n  MonitorState,\n> extends Component<Props<S, A, MonitorState>> {\n  liftedStore?: LiftedStore<S, A, MonitorState>;\n}\n\nexport interface DevToolsClass<\n  S,\n  A extends Action<string>,\n  MonitorState,\n  MonitorAction extends Action<string>,\n> {\n  new (props: Props<S, A, MonitorState>): DevToolsInstance<S, A, MonitorState>;\n  instrument: (\n    options?: Options<S, A, MonitorState, MonitorAction>,\n  ) => StoreEnhancer<InstrumentExt<any, any, MonitorState>>;\n}\n\nexport default function createDevTools<\n  S,\n  A extends Action<string>,\n  MonitorProps extends LiftedState<S, A, MonitorState>,\n  MonitorState,\n  MonitorAction extends Action<string>,\n>(\n  children: Monitor<S, A, MonitorProps, MonitorState, MonitorAction>,\n): DevToolsClass<S, A, MonitorState, MonitorAction> {\n  const monitorElement = Children.only(children);\n  const monitorProps = monitorElement.props;\n  const Monitor = monitorElement.type;\n  const ConnectedMonitor = connect(\n    (state: LiftedState<S, A, MonitorState>) => state,\n  )(Monitor as React.ComponentType<any>);\n\n  return class DevTools extends Component<Props<S, A, MonitorState>> {\n    liftedStore?: LiftedStore<S, A, MonitorState>;\n\n    static instrument = (\n      options?: Options<S, A, MonitorState, MonitorAction>,\n    ) =>\n      instrument(\n        (state, action) => Monitor.update(monitorProps, state, action),\n        options,\n      );\n\n    constructor(props: Props<S, A, MonitorState>) {\n      super(props);\n\n      if (ReactReduxContext as typeof ReactReduxContext | undefined) {\n        if (this.props.store && !this.props.store.liftedStore) {\n          logError('NoLiftedStore');\n        }\n        return;\n      }\n\n      if (!props.store) {\n        logError('NoStore');\n        return;\n      }\n\n      this.liftedStore = props.store.liftedStore;\n\n      if (!this.liftedStore) {\n        logError('NoLiftedStore');\n      }\n    }\n\n    render() {\n      if (ReactReduxContext) {\n        // For react-redux@6\n        if (this.props.store) {\n          if (!this.props.store.liftedStore) {\n            return null;\n          }\n          return (\n            <Provider store={this.props.store.liftedStore}>\n              <ConnectedMonitor {...monitorProps} />\n            </Provider>\n          );\n        }\n        return (\n          <ReactReduxContext.Consumer>\n            {(props) => {\n              if (!props || !props.store) {\n                logError('NoStore');\n                return null;\n              }\n              if (\n                !(props.store as unknown as EnhancedStore<S, A, MonitorState>)\n                  .liftedStore\n              ) {\n                logError('NoLiftedStore');\n                return null;\n              }\n              return (\n                <Provider\n                  store={\n                    (\n                      props.store as unknown as EnhancedStore<\n                        S,\n                        A,\n                        MonitorState\n                      >\n                    ).liftedStore\n                  }\n                >\n                  <ConnectedMonitor {...monitorProps} />\n                </Provider>\n              );\n            }}\n          </ReactReduxContext.Consumer>\n        );\n      }\n\n      if (!this.liftedStore) {\n        return null;\n      }\n\n      return <ConnectedMonitor {...monitorProps} store={this.liftedStore} />;\n    }\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools/src/index.ts",
    "content": "export {\n  instrument,\n  ActionCreators,\n  ActionTypes,\n  type PerformAction,\n  type LiftedAction,\n  type LiftedState,\n} from '@redux-devtools/instrument';\nexport { default as persistState } from './persistState.js';\nexport { default as createDevTools, type Monitor } from './createDevTools.js';\n"
  },
  {
    "path": "packages/redux-devtools/src/persistState.ts",
    "content": "import { Action, Reducer, StoreEnhancer } from 'redux';\nimport { LiftedState } from '@redux-devtools/instrument';\n\nexport default function persistState<S, A extends Action<string>, MonitorState>(\n  sessionId?: string | null,\n  deserializeState: (state: S) => S = (state) => state,\n  deserializeAction: (action: A) => A = (state) => state,\n): StoreEnhancer {\n  if (!sessionId) {\n    return (next) =>\n      (...args) =>\n        next(...args);\n  }\n\n  function deserialize(\n    state: LiftedState<S, A, MonitorState>,\n  ): LiftedState<S, A, MonitorState> {\n    return {\n      ...state,\n      actionsById: Object.fromEntries(\n        Object.entries(state.actionsById).map(([actionId, liftedAction]) => [\n          actionId,\n          {\n            ...liftedAction,\n            action: deserializeAction(liftedAction.action),\n          },\n        ]),\n      ),\n      committedState: deserializeState(state.committedState),\n      computedStates: state.computedStates.map((computedState) => ({\n        ...computedState,\n        state: deserializeState(computedState.state),\n      })),\n    };\n  }\n\n  return (next) =>\n    <S2, A2 extends Action<string>, PreloadedState>(\n      reducer: Reducer<S2, A2, PreloadedState>,\n      initialState?: PreloadedState | undefined,\n    ) => {\n      const key = `redux-dev-session-${sessionId}`;\n\n      let finalInitialState;\n      try {\n        const json = localStorage.getItem(key);\n        if (json) {\n          finalInitialState =\n            deserialize(JSON.parse(json) as LiftedState<S, A, MonitorState>) ||\n            initialState;\n          next(reducer, initialState);\n        }\n      } catch (e) {\n        console.warn('Could not read debug session from localStorage:', e); // eslint-disable-line no-console\n        try {\n          localStorage.removeItem(key);\n        } finally {\n          finalInitialState = undefined;\n        }\n      }\n\n      const store = next(\n        reducer,\n        finalInitialState as PreloadedState | undefined,\n      );\n\n      return {\n        ...store,\n        dispatch<T extends A2>(action: T) {\n          store.dispatch(action);\n\n          try {\n            localStorage.setItem(key, JSON.stringify(store.getState()));\n          } catch (e) {\n            console.warn('Could not write debug session to localStorage:', e); // eslint-disable-line no-console\n          }\n\n          return action;\n        },\n      };\n    };\n}\n"
  },
  {
    "path": "packages/redux-devtools/test/globalLocalStorage.d.ts",
    "content": "declare namespace NodeJS {\n  interface Global {\n    localStorage: Storage;\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools/test/persistState.spec.ts",
    "content": "import { jest } from '@jest/globals';\nimport { instrument, persistState } from '../src/index.js';\nimport { compose, createStore, StoreEnhancer } from 'redux';\n\ndescribe('persistState', () => {\n  const savedLocalStorage = global.localStorage;\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  delete global.localStorage;\n\n  beforeEach(() => {\n    global.localStorage = {\n      store: {},\n      getItem(key) {\n        return this.store[key] || null;\n      },\n      setItem(key, value) {\n        this.store[key] = value;\n      },\n      removeItem(key) {\n        delete this.store[key];\n      },\n      clear() {\n        this.store = {};\n      },\n      get length() {\n        return this.store.length;\n      },\n      key(index) {\n        throw new Error('Unimplemented');\n      },\n    };\n  });\n\n  afterAll(() => {\n    global.localStorage = savedLocalStorage;\n  });\n\n  type Action = { type: 'INCREMENT' } | { type: 'DECREMENT' };\n  const reducer = (state = 0, action: Action) => {\n    switch (action.type) {\n      case 'INCREMENT':\n        return state + 1;\n      case 'DECREMENT':\n        return state - 1;\n      default:\n        return state;\n    }\n  };\n\n  it('should persist state', () => {\n    const store = createStore(\n      reducer,\n      compose(instrument(), persistState('id')) as StoreEnhancer,\n    );\n    expect(store.getState()).toBe(0);\n\n    store.dispatch({ type: 'INCREMENT' });\n    store.dispatch({ type: 'INCREMENT' });\n    expect(store.getState()).toBe(2);\n\n    const store2 = createStore(\n      reducer,\n      compose(instrument(), persistState('id')) as StoreEnhancer,\n    );\n    expect(store2.getState()).toBe(2);\n  });\n\n  it('should not persist state if no session id', () => {\n    const store = createStore(\n      reducer,\n      compose(instrument(), persistState()) as StoreEnhancer,\n    );\n    expect(store.getState()).toBe(0);\n\n    store.dispatch({ type: 'INCREMENT' });\n    store.dispatch({ type: 'INCREMENT' });\n    expect(store.getState()).toBe(2);\n\n    const store2 = createStore(\n      reducer,\n      compose(instrument(), persistState()) as StoreEnhancer,\n    );\n    expect(store2.getState()).toBe(0);\n  });\n\n  it('should run with a custom state deserializer', () => {\n    const oneLess = (state: number | undefined) =>\n      state === undefined ? -1 : state - 1;\n    const store = createStore(\n      reducer,\n      compose(instrument(), persistState('id', oneLess)) as StoreEnhancer,\n    );\n    expect(store.getState()).toBe(0);\n\n    store.dispatch({ type: 'INCREMENT' });\n    store.dispatch({ type: 'INCREMENT' });\n    expect(store.getState()).toBe(2);\n\n    const store2 = createStore(\n      reducer,\n      compose(instrument(), persistState('id', oneLess)) as StoreEnhancer,\n    );\n    expect(store2.getState()).toBe(1);\n  });\n\n  it('should run with a custom action deserializer', () => {\n    const incToDec = (action: Action) =>\n      action.type === 'INCREMENT' ? ({ type: 'DECREMENT' } as const) : action;\n    const store = createStore(\n      reducer,\n      compose(\n        instrument(),\n        persistState('id', undefined, incToDec),\n      ) as StoreEnhancer,\n    );\n    expect(store.getState()).toBe(0);\n\n    store.dispatch({ type: 'INCREMENT' });\n    store.dispatch({ type: 'INCREMENT' });\n    expect(store.getState()).toBe(2);\n\n    const store2 = createStore(\n      reducer,\n      compose(\n        instrument(),\n        persistState('id', undefined, incToDec),\n      ) as StoreEnhancer,\n    );\n    expect(store2.getState()).toBe(-2);\n  });\n\n  it('should warn if read from localStorage fails', () => {\n    const spy = jest.spyOn(console, 'warn').mockImplementation(() => {\n      // noop\n    });\n    // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n    // @ts-ignore\n    delete global.localStorage.getItem;\n    createStore(\n      reducer,\n      compose(instrument(), persistState('id')) as StoreEnhancer,\n    );\n\n    expect(spy.mock.calls[0]).toContain(\n      'Could not read debug session from localStorage:',\n    );\n\n    spy.mockReset();\n  });\n\n  it('should warn if write to localStorage fails', () => {\n    const spy = jest.spyOn(console, 'warn').mockImplementation(() => {\n      // noop\n    });\n    // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n    // @ts-ignore\n    delete global.localStorage.setItem;\n    const store = createStore(\n      reducer,\n      compose(instrument(), persistState('id')) as StoreEnhancer,\n    );\n\n    store.dispatch({ type: 'INCREMENT' });\n    expect(spy.mock.calls[0]).toContain(\n      'Could not write debug session to localStorage:',\n    );\n\n    spy.mockReset();\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools/tsconfig.test.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"jest\", \"node\"]\n  },\n  \"include\": [\"src\", \"test\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-app/CHANGELOG.md",
    "content": "# Change Log\n\n## 8.0.0\n\n### Major Changes\n\n- 6481386: Convert remaining packages to ESM\n\n### Patch Changes\n\n- Updated dependencies [d61d31a]\n- Updated dependencies [804e729]\n- Updated dependencies [6481386]\n  - @redux-devtools/ui@3.0.0\n  - @redux-devtools/app-core@3.0.0\n\n## 7.0.0\n\n### Major Changes\n\n- 6163276: Replace styled-components with Emotion\n\n### Patch Changes\n\n- Updated dependencies [6163276]\n  - @redux-devtools/app-core@2.0.0\n  - @redux-devtools/ui@2.0.0\n\n## 6.2.2\n\n### Patch Changes\n\n- @redux-devtools/app-core@1.1.2\n\n## 6.2.1\n\n### Patch Changes\n\n- @redux-devtools/app-core@1.1.1\n\n## 6.2.0\n\n### Minor Changes\n\n- 6830118: Add React 19 to peer deps\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - @redux-devtools/app-core@1.1.0\n  - @redux-devtools/ui@1.4.0\n\n## 6.1.0\n\n### Minor Changes\n\n- 96ac1f2: Move the logic from @redux-devtools/app into @redux-devtools/app-core\n\n### Patch Changes\n\n- Updated dependencies [96ac1f2]\n  - @redux-devtools/app-core@1.0.0\n\n## 6.0.1\n\n### Patch Changes\n\n- 191d419: Convert d3 packages to ESM\n- Updated dependencies [191d419]\n  - d3-state-visualizer@3.0.0\n  - @redux-devtools/chart-monitor@5.0.1\n\n## 6.0.0\n\n### Major Changes\n\n- 5cfe3e5: Update min required React version to 16.8.4\n\n### Patch Changes\n\n- Updated dependencies [5cfe3e5]\n- Updated dependencies [decc035]\n  - @redux-devtools/chart-monitor@5.0.0\n  - @redux-devtools/inspector-monitor-test-tab@4.0.0\n  - @redux-devtools/inspector-monitor-trace-tab@4.0.0\n  - @redux-devtools/inspector-monitor@6.0.0\n  - @redux-devtools/log-monitor@5.0.0\n  - @redux-devtools/rtk-query-monitor@5.0.0\n  - @redux-devtools/slider-monitor@5.0.0\n  - @redux-devtools/core@4.0.0\n\n## 5.0.0\n\n### Major Changes\n\n- 158ba2c: Replace jss with Emotion in inspector-monitor. `@emotion/react` is now a required peer dependency.\n\n### Patch Changes\n\n- Updated dependencies [158ba2c]\n- Updated dependencies [6954eb9]\n  - @redux-devtools/inspector-monitor-test-tab@3.0.0\n  - @redux-devtools/inspector-monitor-trace-tab@3.0.0\n  - @redux-devtools/inspector-monitor@5.0.0\n  - @redux-devtools/rtk-query-monitor@4.0.0\n\n## 4.0.2\n\n### Patch Changes\n\n- 7f5bddbd: Widen peer dependencies\n- Updated dependencies [7f5bddbd]\n- Updated dependencies [6fc18ed7]\n  - @redux-devtools/chart-monitor@4.1.0\n  - @redux-devtools/inspector-monitor-test-tab@2.1.0\n  - @redux-devtools/inspector-monitor-trace-tab@2.1.0\n  - @redux-devtools/inspector-monitor@4.1.0\n  - @redux-devtools/log-monitor@4.1.0\n  - @redux-devtools/rtk-query-monitor@3.2.0\n  - @redux-devtools/slider-monitor@4.1.0\n  - @redux-devtools/ui@1.3.1\n  - @redux-devtools/core@3.14.0\n\n## 4.0.1\n\n### Patch Changes\n\n- 65205f90: Replace Action<unknown> with Action<string>\n- Updated dependencies [65205f90]\n  - @redux-devtools/chart-monitor@4.0.1\n  - @redux-devtools/inspector-monitor-test-tab@2.0.1\n  - @redux-devtools/inspector-monitor-trace-tab@2.0.1\n  - @redux-devtools/inspector-monitor@4.0.1\n  - @redux-devtools/core@3.13.2\n\n## 4.0.0\n\n### Major Changes\n\n- e57bcb39: The UMD bundle now exports the same thing as the library and includes the CSS in a sperate file. Therfore, the new usage is:\n\n  ```diff\n  <!doctype html>\n  <html>\n    <head>\n      <meta charset=\"utf-8\" />\n      <title>Redux DevTools</title>\n  +   <link href=\"/redux-devtools-app.min.css\" rel=\"stylesheet\" />\n    </head>\n    <body>\n      <div id=\"root\"></div>\n      <script src=\"/react.production.min.js\"></script>\n      <script src=\"/react-dom.production.min.js\"></script>\n      <script src=\"/redux-devtools-app.min.js\"></script>\n      <script src=\"/port.js\"></script>\n      <script>\n        const container = document.querySelector('#root');\n  -     const element = React.createElement(ReduxDevToolsApp, {\n  +     const element = React.createElement(ReduxDevToolsApp.Root, {\n          socketOptions: {\n            hostname: location.hostname,\n            port: reduxDevToolsPort,\n            autoReconnect: true,\n          },\n        });\n        ReactDOM.createRoot(container).render(element);\n      </script>\n    </body>\n  </html>\n  ```\n\n## 3.0.0\n\n### Major Changes\n\n- 57751ff9: Add react-dom peerDependency and bump react peerDependency to `^16.8.0 || ^17.0.0 || ^18.0.0`\n\n### Patch Changes\n\n- Updated dependencies [57751ff9]\n  - @redux-devtools/inspector-monitor-test-tab@2.0.0\n  - @redux-devtools/inspector-monitor-trace-tab@2.0.0\n  - @redux-devtools/inspector-monitor@4.0.0\n\n## 2.2.3\n\n### Patch Changes\n\n- fe32709c: Update jsondiffpatch to fix bundling issues.\n- Updated dependencies [fe32709c]\n  - @redux-devtools/inspector-monitor@3.1.1\n\n## 2.2.2\n\n### Patch Changes\n\n- Updated dependencies [14a79573]\n- Updated dependencies [d54adb76]\n- Updated dependencies [bb9bd907]\n  - @redux-devtools/inspector-monitor@3.1.0\n  - @redux-devtools/inspector-monitor-test-tab@2.0.0\n  - @redux-devtools/inspector-monitor-trace-tab@2.0.0\n\n## 2.2.1\n\n### Patch Changes\n\n- Updated dependencies [b323f77d]\n- Updated dependencies [b323f77d]\n  - d3-state-visualizer@2.0.0\n  - @redux-devtools/chart-monitor@4.0.0\n  - @redux-devtools/inspector-monitor@3.0.2\n  - @redux-devtools/log-monitor@4.0.2\n  - @redux-devtools/rtk-query-monitor@3.1.1\n\n## 2.2.0\n\n### Minor Changes\n\n- 8a7eae4: Add React 18 to peerDependencies range\n\n### Patch Changes\n\n- Updated dependencies [8a7eae4]\n  - @redux-devtools/chart-monitor@3.0.0\n  - @redux-devtools/inspector-monitor-test-tab@1.0.0\n  - @redux-devtools/inspector-monitor-trace-tab@1.0.0\n  - @redux-devtools/inspector-monitor@3.0.0\n  - @redux-devtools/log-monitor@4.0.0\n  - @redux-devtools/rtk-query-monitor@3.0.0\n  - @redux-devtools/slider-monitor@4.0.0\n  - @redux-devtools/ui@1.3.0\n  - @redux-devtools/core@3.13.0\n\n## 2.1.4\n\n### Patch Changes\n\n- Updated dependencies [4891bf6]\n  - @redux-devtools/core@3.12.0\n  - @redux-devtools/chart-monitor@2.1.1\n  - @redux-devtools/inspector-monitor@2.1.2\n  - @redux-devtools/log-monitor@3.1.1\n  - @redux-devtools/rtk-query-monitor@2.1.2\n  - @redux-devtools/slider-monitor@3.1.2\n  - @redux-devtools/inspector-monitor-test-tab@0.8.6\n  - @redux-devtools/inspector-monitor-trace-tab@0.3.4\n\n## 2.1.3\n\n### Patch Changes\n\n- ab3c0e2: Avoid persisting the selected action index between sessions\n\n## 2.1.2\n\n### Patch Changes\n\n- 55cc37e: Fix filter to show state-controlled search value\n- Updated dependencies [55cc37e]\n  - @redux-devtools/inspector-monitor@2.1.1\n\n## 2.0.0\n\n- Adds ESM build (https://github.com/reduxjs/redux-devtools/pull/997) and switches the default export to a named export in order to ensure that the CommonJS output and the ESM output are [interchangeable](https://rollupjs.org/guide/en/#outputexports):\n\n```diff\n- import DevToolsApp from '@redux-devtools/app';\n+ import { Root } from '@redux-devtools/app';\n```\n\n## [1.0.0-8](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/app@1.0.0-7...@redux-devtools/app@1.0.0-8) (2021-06-11)\n\n### Bug Fixes\n\n- **app:** fix dependency version of inspector ([#732](https://github.com/reduxjs/redux-devtools/issues/732)) ([30c6971](https://github.com/reduxjs/redux-devtools/commit/30c6971d379c53ec1343a20240b73705751f7445))\n\n## [1.0.0-7](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/app@1.0.0-6...@redux-devtools/app@1.0.0-7) (2021-06-11)\n\n### Bug Fixes\n\n- fix Select types and usages ([#724](https://github.com/reduxjs/redux-devtools/issues/724)) ([07e409d](https://github.com/reduxjs/redux-devtools/commit/07e409de6a1c3d362929d854542df0c1d74ce18e))\n- **app:** remove unimplemented reports tab ([#731](https://github.com/reduxjs/redux-devtools/issues/731)) ([c4a8fa2](https://github.com/reduxjs/redux-devtools/commit/c4a8fa286cfe3f30133c2f948164001bd2a618ac))\n\n## [1.0.0-6](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/app@1.0.0-5...@redux-devtools/app@1.0.0-6) (2021-03-06)\n\n### Features\n\n- update peer dependencies to allow react@^17 ([#703](https://github.com/reduxjs/redux-devtools/issues/703)) ([2aaa9c1](https://github.com/reduxjs/redux-devtools/commit/2aaa9c10a383e3a7ab20b3ab14639781fd7bb2eb))\n\n## 1.0.0-5 (2021-03-06)\n\n**Note:** Version bump only for package @redux-devtools/app\n\n## [1.0.0-4](https://github.com/reduxjs/redux-devtools/compare/redux-devtools-core@1.0.0-3...redux-devtools-core@1.0.0-4) (2020-09-07)\n\n### Bug Fixes\n\n- **redux-devtools-core:** don't mutate source object during stringification ([#627](https://github.com/reduxjs/redux-devtools/issues/627)) ([5259dee](https://github.com/reduxjs/redux-devtools/commit/5259dee601e07c46f8e7af964ab83cb23a4e7b1b))\n\n## [1.0.0-3](https://github.com/reduxjs/redux-devtools/compare/redux-devtools-core@1.0.0-2...redux-devtools-core@1.0.0-3) (2020-08-14)\n\n**Note:** Version bump only for package redux-devtools-core\n"
  },
  {
    "path": "packages/redux-devtools-app/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 Mihail Diordiev\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/redux-devtools-app/README.md",
    "content": "# Redux DevTools monitor app\n\n![Demo](https://raw.githubusercontent.com/zalmoxisus/remote-redux-devtools/master/demo.gif)\n\nWeb, Electron and Chrome app for monitoring [remote-redux-devtools](https://github.com/zalmoxisus/remote-redux-devtools).\n\nAlso it's a react component you can use to build amazing monitor applications like:\n\n- [redux-devtools-extension](https://github.com/zalmoxisus/redux-devtools-extension).\n- [react-native-debugger](https://github.com/jhen0409/react-native-debugger) - Electron app, which already includes `remotedev-server`, `redux-devtools-app` and even React DevTools.\n- [remote-redux-devtools-on-debugger](https://github.com/jhen0409/remote-redux-devtools-on-debugger) - Used in React Native debugger as a dock monitor.\n- [atom-redux-devtools](https://github.com/zalmoxisus/atom-redux-devtools) - Used in Atom editor.\n- [vscode-redux-devtools](https://github.com/jkzing/vscode-redux-devtools) - Used in Visual Studio Code.\n- [intellij-redux-devtools](https://github.com/takanuva15/intellij-redux-devtools) - Used in IntelliJ IDEA.\n\n### Usage\n\n```js\nimport React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport { Root } from '@redux-devtools/app';\n\nconst root = ReactDOM.createRoot(document.getElementById('root'));\nroot.render(<Root />);\n```\n\n### Parameters\n\n- `socketOptions` - _object_ used to specify predefined options for the connection:\n  - `hostname` - _string_\n  - `port` - _number or string_\n  - `autoReconnect` - _boolean_\n  - `secure` - _boolean_.\n- `monitorOptions` - _object_ used to specify predefined monitor options:\n  - `selected` - _string_ - which monitor is selected by default. One of the following values: `LogMonitor`, `InspectorMonitor`, `ChartMonitor`.\n- `testTemplates` - _array_ of strings representing predefined test templates.\n- `noSettings` - _boolean_ set to `true` in order to hide settings button and dialog.\n\n### License\n\nMIT\n"
  },
  {
    "path": "packages/redux-devtools-app/assets/index.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />\n    <title>Redux DevTools</title>\n    <style>\n      body {\n        position: fixed;\n        overflow: hidden;\n        height: 100%;\n        width: 100%;\n        margin: 0;\n        padding: 0;\n      }\n      #root {\n        height: 100%;\n      }\n\n      @media print {\n        @page {\n          size: auto;\n          margin: 0;\n        }\n        body {\n          position: static;\n        }\n        #root > div > div:not(:nth-child(2)) {\n          display: none !important;\n        }\n        #root > div > div:nth-child(2) {\n          overflow: visible !important;\n          position: absolute !important;\n          z-index: 2147483647;\n          page-break-after: avoid;\n        }\n        #root > div > div:nth-child(2) * {\n          overflow: visible !important;\n        }\n      }\n    </style>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/redux-devtools-app/babel.config.json",
    "content": "{\n  \"presets\": [\n    [\"@babel/preset-env\", { \"targets\": \"defaults\" }],\n    \"@babel/preset-react\",\n    \"@babel/preset-typescript\"\n  ],\n  \"plugins\": [\"@babel/plugin-transform-runtime\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-app/buildUmd.mjs",
    "content": "import * as esbuild from 'esbuild';\n\nconst args = process.argv.slice(2);\nconst prod = !args.includes('--dev');\n\nawait esbuild.build({\n  bundle: true,\n  logLevel: 'info',\n  format: 'iife',\n  globalName: 'ReduxDevToolsApp',\n  outfile: prod ? 'umd/redux-devtools-app.min.js' : 'umd/redux-devtools-app.js',\n  minify: prod,\n  sourcemap: true,\n  define: {\n    'process.env.NODE_ENV': prod ? '\"production\"' : '\"development\"',\n  },\n  entryPoints: ['src/index.tsx'],\n  loader: {\n    '.woff2': 'dataurl',\n  },\n  plugins: [\n    importAsGlobals({\n      react: 'React',\n      'react-dom': 'ReactDOM',\n    }),\n  ],\n});\n\n// https://github.com/evanw/esbuild/issues/337#issuecomment-954633403\nfunction importAsGlobals(mapping) {\n  // https://stackoverflow.com/a/3561711/153718\n  const escRe = (s) => s.replace(/[-/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&');\n  const filter = new RegExp(\n    Object.keys(mapping)\n      .map((mod) => `^${escRe(mod)}$`)\n      .join('|'),\n  );\n\n  return {\n    name: 'global-imports',\n    setup(build) {\n      build.onResolve({ filter }, (args) => {\n        if (!mapping[args.path]) {\n          throw new Error('Unknown global: ' + args.path);\n        }\n        return {\n          path: args.path,\n          namespace: 'external-global',\n        };\n      });\n\n      build.onLoad(\n        {\n          filter,\n          namespace: 'external-global',\n        },\n        async (args) => {\n          const global = mapping[args.path];\n          return {\n            contents: `module.exports = ${global};`,\n            loader: 'js',\n          };\n        },\n      );\n    },\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-app/demo/index.tsx",
    "content": "import React from 'react';\nimport { createRoot } from 'react-dom/client';\nimport { Root } from '../lib';\n\nconst root = createRoot(document.getElementById('root')!);\nroot.render(<Root />);\n\nif (module.hot) {\n  // https://github.com/webpack/webpack/issues/418#issuecomment-53398056\n  module.hot.accept((err) => {\n    if (err) console.error(err.message); // eslint-disable-line no-console\n  });\n\n  /*\n    module.hot.accept('./app', () => {\n      const NextApp = require('./app').default;\n      render(\n        <NextApp />,\n        document.getElementById('root')\n      );\n    });\n   */\n}\n"
  },
  {
    "path": "packages/redux-devtools-app/eslint.config.mjs",
    "content": "import globals from 'globals';\nimport eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTsReact from '../../eslint.ts.react.config.base.mjs';\nimport eslintTsReactJest from '../../eslint.ts.react.jest.config.base.mjs';\nimport eslintTs from '../../eslint.ts.react.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTsReact(import.meta.dirname),\n  ...eslintTsReact(\n    import.meta.dirname,\n    ['demo/**/*.ts', 'demo/**/*.tsx'],\n    ['./tsconfig.demo.json'],\n  ),\n  ...eslintTsReactJest(import.meta.dirname),\n  ...eslintTs(\n    import.meta.dirname,\n    ['webpack.config.ts'],\n    ['./tsconfig.webpack.json'],\n  ),\n  {\n    ignores: ['build', 'lib', 'umd'],\n  },\n  {\n    files: ['buildUmd.mjs'],\n    languageOptions: {\n      globals: {\n        ...globals.nodeBuiltin,\n      },\n    },\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-app/package.json",
    "content": "{\n  \"name\": \"@redux-devtools/app\",\n  \"version\": \"8.0.0\",\n  \"description\": \"Redux DevTools app\",\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-app\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)\",\n  \"files\": [\n    \"build\",\n    \"lib\",\n    \"src\",\n    \"umd\"\n  ],\n  \"exports\": {\n    \".\": \"./lib/index.js\",\n    \"./package.json\": \"./package.json\"\n  },\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"start\": \"cross-env TS_NODE_PROJECT=\\\"tsconfig.webpack.json\\\" webpack serve --hot --env development --env platform=web --progress\",\n    \"build\": \"pnpm run build:lib && pnpm run build:web && pnpm run build:umd && pnpm run build:umd:min\",\n    \"build:lib\": \"tsc\",\n    \"build:web\": \"cross-env TS_NODE_PROJECT=\\\"tsconfig.webpack.json\\\" webpack --env platform=web\",\n    \"build:umd\": \"node buildUmd.mjs --dev\",\n    \"build:umd:min\": \"node buildUmd.mjs\",\n    \"clean\": \"rimraf build lib umd\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run type-check && pnpm run lint\"\n  },\n  \"dependencies\": {\n    \"@redux-devtools/app-core\": \"workspace:^\",\n    \"@redux-devtools/ui\": \"workspace:^\",\n    \"localforage\": \"^1.10.0\",\n    \"jsan\": \"^3.1.14\",\n    \"react-redux\": \"^9.2.0\",\n    \"redux\": \"^5.0.1\",\n    \"redux-persist\": \"^6.0.0\",\n    \"socketcluster-client\": \"^20.0.1\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.29.0\",\n    \"@babel/eslint-parser\": \"^7.28.6\",\n    \"@babel/plugin-transform-runtime\": \"^7.29.0\",\n    \"@babel/preset-env\": \"^7.29.0\",\n    \"@babel/preset-react\": \"^7.28.5\",\n    \"@babel/preset-typescript\": \"^7.28.5\",\n    \"@emotion/react\": \"^11.14.0\",\n    \"@emotion/styled\": \"^11.14.1\",\n    \"@reduxjs/toolkit\": \"^2.11.2\",\n    \"@rjsf/core\": \"^6.4.1\",\n    \"@types/jsan\": \"^3.1.5\",\n    \"@types/json-schema\": \"^7.0.15\",\n    \"@types/node\": \"^24.12.0\",\n    \"@types/react\": \"^19.2.14\",\n    \"@types/react-dom\": \"^19.2.3\",\n    \"@types/socketcluster-client\": \"^20.0.0\",\n    \"@types/webpack-env\": \"^1.18.8\",\n    \"babel-loader\": \"^10.1.1\",\n    \"cross-env\": \"^10.1.0\",\n    \"css-loader\": \"^7.1.4\",\n    \"esbuild\": \"^0.27.4\",\n    \"fork-ts-checker-webpack-plugin\": \"^9.1.0\",\n    \"globals\": \"^17.4.0\",\n    \"html-loader\": \"^5.1.0\",\n    \"html-webpack-plugin\": \"^5.6.6\",\n    \"react\": \"^19.2.4\",\n    \"react-dom\": \"^19.2.4\",\n    \"rimraf\": \"^6.1.3\",\n    \"style-loader\": \"^4.0.0\",\n    \"ts-jest\": \"^29.4.6\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"~5.9.3\",\n    \"webpack\": \"^5.105.4\",\n    \"webpack-cli\": \"^7.0.0\",\n    \"webpack-dev-server\": \"^5.2.3\"\n  },\n  \"peerDependencies\": {\n    \"@emotion/react\": \"^11.14.0\",\n    \"@emotion/styled\": \"^11.14.1\",\n    \"@reduxjs/toolkit\": \"^1.0.0 || ^2.0.0\",\n    \"@types/react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react\": \"^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-app/src/actions/index.ts",
    "content": "import { AuthStates, States } from 'socketcluster-client/lib/clientsocket.js';\nimport {\n  CoreStoreActionWithoutUpdateStateOrLiftedAction,\n  LiftedActionAction,\n  UPDATE_REPORTS,\n  UPDATE_STATE,\n  UpdateStateAction,\n} from '@redux-devtools/app-core';\nimport {\n  AUTH_ERROR,\n  AUTH_REQUEST,\n  AUTH_SUCCESS,\n  CONNECT_ERROR,\n  CONNECT_REQUEST,\n  CONNECT_SUCCESS,\n  DEAUTHENTICATE,\n  DISCONNECTED,\n  EMIT,\n  RECONNECT,\n  SUBSCRIBE_ERROR,\n  SUBSCRIBE_REQUEST,\n  SUBSCRIBE_SUCCESS,\n  UNSUBSCRIBE,\n} from '../constants/socketActionTypes.js';\n\nexport type ConnectionType = 'disabled' | 'custom';\nexport interface ConnectionOptions {\n  readonly type: ConnectionType;\n  readonly hostname: string;\n  readonly port: number;\n  readonly secure: boolean;\n}\nexport interface ReconnectAction {\n  readonly type: typeof RECONNECT;\n  readonly options: ConnectionOptions;\n}\nexport function saveSocketSettings(\n  options: ConnectionOptions,\n): ReconnectAction {\n  return { type: RECONNECT, options };\n}\n\nexport interface ConnectRequestAction {\n  type: typeof CONNECT_REQUEST;\n}\n\ninterface ConnectSuccessPayload {\n  id: string;\n  authState: AuthStates;\n  socketState: States;\n}\nexport interface ConnectSuccessAction {\n  type: typeof CONNECT_SUCCESS;\n  payload: ConnectSuccessPayload;\n  error: Error | undefined;\n}\n\nexport interface ConnectErrorAction {\n  type: typeof CONNECT_ERROR;\n  error: Error | undefined;\n}\n\nexport interface AuthRequestAction {\n  type: typeof AUTH_REQUEST;\n}\n\nexport interface AuthSuccessAction {\n  type: typeof AUTH_SUCCESS;\n  baseChannel: string;\n}\n\nexport interface AuthErrorAction {\n  type: typeof AUTH_ERROR;\n  error: Error;\n}\n\nexport interface DisconnectedAction {\n  type: typeof DISCONNECTED;\n  code: number;\n}\n\nexport interface DeauthenticateAction {\n  type: typeof DEAUTHENTICATE;\n}\n\nexport interface SubscribeRequestAction {\n  type: typeof SUBSCRIBE_REQUEST;\n  channel: string;\n  subscription: typeof UPDATE_STATE | typeof UPDATE_REPORTS;\n}\n\nexport interface SubscribeSuccessAction {\n  type: typeof SUBSCRIBE_SUCCESS;\n  channel: string;\n}\n\nexport interface SubscribeErrorAction {\n  type: typeof SUBSCRIBE_ERROR;\n  error: Error;\n  status: string;\n}\n\nexport interface UnsubscribeAction {\n  type: typeof UNSUBSCRIBE;\n  channel: string;\n}\n\nexport interface EmitAction {\n  type: typeof EMIT;\n  message: string;\n  id?: string | number | false;\n  instanceId?: string | number;\n  action?: unknown;\n  state?: unknown;\n}\n\nexport type StoreActionWithoutUpdateStateOrLiftedAction =\n  | CoreStoreActionWithoutUpdateStateOrLiftedAction\n  | ReconnectAction\n  | ConnectRequestAction\n  | ConnectSuccessAction\n  | ConnectErrorAction\n  | AuthRequestAction\n  | AuthSuccessAction\n  | AuthErrorAction\n  | DisconnectedAction\n  | DeauthenticateAction\n  | SubscribeRequestAction\n  | SubscribeSuccessAction\n  | SubscribeErrorAction\n  | UnsubscribeAction\n  | EmitAction;\n\nexport type StoreActionWithoutUpdateState =\n  | StoreActionWithoutUpdateStateOrLiftedAction\n  | LiftedActionAction;\n\nexport type StoreActionWithoutLiftedAction =\n  | StoreActionWithoutUpdateStateOrLiftedAction\n  | UpdateStateAction;\n\nexport type StoreAction = StoreActionWithoutUpdateState | UpdateStateAction;\n"
  },
  {
    "path": "packages/redux-devtools-app/src/components/Settings/Connection.tsx",
    "content": "import React, { Component } from 'react';\nimport { connect, ResolveThunks } from 'react-redux';\nimport { Container, Form } from '@redux-devtools/ui';\nimport { JSONSchema7Definition, JSONSchema7TypeName } from 'json-schema';\nimport { ConnectionType, saveSocketSettings } from '../../actions/index.js';\nimport { StoreState } from '../../reducers/index.js';\nimport { ConnectionStateOptions } from '../../reducers/connection.js';\nimport { IChangeEvent } from '@rjsf/core';\n\ndeclare module 'json-schema' {\n  export interface JSONSchema7 {\n    enumNames?: JSONSchema7Type[];\n  }\n}\n\ninterface Schema {\n  type: JSONSchema7TypeName;\n  required?: string[];\n  properties: {\n    [key: string]: JSONSchema7Definition;\n  };\n}\n\nconst defaultSchema: Schema = {\n  type: 'object',\n  required: [],\n  properties: {\n    type: {\n      title: 'Connection settings (for getting reports and remote debugging)',\n      type: 'string',\n      enum: ['disabled', 'custom'],\n      enumNames: ['no remote connection', 'use local (custom) server'],\n    },\n    hostname: {\n      type: 'string',\n    },\n    port: {\n      type: 'number',\n    },\n    secure: {\n      type: 'boolean',\n    },\n  },\n};\n\nconst uiSchema = {\n  type: {\n    'ui:widget': 'radio',\n  },\n};\n\ntype StateProps = ReturnType<typeof mapStateToProps>;\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ntype Props = StateProps & DispatchProps;\n\ninterface FormData extends ConnectionStateOptions {\n  readonly type: ConnectionType;\n}\n\ninterface State {\n  readonly formData: FormData;\n  readonly type: ConnectionType;\n  readonly schema: Schema;\n  readonly changed: boolean | undefined;\n}\n\nexport class Connection extends Component<Props, State> {\n  setFormData = (type: ConnectionType, changed?: boolean) => {\n    let schema: Schema;\n    if (type !== 'custom') {\n      schema = {\n        type: 'object',\n        properties: { type: defaultSchema.properties.type },\n      };\n    } else {\n      schema = defaultSchema;\n    }\n    return {\n      formData: {\n        type,\n        ...this.props.options,\n      },\n      type,\n      schema,\n      changed,\n    };\n  };\n\n  state: State = this.setFormData(this.props.type);\n\n  shouldComponentUpdate(nextProps: Props, nextState: State) {\n    return this.state !== nextState;\n  }\n\n  UNSAFE_componentWillReceiveProps(nextProps: Props) {\n    if (this.props.options !== nextProps.options) {\n      this.setState({\n        formData: { ...nextProps.options, type: nextProps.type },\n      });\n    }\n  }\n\n  handleSave = (data: IChangeEvent<FormData>) => {\n    this.props.saveSettings(data.formData!);\n    this.setState({ changed: false });\n  };\n\n  handleChange = (data: IChangeEvent<FormData>) => {\n    const formData = data.formData!;\n    const type = formData.type;\n    if (type !== this.state.type) {\n      this.setState(this.setFormData(type, true));\n    } else if (!this.state.changed) {\n      this.setState({ changed: true, formData });\n    }\n  };\n\n  render() {\n    const type = this.state.type || 'disabled';\n    const changed = this.state.changed;\n    const disabled = type === 'disabled';\n\n    return (\n      <Container>\n        <Form\n          primaryButton={changed}\n          noSubmit={disabled && !changed}\n          submitText={disabled ? 'Disconnect' : 'Connect'}\n          formData={this.state.formData}\n          schema={this.state.schema}\n          uiSchema={uiSchema}\n          onChange={this.handleChange}\n          onSubmit={this.handleSave}\n        />\n      </Container>\n    );\n  }\n}\n\nconst mapStateToProps = (state: StoreState) => state.connection;\n\nconst actionCreators = {\n  saveSettings: saveSocketSettings,\n};\n\nexport default connect(mapStateToProps, actionCreators)(Connection);\n"
  },
  {
    "path": "packages/redux-devtools-app/src/constants/socketActionTypes.ts",
    "content": "import socketCluster from 'socketcluster-client';\n\ninterface States {\n  CLOSED: 'closed';\n  CONNECTING: 'connecting';\n  OPEN: 'open';\n  AUTHENTICATED: 'authenticated';\n  PENDING: 'pending';\n  UNAUTHENTICATED: 'unauthenticated';\n}\n\nexport const {\n  CLOSED,\n  CONNECTING,\n  OPEN,\n  AUTHENTICATED,\n  PENDING,\n  UNAUTHENTICATED,\n} = socketCluster.AGClientSocket as unknown as States;\nexport const CONNECT_REQUEST = 'socket/CONNECT_REQUEST';\nexport const CONNECT_SUCCESS = 'socket/CONNECT_SUCCESS';\nexport const CONNECT_ERROR = 'socket/CONNECT_ERROR';\nexport const RECONNECT = 'socket/RECONNECT';\nexport const AUTH_REQUEST = 'socket/AUTH_REQUEST';\nexport const AUTH_SUCCESS = 'socket/AUTH_SUCCESS';\nexport const AUTH_ERROR = 'socket/AUTH_ERROR';\nexport const DISCONNECTED = 'socket/DISCONNECTED';\nexport const DEAUTHENTICATE = 'socket/DEAUTHENTICATE';\nexport const SUBSCRIBE_REQUEST = 'socket/SUBSCRIBE_REQUEST';\nexport const SUBSCRIBE_SUCCESS = 'socket/SUBSCRIBE_SUCCESS';\nexport const SUBSCRIBE_ERROR = 'socket/SUBSCRIBE_ERROR';\nexport const UNSUBSCRIBE = 'socket/UNSUBSCRIBE';\nexport const EMIT = 'socket/EMIT';\n"
  },
  {
    "path": "packages/redux-devtools-app/src/index.tsx",
    "content": "import React, { Component } from 'react';\nimport { Provider } from 'react-redux';\nimport { Store } from 'redux';\nimport { Persistor } from 'redux-persist';\nimport { PersistGate } from 'redux-persist/integration/react';\nimport { App } from '@redux-devtools/app-core';\nimport { StoreState } from './reducers/index.js';\nimport { StoreAction } from './actions/index.js';\nimport { CONNECT_REQUEST } from './constants/socketActionTypes.js';\nimport Connection from './components/Settings/Connection.js';\nimport configureStore from './store/configureStore.js';\n\nexport class Root extends Component {\n  store?: Store<StoreState, StoreAction>;\n  persistor?: Persistor;\n\n  UNSAFE_componentWillMount() {\n    const { store, persistor } = configureStore(\n      (store: Store<StoreState, StoreAction>) => {\n        if (store.getState().connection.type !== 'disabled') {\n          store.dispatch({\n            type: CONNECT_REQUEST,\n          });\n        }\n      },\n    );\n    this.store = store;\n    this.persistor = persistor;\n  }\n\n  render() {\n    if (!this.store) return null;\n    return (\n      <Provider store={this.store}>\n        <PersistGate loading={null} persistor={this.persistor!}>\n          <App\n            extraSettingsTabs={[{ name: 'Connection', component: Connection }]}\n          />\n        </PersistGate>\n      </Provider>\n    );\n  }\n}\n\nexport * from '@redux-devtools/app-core';\nexport * from './actions/index.js';\nexport * from './constants/socketActionTypes.js';\nexport * from './middlewares/api.js';\nexport * from './reducers/index.js';\nexport * from './reducers/connection.js';\nexport * from './reducers/socket.js';\nexport * from './utils/monitorActions.js';\n"
  },
  {
    "path": "packages/redux-devtools-app/src/middlewares/api.ts",
    "content": "import {\n  DispatchAction,\n  GET_REPORT_ERROR,\n  GET_REPORT_REQUEST,\n  GET_REPORT_SUCCESS,\n  CLEAR_INSTANCES,\n  getActiveInstance,\n  importState,\n  LIFTED_ACTION,\n  LiftedActionAction,\n  REMOVE_INSTANCE,\n  Request,\n  showNotification,\n  UPDATE_REPORTS,\n  UPDATE_STATE,\n  UpdateReportsRequest,\n} from '@redux-devtools/app-core';\nimport socketClusterClient, { AGClientSocket } from 'socketcluster-client';\nimport { stringify } from 'jsan';\nimport { Dispatch, Middleware, MiddlewareAPI } from 'redux';\nimport * as actions from '../constants/socketActionTypes.js';\nimport { nonReduxDispatch } from '../utils/monitorActions.js';\nimport { EmitAction, StoreAction } from '../actions/index.js';\nimport { StoreState } from '../reducers/index.js';\n\nlet socket: AGClientSocket;\nlet store: MiddlewareAPI<Dispatch<StoreAction>, StoreState>;\n\nfunction emit({ message: type, id, instanceId, action, state }: EmitAction) {\n  void socket.transmit(id ? `sc-${id}` : 'respond', {\n    type,\n    action,\n    state,\n    instanceId,\n  });\n}\n\nfunction startMonitoring(channel: string) {\n  if (channel !== store.getState().socket.baseChannel) return;\n  store.dispatch({ type: actions.EMIT, message: 'START' });\n}\n\nfunction dispatchRemoteAction({\n  message,\n  action,\n  state,\n  toAll,\n}: LiftedActionAction) {\n  const instances = store.getState().instances;\n  const instanceId = getActiveInstance(instances);\n  const id = !toAll && instances.options[instanceId].connectionId;\n  store.dispatch({\n    type: actions.EMIT,\n    message,\n    action,\n    state: nonReduxDispatch(\n      store,\n      message,\n      instanceId,\n      action as DispatchAction,\n      state,\n      instances,\n    ),\n    instanceId,\n    id,\n  });\n}\n\ninterface RequestBase {\n  id?: string;\n  instanceId?: string;\n}\ninterface DisconnectedAction extends RequestBase {\n  type: 'DISCONNECTED';\n  id: string;\n}\ninterface StartAction extends RequestBase {\n  type: 'START';\n  id: string;\n}\ninterface ErrorAction extends RequestBase {\n  type: 'ERROR';\n  payload: string;\n}\ninterface RequestWithData extends RequestBase {\n  data: Request;\n}\ntype MonitoringRequest =\n  | DisconnectedAction\n  | StartAction\n  | ErrorAction\n  | Request;\n\nfunction monitoring(request: MonitoringRequest) {\n  if (request.type === 'DISCONNECTED') {\n    store.dispatch({\n      type: REMOVE_INSTANCE,\n      id: request.id,\n    });\n    return;\n  }\n  if (request.type === 'START') {\n    store.dispatch({ type: actions.EMIT, message: 'START', id: request.id });\n    return;\n  }\n\n  if (request.type === 'ERROR') {\n    store.dispatch(showNotification(request.payload));\n    return;\n  }\n\n  store.dispatch({\n    type: UPDATE_STATE,\n    request: (request as unknown as RequestWithData).data\n      ? { ...(request as unknown as RequestWithData).data, id: request.id }\n      : request,\n  });\n\n  const instances = store.getState().instances;\n  const instanceId = request.instanceId || request.id;\n  if (\n    instances.sync &&\n    instanceId === instances.selected &&\n    (request.type === 'ACTION' || request.type === 'STATE')\n  ) {\n    void socket.transmit('respond', {\n      type: 'SYNC',\n      state: stringify(instances.states[instanceId]),\n      id: request.id,\n      instanceId,\n    });\n  }\n}\n\nfunction subscribe(\n  channelName: string,\n  subscription: typeof UPDATE_STATE | typeof UPDATE_REPORTS,\n) {\n  const channel = socket.subscribe(channelName);\n  if (subscription === UPDATE_STATE) {\n    void (async () => {\n      for await (const data of channel) {\n        monitoring(data as MonitoringRequest);\n      }\n    })();\n  } else {\n    const watcher = (request: UpdateReportsRequest) => {\n      store.dispatch({ type: subscription, request });\n    };\n    void (async () => {\n      for await (const data of channel) {\n        watcher(data as UpdateReportsRequest);\n      }\n    })();\n  }\n}\n\nfunction handleConnection() {\n  void (async () => {\n    for await (const data of socket.listener('connect')) {\n      store.dispatch({\n        type: actions.CONNECT_SUCCESS,\n        payload: {\n          id: data.id,\n          authState: socket.authState,\n          socketState: socket.state,\n        },\n        // @ts-expect-error Is this legitimate?\n        error: data.authError,\n      });\n      if (socket.authState !== actions.AUTHENTICATED) {\n        store.dispatch({ type: actions.AUTH_REQUEST });\n      }\n    }\n  })();\n  void (async () => {\n    for await (const data of socket.listener('disconnect')) {\n      store.dispatch({ type: actions.DISCONNECTED, code: data.code });\n      store.dispatch({ type: CLEAR_INSTANCES });\n    }\n  })();\n\n  void (async () => {\n    for await (const data of socket.listener('subscribe')) {\n      store.dispatch({\n        type: actions.SUBSCRIBE_SUCCESS,\n        channel: data.channel,\n      });\n    }\n  })();\n  void (async () => {\n    for await (const data of socket.listener('unsubscribe')) {\n      void socket.unsubscribe(data.channel);\n      store.dispatch({ type: actions.UNSUBSCRIBE, channel: data.channel });\n    }\n  })();\n  void (async () => {\n    for await (const data of socket.listener('subscribeFail')) {\n      store.dispatch({\n        type: actions.SUBSCRIBE_ERROR,\n        error: data.error,\n        status: 'subscribeFail',\n      });\n    }\n  })();\n\n  void (async () => {\n    for await (const data of socket.listener('error')) {\n      store.dispatch({ type: actions.CONNECT_ERROR, error: data.error });\n    }\n  })();\n}\n\nfunction connect() {\n  if (process.env.NODE_ENV === 'test') return;\n  const connection = store.getState().connection;\n  try {\n    socket = socketClusterClient.create(connection.options);\n    handleConnection();\n  } catch (error) {\n    store.dispatch({ type: actions.CONNECT_ERROR, error: error as Error });\n    store.dispatch(\n      showNotification((error as Error).message || (error as string)),\n    );\n  }\n}\n\nfunction disconnect() {\n  if (socket) {\n    socket.disconnect();\n  }\n}\n\nfunction login() {\n  void (async () => {\n    try {\n      const baseChannel = (await socket.invoke('login', {})) as string;\n      store.dispatch({ type: actions.AUTH_SUCCESS, baseChannel });\n      store.dispatch({\n        type: actions.SUBSCRIBE_REQUEST,\n        channel: baseChannel,\n        subscription: UPDATE_STATE,\n      });\n      store.dispatch({\n        type: actions.SUBSCRIBE_REQUEST,\n        channel: 'report',\n        subscription: UPDATE_REPORTS,\n      });\n    } catch (error) {\n      store.dispatch({ type: actions.AUTH_ERROR, error: error as Error });\n    }\n  })();\n}\n\nfunction getReport(reportId: unknown) {\n  void (async () => {\n    try {\n      const data = (await socket.invoke('getReport', reportId)) as {\n        payload: string;\n      };\n      store.dispatch({ type: GET_REPORT_SUCCESS, data });\n      store.dispatch(importState(data.payload));\n    } catch (error) {\n      store.dispatch({ type: GET_REPORT_ERROR, error: error as Error });\n    }\n  })();\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport const api: Middleware<{}, StoreState, Dispatch<StoreAction>> = (\n  inStore,\n) => {\n  store = inStore;\n  return (next) => (untypedAction) => {\n    const result = next(untypedAction);\n\n    const action = untypedAction as StoreAction;\n    switch (action.type) {\n      case actions.CONNECT_REQUEST:\n        connect();\n        break;\n      case actions.RECONNECT:\n        disconnect();\n        if (action.options.type !== 'disabled') connect();\n        break;\n      case actions.AUTH_REQUEST:\n        login();\n        break;\n      case actions.SUBSCRIBE_REQUEST:\n        subscribe(action.channel, action.subscription);\n        break;\n      case actions.SUBSCRIBE_SUCCESS:\n        startMonitoring(action.channel);\n        break;\n      case actions.EMIT:\n        if (socket) emit(action);\n        break;\n      case LIFTED_ACTION:\n        dispatchRemoteAction(action);\n        break;\n      case GET_REPORT_REQUEST:\n        getReport(action.report);\n        break;\n    }\n    return result;\n  };\n};\n"
  },
  {
    "path": "packages/redux-devtools-app/src/reducers/connection.ts",
    "content": "import { RECONNECT } from '../constants/socketActionTypes.js';\nimport { ConnectionType, StoreAction } from '../actions/index.js';\n\nexport interface ConnectionStateOptions {\n  readonly hostname: string;\n  readonly port: number;\n  readonly secure: boolean;\n}\nexport interface ConnectionState {\n  readonly options: ConnectionStateOptions;\n  readonly type: ConnectionType;\n}\n\nexport function connection(\n  state: ConnectionState = {\n    options: { hostname: 'localhost', port: 8000, secure: false },\n    type: 'disabled',\n  },\n  action: StoreAction,\n) {\n  if (action.type === RECONNECT) {\n    const { type, ...options } = action.options;\n    return { ...state, type, options };\n  }\n  return state;\n}\n"
  },
  {
    "path": "packages/redux-devtools-app/src/reducers/index.ts",
    "content": "import { CoreStoreState, coreReducers } from '@redux-devtools/app-core';\nimport { combineReducers } from 'redux';\nimport { connection, ConnectionState } from './connection.js';\nimport { socket, SocketState } from './socket.js';\n\nexport interface StoreState extends CoreStoreState {\n  readonly connection: ConnectionState;\n  readonly socket: SocketState;\n}\n\nexport const rootReducer = combineReducers({\n  ...coreReducers,\n  connection,\n  socket,\n});\n"
  },
  {
    "path": "packages/redux-devtools-app/src/reducers/socket.ts",
    "content": "import { AuthStates, States } from 'socketcluster-client/lib/clientsocket.js';\nimport * as actions from '../constants/socketActionTypes.js';\nimport { StoreAction } from '../actions/index.js';\n\nexport interface SocketState {\n  id: string | null;\n  channels: string[];\n  socketState: States;\n  authState: AuthStates | 'pending';\n  error: Error | undefined;\n  baseChannel?: string;\n  authToken?: null;\n}\n\nconst initialState: SocketState = {\n  id: null,\n  channels: [],\n  socketState: actions.CLOSED,\n  authState: actions.PENDING,\n  error: undefined,\n};\n\nexport function socket(state = initialState, action: StoreAction): SocketState {\n  switch (action.type) {\n    case actions.CONNECT_REQUEST: {\n      return {\n        ...state,\n        socketState: actions.CONNECTING,\n      };\n    }\n    case actions.CONNECT_ERROR:\n      return {\n        ...state,\n        error: action.error,\n      };\n    case actions.CONNECT_SUCCESS:\n      return {\n        ...state,\n        id: action.payload.id,\n        socketState: action.payload.socketState,\n        authState: action.payload.authState,\n        error: action.error,\n      };\n    case actions.AUTH_REQUEST:\n      return {\n        ...state,\n        authState: actions.PENDING,\n      };\n    case actions.AUTH_SUCCESS:\n      return {\n        ...state,\n        authState: actions.AUTHENTICATED,\n        baseChannel: action.baseChannel,\n      };\n    case actions.AUTH_ERROR:\n      return {\n        ...state,\n        authState: actions.UNAUTHENTICATED,\n        error: action.error,\n      };\n    case actions.DEAUTHENTICATE:\n      return {\n        ...state,\n        authState: actions.UNAUTHENTICATED,\n        authToken: null,\n      };\n    case actions.SUBSCRIBE_SUCCESS:\n      return {\n        ...state,\n        channels: [...state.channels, action.channel],\n      };\n    case actions.UNSUBSCRIBE:\n      return {\n        ...state,\n        channels: state.channels.filter(\n          (channel) => channel !== action.channel,\n        ),\n      };\n    case actions.DISCONNECTED:\n      return initialState;\n    default:\n      return state;\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-app/src/store/configureStore.ts",
    "content": "import { middlewares } from '@redux-devtools/app-core';\nimport { createStore, compose, applyMiddleware, Reducer, Store } from 'redux';\nimport localForage from 'localforage';\nimport { persistReducer, persistStore } from 'redux-persist';\nimport { api } from '../middlewares/api.js';\nimport { StoreState, rootReducer } from '../reducers/index.js';\nimport { StoreAction } from '../actions/index.js';\n\nconst persistConfig = {\n  key: 'redux-devtools',\n  blacklist: ['instances', 'socket'],\n  storage: localForage,\n};\n\nconst persistedReducer: Reducer<StoreState, StoreAction> = persistReducer(\n  persistConfig,\n  rootReducer as unknown as Reducer<StoreState, StoreAction>,\n) as any;\n\nexport default function configureStore(\n  callback: (store: Store<StoreState, StoreAction>) => void,\n) {\n  let composeEnhancers = compose;\n  if (process.env.NODE_ENV !== 'production') {\n    if (\n      (\n        window as unknown as {\n          __REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof compose;\n        }\n      ).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__\n    ) {\n      composeEnhancers = (\n        window as unknown as {\n          __REDUX_DEVTOOLS_EXTENSION_COMPOSE__: typeof compose;\n        }\n      ).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__;\n    }\n  }\n\n  const store = createStore(\n    persistedReducer,\n    composeEnhancers(applyMiddleware(...middlewares, api)),\n  );\n  const persistor = persistStore(store as Store, null, () => {\n    callback(store);\n  });\n  return { store, persistor };\n}\n"
  },
  {
    "path": "packages/redux-devtools-app/src/utils/monitorActions.ts",
    "content": "import {\n  DispatchAction,\n  InstancesState,\n  SET_STATE,\n  State,\n  stringifyJSON,\n} from '@redux-devtools/app-core';\nimport { Dispatch, MiddlewareAPI } from 'redux';\nimport { StoreActionWithoutLiftedAction } from '../actions/index.js';\n\nexport function sweep(state: State): State {\n  const skippedActionIdsSet = new Set(state.skippedActionIds);\n\n  return {\n    ...state,\n    actionsById: Object.fromEntries(\n      Object.entries(state.actionsById).filter(\n        ([actionId]) => !skippedActionIdsSet.has(parseInt(actionId, 10)),\n      ),\n    ),\n    stagedActionIds: state.stagedActionIds.filter(\n      (actionId) => !skippedActionIdsSet.has(actionId),\n    ),\n    skippedActionIds: [],\n    currentStateIndex: Math.min(\n      state.currentStateIndex,\n      state.stagedActionIds.length - 1,\n    ),\n  };\n}\n\nexport function nonReduxDispatch(\n  store: MiddlewareAPI<\n    Dispatch<StoreActionWithoutLiftedAction>,\n    { readonly instances: InstancesState }\n  >,\n  message: string,\n  instanceId: string | number,\n  action: DispatchAction,\n  initialState: string | undefined,\n  preInstances?: InstancesState,\n) {\n  const instances = preInstances || store.getState().instances;\n  const state = instances.states[instanceId];\n  const options = instances.options[instanceId];\n\n  if (message !== 'DISPATCH') {\n    if (message === 'IMPORT') {\n      if (options.features.import === true) {\n        return stringifyJSON(\n          state.computedStates[state.currentStateIndex].state,\n          true,\n        );\n      }\n      return initialState;\n    }\n    return undefined;\n  }\n\n  if (options.lib === 'redux') return undefined;\n\n  switch (action.type) {\n    case 'TOGGLE_ACTION':\n      return stringifyJSON(state, true);\n    case 'JUMP_TO_STATE':\n      return stringifyJSON(state.computedStates[action.index].state, true);\n    case 'JUMP_TO_ACTION':\n      return stringifyJSON(\n        state.computedStates[state.stagedActionIds.indexOf(action.actionId)]\n          .state,\n        true,\n      );\n    case 'ROLLBACK':\n      return stringifyJSON(state.computedStates[0].state, true);\n    case 'SWEEP':\n      store.dispatch({ type: SET_STATE, newState: sweep(state) });\n      return undefined;\n    default:\n      return undefined;\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-app/tsconfig.demo.json",
    "content": "{\n  \"extends\": \"../../tsconfig.react.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"webpack-env\"]\n  },\n  \"include\": [\"demo\", \"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-app/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\",\n    \"types\": []\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-app/tsconfig.webpack.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"webpack-dev-server\"]\n  },\n  \"include\": [\"webpack.config.ts\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-app/webpack.config.ts",
    "content": "import * as path from 'path';\nimport webpack from 'webpack';\nimport HtmlWebpackPlugin from 'html-webpack-plugin';\nimport ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';\n\nexport default (\n  env: { development?: boolean; platform?: string } = {},\n): webpack.Configuration => ({\n  mode: env.development ? 'development' : 'production',\n  entry: {\n    app: './demo/index',\n  },\n  output: {\n    path: path.resolve(import.meta.dirname, `build/${env.platform as string}`),\n    publicPath: '',\n    filename: 'js/[name].js',\n    sourceMapFilename: 'js/[name].map',\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.(js|ts)x?$/,\n        loader: 'babel-loader',\n        exclude: /node_modules/,\n      },\n      {\n        test: /\\.html$/,\n        loader: 'html-loader',\n      },\n      {\n        test: /\\.css$/,\n        use: [{ loader: 'style-loader' }, { loader: 'css-loader' }],\n      },\n      {\n        test: /\\.woff2$/,\n        type: 'asset/resource',\n      },\n    ],\n  },\n  resolve: {\n    extensions: ['.js', '.jsx', '.ts', '.tsx'],\n  },\n  plugins: [\n    new webpack.DefinePlugin({\n      'process.env': {\n        NODE_ENV: JSON.stringify(\n          env.development ? 'development' : 'production',\n        ),\n        PLATFORM: JSON.stringify(env.platform),\n      },\n    }),\n    new HtmlWebpackPlugin({\n      template: 'assets/index.html',\n    }),\n    new ForkTsCheckerWebpackPlugin({\n      typescript: {\n        configFile: 'tsconfig.demo.json',\n      },\n    }),\n  ],\n  optimization: {\n    minimize: false,\n    splitChunks: {\n      cacheGroups: {\n        vendor: {\n          test: /[\\\\/]node_modules[\\\\/]/,\n          name: 'common',\n          chunks: 'all',\n        },\n      },\n    },\n  },\n  performance: {\n    hints: false,\n  },\n  devServer: {\n    port: 3000,\n  },\n  devtool: env.development ? 'eval-source-map' : 'source-map',\n});\n"
  },
  {
    "path": "packages/redux-devtools-app-core/CHANGELOG.md",
    "content": "# @redux-devtools/app-core\n\n## 3.0.0\n\n### Major Changes\n\n- 6481386: Convert remaining packages to ESM\n\n### Patch Changes\n\n- Updated dependencies [d61d31a]\n- Updated dependencies [804e729]\n- Updated dependencies [12849a4]\n- Updated dependencies [804d6bd]\n  - @redux-devtools/ui@3.0.0\n  - @redux-devtools/chart-monitor@6.0.0\n  - @redux-devtools/inspector-monitor@7.0.0\n  - @redux-devtools/inspector-monitor-test-tab@6.0.0\n  - @redux-devtools/inspector-monitor-trace-tab@5.0.0\n  - @redux-devtools/log-monitor@6.0.0\n  - @redux-devtools/rtk-query-monitor@7.0.0\n  - @redux-devtools/slider-monitor@7.0.0\n  - @redux-devtools/core@5.0.0\n\n## 2.0.0\n\n### Major Changes\n\n- 6163276: Replace styled-components with Emotion\n\n### Patch Changes\n\n- Updated dependencies [6163276]\n- Updated dependencies [20883e5]\n  - @redux-devtools/inspector-monitor-test-tab@5.0.0\n  - @redux-devtools/rtk-query-monitor@6.0.0\n  - @redux-devtools/slider-monitor@6.0.0\n  - @redux-devtools/ui@2.0.0\n  - @redux-devtools/inspector-monitor@6.1.2\n\n## 1.1.2\n\n### Patch Changes\n\n- Updated dependencies [17b55ef]\n  - @redux-devtools/rtk-query-monitor@5.2.0\n\n## 1.1.1\n\n### Patch Changes\n\n- Updated dependencies [91f21b2]\n  - @redux-devtools/core@4.1.1\n  - @redux-devtools/chart-monitor@5.1.1\n  - @redux-devtools/inspector-monitor@6.1.1\n  - @redux-devtools/inspector-monitor-test-tab@4.1.1\n  - @redux-devtools/inspector-monitor-trace-tab@4.1.1\n  - @redux-devtools/log-monitor@5.1.1\n  - @redux-devtools/rtk-query-monitor@5.1.1\n  - @redux-devtools/slider-monitor@5.1.1\n\n## 1.1.0\n\n### Minor Changes\n\n- 6830118: Add React 19 to peer deps\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - @redux-devtools/chart-monitor@6.0.0\n  - @redux-devtools/inspector-monitor-test-tab@5.0.0\n  - @redux-devtools/inspector-monitor-trace-tab@5.0.0\n  - @redux-devtools/inspector-monitor@7.0.0\n  - @redux-devtools/log-monitor@6.0.0\n  - @redux-devtools/rtk-query-monitor@6.0.0\n  - @redux-devtools/slider-monitor@6.0.0\n  - @redux-devtools/ui@1.4.0\n  - @redux-devtools/core@4.1.0\n\n## 1.0.0\n\n### Major Changes\n\n- 96ac1f2: Move the logic from @redux-devtools/app into @redux-devtools/app-core\n"
  },
  {
    "path": "packages/redux-devtools-app-core/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Mihail Diordiev\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/redux-devtools-app-core/README.md",
    "content": "# Redux DevTools monitor app core\n\nThe core React component and Redux store for the Redux DevTools monitor app. It is split out to allow you to use it directly for transports other than the standard WebSocket one.\n\n### Usage\n\n```js\nimport { Provider } from 'react-redux';\nimport { Persistor } from 'redux-persist';\nimport { PersistGate } from 'redux-persist/integration/react';\nimport { App } from '@redux-devtools/app-core';\nimport { store, persistor } from \"./yourStore\";\n\nexport function Root() {\n  return (\n    <Provider store={store}>\n      <PersistGate loading={null} persistor={persistor!}>\n        <App />\n      </PersistGate>\n    </Provider>\n  );\n}\n```\n\n### License\n\nMIT\n"
  },
  {
    "path": "packages/redux-devtools-app-core/eslint.config.mjs",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTsReact from '../../eslint.ts.react.config.base.mjs';\nimport eslintTsReactJest from '../../eslint.ts.react.jest.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTsReact(import.meta.dirname),\n  ...eslintTsReactJest(import.meta.dirname),\n  {\n    ignores: ['jest.config.ts', 'lib'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-app-core/jest.config.ts",
    "content": "import { createDefaultEsmPreset, type JestConfigWithTsJest } from 'ts-jest';\n\nconst presetConfig = createDefaultEsmPreset({\n  tsconfig: 'tsconfig.test.json',\n});\n\nconst jestConfig: JestConfigWithTsJest = {\n  ...presetConfig,\n  setupFilesAfterEnv: ['<rootDir>/test/setup.ts'],\n  testEnvironment: 'jsdom',\n  moduleNameMapper: {\n    '^(\\\\.{1,2}/.*)\\\\.js$': '$1',\n    '\\\\.css$': '<rootDir>/test/__mocks__/styleMock.ts',\n  },\n};\n\nexport default jestConfig;\n"
  },
  {
    "path": "packages/redux-devtools-app-core/package.json",
    "content": "{\n  \"name\": \"@redux-devtools/app-core\",\n  \"version\": \"3.0.0\",\n  \"description\": \"Redux DevTools app core\",\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-app-core\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)\",\n  \"files\": [\n    \"build\",\n    \"lib\",\n    \"src\",\n    \"umd\"\n  ],\n  \"exports\": \"./lib/index.js\",\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"test\": \"node --experimental-vm-modules node_modules/jest/bin/jest.js\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run type-check && pnpm run lint && pnpm run test\"\n  },\n  \"dependencies\": {\n    \"@redux-devtools/chart-monitor\": \"workspace:^\",\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@redux-devtools/inspector-monitor\": \"workspace:^\",\n    \"@redux-devtools/inspector-monitor-test-tab\": \"workspace:^\",\n    \"@redux-devtools/inspector-monitor-trace-tab\": \"workspace:^\",\n    \"@redux-devtools/log-monitor\": \"workspace:^\",\n    \"@redux-devtools/rtk-query-monitor\": \"workspace:^\",\n    \"@redux-devtools/slider-monitor\": \"workspace:^\",\n    \"@redux-devtools/ui\": \"workspace:^\",\n    \"d3-state-visualizer\": \"workspace:^\",\n    \"javascript-stringify\": \"^2.1.0\",\n    \"jsan\": \"^3.1.14\",\n    \"jsondiffpatch\": \"^0.7.3\",\n    \"react-icons\": \"^5.6.0\",\n    \"react-is\": \"^19.2.4\"\n  },\n  \"devDependencies\": {\n    \"@emotion/react\": \"^11.14.0\",\n    \"@emotion/styled\": \"^11.14.1\",\n    \"@jest/globals\": \"^30.3.0\",\n    \"@reduxjs/toolkit\": \"^2.11.2\",\n    \"@rjsf/core\": \"^6.4.1\",\n    \"@testing-library/dom\": \"^10.4.1\",\n    \"@testing-library/jest-dom\": \"^6.9.1\",\n    \"@testing-library/react\": \"^16.3.2\",\n    \"@types/jest\": \"^30.0.0\",\n    \"@types/jsan\": \"^3.1.5\",\n    \"@types/json-schema\": \"^7.0.15\",\n    \"@types/node\": \"^24.12.0\",\n    \"@types/react\": \"^19.2.14\",\n    \"@types/react-dom\": \"^19.2.3\",\n    \"cross-env\": \"^10.1.0\",\n    \"esbuild\": \"^0.27.4\",\n    \"jest\": \"^30.3.0\",\n    \"jest-environment-jsdom\": \"^30.3.0\",\n    \"react\": \"^19.2.4\",\n    \"react-dom\": \"^19.2.4\",\n    \"react-redux\": \"^9.2.0\",\n    \"redux\": \"^5.0.1\",\n    \"redux-persist\": \"^6.0.0\",\n    \"rimraf\": \"^6.1.3\",\n    \"ts-jest\": \"^29.4.6\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"~5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"@emotion/react\": \"^11.14.0\",\n    \"@emotion/styled\": \"^11.14.1\",\n    \"@reduxjs/toolkit\": \"^1.0.0 || ^2.0.0\",\n    \"@types/react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react\": \"^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-redux\": \"^8.0.0 || ^9.0.0\",\n    \"redux\": \"^4.0.0 || ^5.0.0\",\n    \"redux-persist\": \"^6.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/actions/index.ts",
    "content": "import { SchemeName, ThemeName } from '@redux-devtools/ui';\nimport { REHYDRATE } from 'redux-persist';\nimport {\n  CHANGE_SECTION,\n  CHANGE_THEME,\n  SELECT_INSTANCE,\n  SELECT_MONITOR,\n  UPDATE_MONITOR_STATE,\n  LIFTED_ACTION,\n  MONITOR_ACTION,\n  EXPORT,\n  TOGGLE_SYNC,\n  TOGGLE_SLIDER,\n  TOGGLE_DISPATCHER,\n  TOGGLE_PERSIST,\n  GET_REPORT_REQUEST,\n  SHOW_NOTIFICATION,\n  CLEAR_NOTIFICATION,\n  UPDATE_STATE,\n  UPDATE_REPORTS,\n  REMOVE_INSTANCE,\n  SET_STATE,\n  GET_REPORT_ERROR,\n  GET_REPORT_SUCCESS,\n  ERROR,\n  SET_PERSIST,\n  CHANGE_STATE_TREE_SETTINGS,\n  CLEAR_INSTANCES,\n} from '../constants/actionTypes.js';\nimport { Action } from 'redux';\nimport { Features, State } from '../reducers/instances.js';\nimport { MonitorStateMonitorState } from '../reducers/monitor.js';\nimport { LiftedAction } from '@redux-devtools/core';\nimport { Data } from '../reducers/reports.js';\nimport { LiftedState } from '@redux-devtools/core';\n\nlet monitorReducer: (\n  monitorProps: unknown,\n  state: unknown | undefined,\n  action: Action<string>,\n) => unknown;\nlet monitorProps: unknown = {};\n\nexport interface ChangeSectionAction {\n  readonly type: typeof CHANGE_SECTION;\n  readonly section: string;\n}\nexport function changeSection(section: string): ChangeSectionAction {\n  return { type: CHANGE_SECTION, section };\n}\n\ninterface ChangeThemeFormData {\n  readonly theme: ThemeName;\n  readonly scheme: SchemeName;\n  readonly colorPreference: 'auto' | 'light' | 'dark';\n}\ninterface ChangeThemeData {\n  readonly formData?: ChangeThemeFormData;\n}\nexport interface ChangeThemeAction {\n  readonly type: typeof CHANGE_THEME;\n  readonly theme: ThemeName;\n  readonly scheme: SchemeName;\n  readonly colorPreference: 'auto' | 'light' | 'dark';\n}\nexport function changeTheme(data: ChangeThemeData): ChangeThemeAction {\n  return { type: CHANGE_THEME, ...data.formData! };\n}\n\ninterface ChangeStateTreeSettingsFormData {\n  readonly sortAlphabetically: boolean;\n  readonly disableCollection: boolean;\n}\n\ninterface ChangeStateTreeSettingsData {\n  readonly formData?: ChangeStateTreeSettingsFormData;\n}\n\nexport interface ChangeStateTreeSettingsAction {\n  readonly type: typeof CHANGE_STATE_TREE_SETTINGS;\n  readonly sortAlphabetically: boolean;\n  readonly disableCollection: boolean;\n}\n\nexport function changeStateTreeSettings(\n  data: ChangeStateTreeSettingsData,\n): ChangeStateTreeSettingsAction {\n  return { type: CHANGE_STATE_TREE_SETTINGS, ...data.formData! };\n}\n\nexport interface InitMonitorAction {\n  type: '@@INIT_MONITOR';\n  newMonitorState: unknown;\n  update: (\n    monitorProps: unknown,\n    state: unknown | undefined,\n    action: Action<string>,\n  ) => unknown;\n  monitorProps: unknown;\n}\nexport interface MonitorActionAction {\n  type: typeof MONITOR_ACTION;\n  action: InitMonitorAction;\n  monitorReducer: (\n    monitorProps: unknown,\n    state: unknown | undefined,\n    action: Action<string>,\n  ) => unknown;\n  monitorProps: unknown;\n}\nexport interface JumpToStateAction {\n  type: 'JUMP_TO_STATE';\n  index: number;\n}\nexport interface JumpToActionAction {\n  type: 'JUMP_TO_ACTION';\n  actionId: number;\n}\nexport interface PauseRecordingAction {\n  type: 'PAUSE_RECORDING';\n  status: boolean;\n}\nexport interface LockChangesAction {\n  type: 'LOCK_CHANGES';\n  status: boolean;\n}\nexport interface ToggleActionAction {\n  type: 'TOGGLE_ACTION';\n  id: number;\n}\nexport interface RollbackAction {\n  type: 'ROLLBACK';\n  timestamp: number;\n}\nexport interface SweepAction {\n  type: 'SWEEP';\n}\ninterface ReorderActionAction {\n  type: 'REORDER_ACTION';\n  actionId: number;\n  beforeActionId: number;\n}\ninterface ImportStateAction {\n  type: 'IMPORT_STATE';\n  nextLiftedState:\n    | LiftedState<unknown, Action<string>, unknown>\n    | readonly Action<string>[];\n  preloadedState?: unknown;\n  noRecompute?: boolean | undefined;\n}\nexport type DispatchAction =\n  | JumpToStateAction\n  | JumpToActionAction\n  | PauseRecordingAction\n  | LockChangesAction\n  | ToggleActionAction\n  | RollbackAction\n  | SweepAction\n  | ReorderActionAction\n  | ImportStateAction;\ninterface LiftedActionActionBase {\n  action?: DispatchAction | string | CustomAction;\n  state?: string;\n  toAll?: boolean;\n}\nexport interface LiftedActionDispatchAction extends LiftedActionActionBase {\n  type: typeof LIFTED_ACTION;\n  message: 'DISPATCH';\n  action: DispatchAction;\n  toAll?: boolean;\n}\nexport interface LiftedActionImportAction extends LiftedActionActionBase {\n  type: typeof LIFTED_ACTION;\n  message: 'IMPORT';\n  state: string;\n  preloadedState: unknown | undefined;\n}\nexport interface LiftedActionActionAction extends LiftedActionActionBase {\n  type: typeof LIFTED_ACTION;\n  message: 'ACTION';\n  action: string | CustomAction;\n}\nexport interface LiftedActionExportAction extends LiftedActionActionBase {\n  type: typeof LIFTED_ACTION;\n  message: 'EXPORT';\n  toExport: boolean;\n}\nexport type LiftedActionAction =\n  | LiftedActionDispatchAction\n  | LiftedActionImportAction\n  | LiftedActionActionAction\n  | LiftedActionExportAction;\nexport function liftedDispatch(\n  action:\n    | InitMonitorAction\n    | JumpToStateAction\n    | JumpToActionAction\n    | LiftedAction<unknown, Action<string>, unknown>,\n): MonitorActionAction | LiftedActionDispatchAction {\n  if (action.type[0] === '@') {\n    if (action.type === '@@INIT_MONITOR') {\n      monitorReducer = action.update;\n      monitorProps = action.monitorProps;\n    }\n    return {\n      type: MONITOR_ACTION,\n      action,\n      monitorReducer,\n      monitorProps,\n    } as MonitorActionAction;\n  }\n  return {\n    type: LIFTED_ACTION,\n    message: 'DISPATCH',\n    action,\n  } as LiftedActionDispatchAction;\n}\n\nexport interface SelectInstanceAction {\n  type: typeof SELECT_INSTANCE;\n  selected: string | number;\n}\nexport function selectInstance(selected: string): SelectInstanceAction {\n  return { type: SELECT_INSTANCE, selected };\n}\n\nexport interface SelectMonitorAction {\n  type: typeof SELECT_MONITOR;\n  monitor: string;\n  monitorState?: MonitorStateMonitorState;\n}\nexport function selectMonitor(monitor: string): SelectMonitorAction {\n  return { type: SELECT_MONITOR, monitor };\n}\nexport function selectMonitorWithState(\n  value: string,\n  monitorState: MonitorStateMonitorState,\n): SelectMonitorAction {\n  return { type: SELECT_MONITOR, monitor: value, monitorState };\n}\n\ninterface NextState {\n  subTabName: string;\n  inspectedStatePath?: string[];\n}\nexport interface UpdateMonitorStateAction {\n  type: typeof UPDATE_MONITOR_STATE;\n  nextState: NextState;\n}\nexport function selectMonitorTab(subTabName: string): UpdateMonitorStateAction {\n  return { type: UPDATE_MONITOR_STATE, nextState: { subTabName } };\n}\n\nexport function updateMonitorState(\n  nextState: NextState,\n): UpdateMonitorStateAction {\n  return { type: UPDATE_MONITOR_STATE, nextState };\n}\n\nexport function importState(\n  state: string,\n  preloadedState?: unknown,\n): LiftedActionImportAction {\n  return { type: LIFTED_ACTION, message: 'IMPORT', state, preloadedState };\n}\n\nexport interface ExportAction {\n  type: typeof EXPORT;\n}\nexport function exportState(): ExportAction {\n  return { type: EXPORT };\n}\n\nexport function lockChanges(status: boolean): LiftedActionDispatchAction {\n  return {\n    type: LIFTED_ACTION,\n    message: 'DISPATCH',\n    action: { type: 'LOCK_CHANGES', status },\n    toAll: true,\n  };\n}\n\nexport function pauseRecording(status: boolean): LiftedActionDispatchAction {\n  return {\n    type: LIFTED_ACTION,\n    message: 'DISPATCH',\n    action: { type: 'PAUSE_RECORDING', status },\n    toAll: true,\n  };\n}\n\nexport interface CustomAction {\n  name: string;\n  selected: number;\n  args: string[];\n  rest: string;\n}\nexport function dispatchRemotely(\n  action: string | CustomAction,\n): LiftedActionActionAction {\n  return { type: LIFTED_ACTION, message: 'ACTION', action };\n}\n\nexport interface TogglePersistAction {\n  type: typeof TOGGLE_PERSIST;\n}\nexport function togglePersist(): TogglePersistAction {\n  return { type: TOGGLE_PERSIST };\n}\n\nexport interface SetPersistAction {\n  type: typeof SET_PERSIST;\n  payload: boolean;\n}\nexport function setPersist(persist: boolean): SetPersistAction {\n  return { type: SET_PERSIST, payload: persist };\n}\n\nexport interface ToggleSyncAction {\n  type: typeof TOGGLE_SYNC;\n}\nexport function toggleSync(): ToggleSyncAction {\n  return { type: TOGGLE_SYNC };\n}\n\nexport interface ToggleSliderAction {\n  type: typeof TOGGLE_SLIDER;\n}\nexport function toggleSlider(): ToggleSliderAction {\n  return { type: TOGGLE_SLIDER };\n}\n\nexport interface ToggleDispatcherAction {\n  type: typeof TOGGLE_DISPATCHER;\n}\nexport function toggleDispatcher(): ToggleDispatcherAction {\n  return { type: TOGGLE_DISPATCHER };\n}\n\ninterface Notification {\n  readonly type: 'error';\n  readonly message: string;\n}\nexport interface ShowNotificationAction {\n  readonly type: typeof SHOW_NOTIFICATION;\n  readonly notification: Notification;\n}\nexport function showNotification(message: string): ShowNotificationAction {\n  return { type: SHOW_NOTIFICATION, notification: { type: 'error', message } };\n}\n\nexport interface ClearNotificationAction {\n  readonly type: typeof CLEAR_NOTIFICATION;\n}\nexport function clearNotification(): ClearNotificationAction {\n  return { type: CLEAR_NOTIFICATION };\n}\n\nexport interface GetReportRequest {\n  readonly type: typeof GET_REPORT_REQUEST;\n  readonly report: unknown;\n}\nexport function getReport(report: unknown): GetReportRequest {\n  return { type: GET_REPORT_REQUEST, report };\n}\n\nexport interface ActionCreator {\n  args: string[];\n  name: string;\n}\n\nexport interface LibConfig {\n  actionCreators?: string;\n  name?: string;\n  type?: string;\n  features?: Features;\n  serialize?: boolean;\n}\n\nexport interface RequestBase {\n  id?: string;\n  instanceId?: string | number;\n  action?: string;\n  name?: string | undefined;\n  libConfig?: LibConfig;\n  actionsById?: string;\n  computedStates?: string;\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  payload?: {} | string;\n  liftedState?: Partial<State>;\n}\ninterface InitRequest extends RequestBase {\n  type: 'INIT';\n  action?: string;\n  payload?: string;\n}\ninterface ActionRequest extends RequestBase {\n  type: 'ACTION';\n  isExcess?: boolean;\n  nextActionId: number;\n  maxAge: number;\n  batched?: boolean;\n}\ninterface StateRequest extends RequestBase {\n  type: 'STATE';\n  committedState: unknown;\n}\ninterface PartialStateRequest extends RequestBase {\n  type: 'PARTIAL_STATE';\n  committedState: unknown;\n  maxAge: number;\n}\ninterface LiftedRequest extends RequestBase {\n  type: 'LIFTED';\n}\nexport interface ExportRequest extends RequestBase {\n  type: 'EXPORT';\n  committedState: unknown;\n}\nexport type Request =\n  | InitRequest\n  | ActionRequest\n  | StateRequest\n  | PartialStateRequest\n  | LiftedRequest\n  | ExportRequest;\n\nexport interface UpdateStateAction {\n  type: typeof UPDATE_STATE;\n  request?: Request;\n  id?: string | number;\n}\n\nexport interface SetStateAction {\n  type: typeof SET_STATE;\n  newState: State;\n}\n\nexport interface RemoveInstanceAction {\n  type: typeof REMOVE_INSTANCE;\n  id: string | number;\n}\n\nexport interface ClearInstancesAction {\n  type: typeof CLEAR_INSTANCES;\n}\n\ninterface ListRequest {\n  type: 'list';\n  data: Data[];\n}\ninterface AddRequest {\n  type: 'add';\n  data: Data;\n}\ninterface RemoveRequest {\n  type: 'remove';\n  data: Data;\n  id: unknown;\n}\nexport type UpdateReportsRequest = ListRequest | AddRequest | RemoveRequest;\nexport interface UpdateReportsAction {\n  type: typeof UPDATE_REPORTS;\n  request: UpdateReportsRequest;\n}\n\nexport interface GetReportError {\n  type: typeof GET_REPORT_ERROR;\n  error: Error;\n}\n\nexport interface GetReportSuccess {\n  type: typeof GET_REPORT_SUCCESS;\n  data: { payload: string };\n}\n\nexport interface ErrorAction {\n  type: typeof ERROR;\n  payload: string;\n}\n\nexport interface ReduxPersistRehydrateAction {\n  type: typeof REHYDRATE;\n  payload: unknown;\n}\n\nexport type CoreStoreActionWithoutUpdateStateOrLiftedAction =\n  | ChangeSectionAction\n  | ChangeThemeAction\n  | ChangeStateTreeSettingsAction\n  | MonitorActionAction\n  | SelectInstanceAction\n  | SelectMonitorAction\n  | UpdateMonitorStateAction\n  | ExportAction\n  | TogglePersistAction\n  | SetPersistAction\n  | ToggleSyncAction\n  | ToggleSliderAction\n  | ToggleDispatcherAction\n  | ShowNotificationAction\n  | ClearNotificationAction\n  | GetReportRequest\n  | SetStateAction\n  | RemoveInstanceAction\n  | ClearInstancesAction\n  | UpdateReportsAction\n  | GetReportError\n  | GetReportSuccess\n  | ErrorAction\n  | ReduxPersistRehydrateAction;\n\nexport type CoreStoreActionWithoutUpdateState =\n  | CoreStoreActionWithoutUpdateStateOrLiftedAction\n  | LiftedActionAction;\n\nexport type CoreStoreActionWithoutLiftedAction =\n  | CoreStoreActionWithoutUpdateStateOrLiftedAction\n  | UpdateStateAction;\n\nexport type CoreStoreAction =\n  | CoreStoreActionWithoutUpdateState\n  | UpdateStateAction;\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/components/BottomButtons.tsx",
    "content": "import React, { Component } from 'react';\nimport { Toolbar, Divider } from '@redux-devtools/ui';\nimport ExportButton from './buttons/ExportButton.js';\nimport ImportButton from './buttons/ImportButton.js';\nimport PrintButton from './buttons/PrintButton.js';\nimport DispatcherButton from './buttons/DispatcherButton.js';\nimport SliderButton from './buttons/SliderButton.js';\nimport MonitorSelector from './MonitorSelector.js';\nimport { Options } from '../reducers/instances.js';\n\ninterface Props {\n  dispatcherIsOpen: boolean;\n  sliderIsOpen: boolean;\n  options: Options;\n}\n\nexport default class BottomButtons extends Component<Props> {\n  shouldComponentUpdate(nextProps: Props) {\n    return (\n      nextProps.dispatcherIsOpen !== this.props.dispatcherIsOpen ||\n      nextProps.sliderIsOpen !== this.props.sliderIsOpen ||\n      nextProps.options !== this.props.options\n    );\n  }\n\n  render() {\n    const features = this.props.options.features;\n    return (\n      <Toolbar borderPosition=\"top\">\n        {features.export && <ExportButton />}\n        {features.import && <ImportButton />}\n        <PrintButton />\n        <Divider />\n        <MonitorSelector />\n        <Divider />\n        {features.jump && <SliderButton isOpen={this.props.sliderIsOpen} />}\n        {features.dispatch && (\n          <DispatcherButton dispatcherIsOpen={this.props.dispatcherIsOpen} />\n        )}\n      </Toolbar>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/components/Header.tsx",
    "content": "import React, { Component } from 'react';\nimport { Tabs, Toolbar, Button, Divider } from '@redux-devtools/ui';\nimport { connect, ResolveThunks } from 'react-redux';\nimport { GoBook } from 'react-icons/go';\nimport { IoMdText } from 'react-icons/io';\nimport { TiSocialTwitter } from 'react-icons/ti';\nimport { TiHeartFullOutline } from 'react-icons/ti';\nimport { changeSection } from '../actions/index.js';\n\nconst tabs = [{ name: 'Actions' }, { name: 'Settings' }];\n\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ninterface OwnProps {\n  readonly section: string;\n}\ntype Props = DispatchProps & OwnProps;\n\nclass Header extends Component<Props> {\n  openLink = (url: string) => () => {\n    window.open(url);\n  };\n\n  render() {\n    return (\n      <Toolbar compact noBorder borderPosition=\"bottom\">\n        <Tabs\n          main\n          collapsible\n          tabs={tabs}\n          onClick={this.props.changeSection}\n          selected={this.props.section || 'Actions'}\n        />\n        <Divider />\n        <Button\n          title=\"Documentation\"\n          tooltipPosition=\"bottom\"\n          onClick={this.openLink(\n            'https://github.com/reduxjs/redux-devtools/blob/main/README.md',\n          )}\n        >\n          <GoBook />\n        </Button>\n        <Button\n          title=\"Feedback\"\n          tooltipPosition=\"bottom\"\n          onClick={this.openLink(\n            'https://github.com/reduxjs/redux-devtools/discussions',\n          )}\n        >\n          <IoMdText />\n        </Button>\n        <Button\n          title=\"Follow us\"\n          tooltipPosition=\"bottom\"\n          onClick={this.openLink('https://twitter.com/NathanBierema')}\n        >\n          <TiSocialTwitter />\n        </Button>\n        <Button\n          title=\"Support us\"\n          tooltipPosition=\"bottom-left\"\n          onClick={this.openLink(\n            'https://opencollective.com/redux-devtools-extension',\n          )}\n        >\n          <TiHeartFullOutline />\n        </Button>\n      </Toolbar>\n    );\n  }\n}\n\nconst actionCreators = {\n  changeSection,\n};\n\nexport default connect(null, actionCreators)(Header);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/components/InstanceSelector.tsx",
    "content": "import React, { Component } from 'react';\nimport { connect, ResolveThunks } from 'react-redux';\nimport { Select } from '@redux-devtools/ui';\nimport { selectInstance } from '../actions/index.js';\nimport { CoreStoreState } from '../reducers/index.js';\n\ntype StateProps = ReturnType<typeof mapStateToProps>;\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ntype Props = StateProps & DispatchProps;\n\nclass InstanceSelector extends Component<Props> {\n  select?: { readonly value: string; readonly label: string | number }[];\n\n  render() {\n    this.select = [{ value: '', label: 'Autoselect instances' }];\n    const instances = this.props.instances;\n    let name;\n    Object.keys(instances).forEach((key) => {\n      name = instances[key].name;\n      if (name !== undefined) this.select!.push({ value: key, label: name });\n    });\n\n    return (\n      <Select\n        options={this.select}\n        onChange={(option) => this.props.onSelect(option!.value)}\n        value={this.select.find(\n          (option) => option.value === this.props.selected,\n        )}\n      />\n    );\n  }\n}\n\nconst mapStateToProps = (state: CoreStoreState) => ({\n  selected: state.instances.selected,\n  instances: state.instances.options,\n});\n\nconst actionCreators = {\n  onSelect: selectInstance,\n};\n\nexport default connect(mapStateToProps, actionCreators)(InstanceSelector);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/components/MonitorSelector.tsx",
    "content": "import React, { Component } from 'react';\nimport { connect, ResolveThunks } from 'react-redux';\nimport { Tabs } from '@redux-devtools/ui';\nimport { monitors } from '../utils/getMonitor.js';\nimport { selectMonitor } from '../actions/index.js';\nimport { CoreStoreState } from '../reducers/index.js';\n\ntype StateProps = ReturnType<typeof mapStateToProps>;\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ntype Props = StateProps & DispatchProps;\n\nclass MonitorSelector extends Component<Props> {\n  shouldComponentUpdate(nextProps: Props) {\n    return nextProps.selected !== this.props.selected;\n  }\n\n  render() {\n    return (\n      <Tabs\n        main\n        collapsible\n        position=\"center\"\n        tabs={monitors}\n        onClick={this.props.selectMonitor}\n        selected={this.props.selected || 'InspectorMonitor'}\n      />\n    );\n  }\n}\n\nconst mapStateToProps = (state: CoreStoreState) => ({\n  selected: state.monitor.selected,\n});\n\nconst actionCreators = {\n  selectMonitor,\n};\n\nexport default connect(mapStateToProps, actionCreators)(MonitorSelector);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/components/Settings/StateTree.tsx",
    "content": "import React, { Component } from 'react';\nimport { connect, ResolveThunks } from 'react-redux';\nimport { Container, Form } from '@redux-devtools/ui';\nimport { changeStateTreeSettings } from '../../actions/index.js';\nimport { CoreStoreState } from '../../reducers/index.js';\n\ntype StateProps = ReturnType<typeof mapStateToProps>;\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ntype Props = StateProps & DispatchProps;\n\nexport class StateTree extends Component<Props> {\n  render() {\n    const stateTree = this.props.theme;\n    const formData = {\n      sortAlphabetically: stateTree.sortAlphabetically,\n      disableCollection: stateTree.disableCollection,\n    };\n\n    return (\n      <Container>\n        <Form\n          schema={{\n            type: 'object',\n            properties: {\n              sortAlphabetically: {\n                title: 'Sort Alphabetically',\n                type: 'boolean',\n              },\n              disableCollection: {\n                title: 'Disable collapsing of nodes',\n                type: 'boolean',\n              },\n            },\n          }}\n          formData={formData}\n          noSubmit\n          onChange={this.props.changeStateTreeSettings}\n        />\n      </Container>\n    );\n  }\n}\n\nconst mapStateToProps = (state: CoreStoreState) => ({\n  theme: state.stateTreeSettings,\n});\n\nconst actionCreators = {\n  changeStateTreeSettings,\n};\n\nexport default connect(mapStateToProps, actionCreators)(StateTree);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/components/Settings/Themes.tsx",
    "content": "import React, { Component } from 'react';\nimport { connect, ResolveThunks } from 'react-redux';\nimport { Container, Form } from '@redux-devtools/ui';\nimport { listSchemes, listThemes } from '@redux-devtools/ui';\nimport { changeTheme } from '../../actions/index.js';\nimport { CoreStoreState } from '../../reducers/index.js';\n\ntype StateProps = ReturnType<typeof mapStateToProps>;\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ntype Props = StateProps & DispatchProps;\n\nexport class Themes extends Component<Props> {\n  render() {\n    const theme = this.props.theme;\n    const formData = {\n      theme: theme.theme,\n      scheme: theme.scheme,\n      colorPreference: theme.colorPreference,\n    };\n\n    return (\n      <Container>\n        <Form\n          schema={{\n            type: 'object',\n            properties: {\n              theme: {\n                type: 'string',\n                enum: listThemes(),\n              },\n              scheme: {\n                title: 'color scheme',\n                type: 'string',\n                enum: listSchemes(),\n              },\n              colorPreference: {\n                title: 'theme color',\n                type: 'string',\n                enum: ['auto', 'light', 'dark'],\n              },\n            },\n          }}\n          formData={formData}\n          noSubmit\n          onChange={this.props.changeTheme}\n        />\n      </Container>\n    );\n  }\n}\n\nconst mapStateToProps = (state: CoreStoreState) => ({\n  theme: state.theme,\n});\n\nconst actionCreators = {\n  changeTheme,\n};\n\nexport default connect(mapStateToProps, actionCreators)(Themes);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/components/Settings/index.tsx",
    "content": "import React, { Component } from 'react';\nimport { Tabs } from '@redux-devtools/ui';\nimport Themes from './Themes.js';\nimport StateTree from './StateTree.js';\n\ninterface Props {\n  extraTabs?: { name: string; component: React.ComponentType }[];\n}\n\ninterface State {\n  selected: string | undefined;\n}\n\nexport default class Settings extends Component<Props, State> {\n  state: State = { selected: undefined };\n\n  handleSelect = (selected: string) => {\n    this.setState({ selected });\n  };\n\n  render() {\n    const { extraTabs = [] } = this.props;\n    const tabs = [\n      ...extraTabs,\n      { name: 'Themes', component: Themes },\n      { name: 'State Tree', component: StateTree },\n    ];\n    return (\n      // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n      <Tabs<{}>\n        tabs={tabs as any}\n        selected={this.state.selected || tabs[0].name}\n        onClick={this.handleSelect}\n      />\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/components/TopButtons.tsx",
    "content": "import React, { Component } from 'react';\nimport { ActionCreators, LiftedAction } from '@redux-devtools/core';\nimport { Button, Toolbar, Divider } from '@redux-devtools/ui';\nimport { Action } from 'redux';\nimport RecordButton from './buttons/RecordButton.js';\nimport PersistButton from './buttons/PersistButton.js';\nimport LockButton from './buttons/LockButton.js';\nimport InstanceSelector from './InstanceSelector.js';\nimport SyncButton from './buttons/SyncButton.js';\nimport { Options, State } from '../reducers/instances.js';\n\nconst { reset, rollback, commit, sweep } = ActionCreators;\n\ninterface Props {\n  dispatch: (action: LiftedAction<unknown, Action<string>, unknown>) => void;\n  liftedState: State;\n  options: Options;\n}\n\nexport default class TopButtons extends Component<Props> {\n  shouldComponentUpdate(nextProps: Props) {\n    return (\n      nextProps.options !== this.props.options ||\n      nextProps.liftedState !== this.props.liftedState\n    );\n  }\n\n  handleRollback = () => {\n    this.props.dispatch(rollback());\n  };\n\n  handleSweep = () => {\n    this.props.dispatch(sweep());\n  };\n\n  handleCommit = () => {\n    this.props.dispatch(commit());\n  };\n\n  handleReset = () => {\n    this.props.dispatch(reset());\n  };\n\n  render() {\n    const options = this.props.options;\n    const features = options.features;\n    const { computedStates, skippedActionIds, isPaused, isLocked } =\n      this.props.liftedState;\n    const noStates = computedStates.length < 2;\n\n    return (\n      <Toolbar borderPosition=\"bottom\">\n        {features.pause && <RecordButton paused={isPaused} />}\n        {features.persist && <PersistButton />}\n        {features.lock && (\n          <LockButton locked={isLocked} disabled={options.lib !== 'redux'} />\n        )}\n        <Divider />\n        <Button\n          title=\"Reset to the state you created the store with\"\n          tooltipPosition=\"bottom\"\n          onClick={this.handleReset}\n        >\n          Reset\n        </Button>\n        <Button\n          title=\"Roll back to the last committed state\"\n          tooltipPosition=\"bottom\"\n          onClick={this.handleRollback}\n          disabled={noStates}\n        >\n          Revert\n        </Button>\n        <Button\n          title=\"Remove all currently disabled actions from the log\"\n          tooltipPosition=\"bottom\"\n          onClick={this.handleSweep}\n          disabled={skippedActionIds.length === 0}\n        >\n          Sweep\n        </Button>\n        <Button\n          title=\"Remove all actions from the log,\\a and make the current state your initial state\"\n          tooltipPosition=\"bottom\"\n          onClick={this.handleCommit}\n          disabled={noStates}\n        >\n          Commit\n        </Button>\n        <Divider />\n        <InstanceSelector />\n        {features.sync && <SyncButton />}\n      </Toolbar>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/components/buttons/DispatcherButton.tsx",
    "content": "import React, { Component } from 'react';\nimport { connect, ResolveThunks } from 'react-redux';\nimport { Button } from '@redux-devtools/ui';\nimport { FaTerminal } from 'react-icons/fa';\nimport { toggleDispatcher } from '../../actions/index.js';\n\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ninterface OwnProps {\n  dispatcherIsOpen: boolean;\n}\ntype Props = DispatchProps & OwnProps;\n\nclass DispatcherButton extends Component<Props> {\n  shouldComponentUpdate(nextProps: Props) {\n    return nextProps.dispatcherIsOpen !== this.props.dispatcherIsOpen;\n  }\n\n  render() {\n    return (\n      <Button\n        mark={this.props.dispatcherIsOpen && 'base0D'}\n        title={\n          this.props.dispatcherIsOpen ? 'Hide dispatcher' : 'Show dispatcher'\n        }\n        onClick={this.props.toggleDispatcher}\n        tooltipPosition=\"top-left\"\n      >\n        <FaTerminal />\n      </Button>\n    );\n  }\n}\n\nconst actionCreators = {\n  toggleDispatcher,\n};\n\nexport default connect(null, actionCreators)(DispatcherButton);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/components/buttons/ExportButton.tsx",
    "content": "import React, { Component } from 'react';\nimport { connect, ResolveThunks } from 'react-redux';\nimport { Button } from '@redux-devtools/ui';\nimport { TiDownload } from 'react-icons/ti';\nimport { exportState } from '../../actions/index.js';\n\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ntype Props = DispatchProps;\n\nclass ExportButton extends Component<Props> {\n  shouldComponentUpdate() {\n    return false;\n  }\n\n  render() {\n    return (\n      <Button title=\"Export to a file\" onClick={this.props.exportState}>\n        <TiDownload />\n      </Button>\n    );\n  }\n}\n\nconst actionCreators = {\n  exportState,\n};\n\nexport default connect(null, actionCreators)(ExportButton);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/components/buttons/ImportButton.tsx",
    "content": "import React, { ChangeEventHandler, Component, RefCallback } from 'react';\nimport { connect, ResolveThunks } from 'react-redux';\nimport { Button } from '@redux-devtools/ui';\nimport { TiUpload } from 'react-icons/ti';\nimport { importState } from '../../actions/index.js';\n\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ntype Props = DispatchProps;\n\nclass ImportButton extends Component<Props> {\n  fileInput?: HTMLInputElement | null;\n\n  shouldComponentUpdate() {\n    return false;\n  }\n\n  mapRef: RefCallback<HTMLInputElement> = (node) => {\n    this.fileInput = node;\n  };\n\n  handleImport = () => {\n    this.fileInput!.click();\n  };\n\n  handleImportFile: ChangeEventHandler<HTMLInputElement> = (e) => {\n    const file = e.target.files![0];\n    const reader = new FileReader();\n    reader.onload = () => {\n      this.props.importState(reader.result as string);\n    };\n    reader.readAsText(file);\n    e.target.value = '';\n  };\n\n  render() {\n    return (\n      <Button title=\"Import from a file\" onClick={this.handleImport}>\n        <TiUpload />\n        <input\n          type=\"file\"\n          ref={this.mapRef}\n          style={{ display: 'none' }}\n          onChange={this.handleImportFile}\n        />\n      </Button>\n    );\n  }\n}\n\nconst actionCreators = {\n  importState,\n};\n\nexport default connect(null, actionCreators)(ImportButton);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/components/buttons/LockButton.tsx",
    "content": "import React, { Component } from 'react';\nimport { connect } from 'react-redux';\nimport { Button } from '@redux-devtools/ui';\nimport { IoIosLock } from 'react-icons/io';\nimport { lockChanges, CoreStoreAction } from '../../actions/index.js';\nimport { Dispatch } from 'redux';\n\ntype DispatchProps = ReturnType<typeof mapDispatchToProps>;\ninterface OwnProps {\n  locked: boolean | undefined;\n  disabled: boolean;\n}\ntype Props = DispatchProps & OwnProps;\n\nclass LockButton extends Component<Props> {\n  shouldComponentUpdate(nextProps: Props) {\n    return nextProps.locked !== this.props.locked;\n  }\n\n  render() {\n    return (\n      <Button\n        tooltipPosition=\"bottom\"\n        disabled={this.props.disabled}\n        mark={this.props.locked && 'base0D'}\n        title={this.props.locked ? 'Unlock changes' : 'Lock changes'}\n        onClick={this.props.lockChanges}\n      >\n        <IoIosLock />\n      </Button>\n    );\n  }\n}\n\nfunction mapDispatchToProps(\n  dispatch: Dispatch<CoreStoreAction>,\n  ownProps: OwnProps,\n) {\n  return {\n    lockChanges: () => dispatch(lockChanges(!ownProps.locked)),\n  };\n}\n\nexport default connect(null, mapDispatchToProps)(LockButton);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/components/buttons/PersistButton.tsx",
    "content": "import React, { Component } from 'react';\nimport { connect, ResolveThunks } from 'react-redux';\nimport { Button } from '@redux-devtools/ui';\nimport { FaThumbtack } from 'react-icons/fa';\nimport { togglePersist } from '../../actions/index.js';\nimport { CoreStoreState } from '../../reducers/index.js';\n\ntype StateProps = ReturnType<typeof mapStateToProps>;\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ninterface OwnProps {\n  disabled?: boolean;\n}\ntype Props = StateProps & DispatchProps & OwnProps;\n\nclass LockButton extends Component<Props> {\n  shouldComponentUpdate(nextProps: Props) {\n    return nextProps.persisted !== this.props.persisted;\n  }\n\n  render() {\n    return (\n      <Button\n        tooltipPosition=\"bottom\"\n        disabled={this.props.disabled}\n        mark={this.props.persisted && 'base0D'}\n        title={\n          this.props.persisted\n            ? 'Disable state persisting'\n            : 'Persist state history'\n        }\n        onClick={this.props.onClick}\n      >\n        <FaThumbtack />\n      </Button>\n    );\n  }\n}\n\nconst mapStateToProps = (state: CoreStoreState) => ({\n  persisted: state.instances.persisted,\n});\n\nconst actionCreators = {\n  onClick: togglePersist,\n};\n\nexport default connect(mapStateToProps, actionCreators)(LockButton);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/components/buttons/PrintButton.tsx",
    "content": "import React, { Component } from 'react';\nimport { Button } from '@redux-devtools/ui';\nimport { MdPrint } from 'react-icons/md';\n\nexport default class PrintButton extends Component {\n  shouldComponentUpdate() {\n    return false;\n  }\n\n  handlePrint = () => {\n    const d3svg = document.getElementById('d3svg') as unknown as SVGGElement;\n    if (!d3svg) {\n      window.print();\n      return;\n    }\n\n    const initHeight = d3svg.style.height;\n    const initWidth = d3svg.style.width;\n    const box = d3svg.getBBox();\n    d3svg.style.height = `${box.height}`;\n    d3svg.style.width = `${box.width}`;\n\n    const g = d3svg.firstChild! as SVGGElement;\n    const initTransform = g.getAttribute('transform')!;\n    g.setAttribute(\n      'transform',\n      initTransform.replace(/.+scale\\(/, 'translate(57, 10) scale('),\n    );\n\n    window.print();\n\n    d3svg.style.height = initHeight;\n    d3svg.style.width = initWidth;\n    g.setAttribute('transform', initTransform);\n  };\n\n  render() {\n    return (\n      <Button title=\"Print\" onClick={this.handlePrint}>\n        <MdPrint />\n      </Button>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/components/buttons/RecordButton.tsx",
    "content": "import React, { Component } from 'react';\nimport { connect } from 'react-redux';\nimport { Button } from '@redux-devtools/ui';\nimport { MdFiberManualRecord } from 'react-icons/md';\nimport { pauseRecording, CoreStoreAction } from '../../actions/index.js';\nimport { Dispatch } from 'redux';\n\ntype DispatchProps = ReturnType<typeof mapDispatchToProps>;\ninterface OwnProps {\n  paused: boolean | undefined;\n}\ntype Props = DispatchProps & OwnProps;\n\nclass RecordButton extends Component<Props> {\n  shouldComponentUpdate(nextProps: Props) {\n    return nextProps.paused !== this.props.paused;\n  }\n\n  render() {\n    return (\n      <Button\n        tooltipPosition=\"bottom-right\"\n        mark={!this.props.paused && 'base08'}\n        title={this.props.paused ? 'Start recording' : 'Pause recording'}\n        onClick={this.props.pauseRecording}\n      >\n        <MdFiberManualRecord />\n      </Button>\n    );\n  }\n}\n\nfunction mapDispatchToProps(\n  dispatch: Dispatch<CoreStoreAction>,\n  ownProps: OwnProps,\n) {\n  return {\n    pauseRecording: () => dispatch(pauseRecording(!ownProps.paused)),\n  };\n}\n\nexport default connect(null, mapDispatchToProps)(RecordButton);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/components/buttons/SliderButton.tsx",
    "content": "import React, { Component } from 'react';\nimport { connect, ResolveThunks } from 'react-redux';\nimport { Button } from '@redux-devtools/ui';\nimport { MdAvTimer } from 'react-icons/md';\nimport { toggleSlider } from '../../actions/index.js';\n\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ninterface OwnProps {\n  isOpen: boolean;\n}\ntype Props = DispatchProps & OwnProps;\n\nclass SliderButton extends Component<Props> {\n  shouldComponentUpdate(nextProps: Props) {\n    return nextProps.isOpen !== this.props.isOpen;\n  }\n\n  render() {\n    return (\n      <Button\n        mark={this.props.isOpen && 'base0D'}\n        title={this.props.isOpen ? 'Hide slider' : 'Show slider'}\n        tooltipPosition=\"top-left\"\n        onClick={this.props.toggleSlider}\n      >\n        <MdAvTimer />\n      </Button>\n    );\n  }\n}\n\nconst actionCreators = {\n  toggleSlider,\n};\n\nexport default connect(null, actionCreators)(SliderButton);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/components/buttons/SyncButton.tsx",
    "content": "import React, { Component } from 'react';\nimport { connect, ResolveThunks } from 'react-redux';\nimport { Button } from '@redux-devtools/ui';\nimport { TiArrowSync } from 'react-icons/ti';\nimport { toggleSync } from '../../actions/index.js';\nimport { CoreStoreState } from '../../reducers/index.js';\n\ntype StateProps = ReturnType<typeof mapStateToProps>;\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ntype Props = StateProps & DispatchProps;\n\nclass SyncButton extends Component<Props> {\n  shouldComponentUpdate(nextProps: Props) {\n    return nextProps.sync !== this.props.sync;\n  }\n\n  render() {\n    return (\n      <Button\n        title=\"Sync actions\"\n        tooltipPosition=\"bottom-left\"\n        onClick={this.props.onClick}\n        mark={this.props.sync && 'base0B'}\n      >\n        <TiArrowSync />\n      </Button>\n    );\n  }\n}\n\nconst mapStateToProps = (state: CoreStoreState) => ({\n  sync: state.instances.sync,\n});\n\nconst actionCreators = {\n  onClick: toggleSync,\n};\n\nexport default connect(mapStateToProps, actionCreators)(SyncButton);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/constants/actionTypes.ts",
    "content": "export const CHANGE_SECTION = 'main/CHANGE_SECTION';\nexport const CHANGE_THEME = 'main/CHANGE_THEME';\nexport const CHANGE_STATE_TREE_SETTINGS = 'main/CHANGE_STATE_TREE_SETTINGS';\n\nexport const UPDATE_STATE = 'devTools/UPDATE_STATE';\nexport const SET_STATE = 'devTools/SET_STATE';\nexport const SELECT_INSTANCE = 'devTools/SELECT_INSTANCE';\nexport const REMOVE_INSTANCE = 'devTools/REMOVE_INSTANCE';\nexport const CLEAR_INSTANCES = 'devTools/CLEAR_INSTANCES';\nexport const LIFTED_ACTION = 'devTools/LIFTED_ACTION';\nexport const MONITOR_ACTION = 'devTools/MONITOR_ACTION';\nexport const TOGGLE_SYNC = 'devTools/TOGGLE_SYNC';\nexport const TOGGLE_PERSIST = 'devTools/TOGGLE_PERSIST';\nexport const SET_PERSIST = 'devTools/SET_PERSIST';\nexport const SELECT_MONITOR = 'devTools/SELECT_MONITOR';\nexport const UPDATE_MONITOR_STATE = 'devTools/UPDATE_MONITOR_STATE';\nexport const TOGGLE_SLIDER = 'devTools/TOGGLE_SLIDER';\nexport const TOGGLE_DISPATCHER = 'devTools/TOGGLE_DISPATCHER';\nexport const EXPORT = 'devTools/EXPORT';\nexport const SHOW_NOTIFICATION = 'devTools/SHOW_NOTIFICATION';\nexport const CLEAR_NOTIFICATION = 'devTools/CLEAR_NOTIFICATION';\n\nexport const UPDATE_REPORTS = 'reports/UPDATE';\nexport const GET_REPORT_REQUEST = 'reports/GET_REPORT_REQUEST';\nexport const GET_REPORT_ERROR = 'reports/GET_REPORT_ERROR';\nexport const GET_REPORT_SUCCESS = 'reports/GET_REPORT_SUCCESS';\nexport const ERROR = 'ERROR';\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/constants/dataTypes.ts",
    "content": "export const DATA_TYPE_KEY = Symbol.for('__serializedType__');\nexport const DATA_REF_KEY = Symbol.for('__serializedRef__');\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/containers/Actions.tsx",
    "content": "import React, { Component } from 'react';\nimport { connect, ResolveThunks } from 'react-redux';\nimport { Container } from '@redux-devtools/ui';\nimport SliderMonitor from './monitors/Slider.js';\nimport { liftedDispatch, getReport } from '../actions/index.js';\nimport { getActiveInstance } from '../reducers/instances.js';\nimport DevTools from './DevTools.js';\nimport Dispatcher from './monitors/Dispatcher.js';\nimport TopButtons from '../components/TopButtons.js';\nimport BottomButtons from '../components/BottomButtons.js';\nimport { CoreStoreState } from '../reducers/index.js';\n\ntype StateProps = ReturnType<typeof mapStateToProps>;\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ntype Props = StateProps & DispatchProps;\n\nclass Actions extends Component<Props> {\n  render() {\n    const {\n      monitor,\n      dispatcherIsOpen,\n      sliderIsOpen,\n      options,\n      liftedState,\n      liftedDispatch,\n      stateTreeSettings,\n    } = this.props;\n    return (\n      <Container>\n        <TopButtons\n          dispatch={liftedDispatch}\n          liftedState={liftedState}\n          options={options}\n        />\n        <DevTools\n          monitor={monitor}\n          liftedState={liftedState}\n          monitorState={this.props.monitorState}\n          dispatch={liftedDispatch}\n          features={options.features}\n          stateTreeSettings={stateTreeSettings}\n        />\n        {sliderIsOpen && options.connectionId && options.features.jump && (\n          <SliderMonitor liftedState={liftedState} dispatch={liftedDispatch} />\n        )}\n        {dispatcherIsOpen &&\n          options.connectionId &&\n          options.features.dispatch && <Dispatcher options={options} />}\n        <BottomButtons\n          dispatcherIsOpen={dispatcherIsOpen}\n          sliderIsOpen={sliderIsOpen}\n          options={options}\n        />\n      </Container>\n    );\n  }\n}\n\nconst mapStateToProps = (state: CoreStoreState) => {\n  const instances = state.instances;\n  const id = getActiveInstance(instances);\n  return {\n    liftedState: instances.states[id],\n    monitorState: state.monitor.monitorState,\n    options: instances.options[id],\n    monitor: state.monitor.selected,\n    dispatcherIsOpen: state.monitor.dispatcherIsOpen,\n    sliderIsOpen: state.monitor.sliderIsOpen,\n    reports: state.reports.data,\n    stateTreeSettings: state.stateTreeSettings,\n  };\n};\n\nconst actionCreators = {\n  liftedDispatch,\n  getReport,\n};\n\nexport default connect(mapStateToProps, actionCreators)(Actions);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/containers/App.tsx",
    "content": "import React, { Component } from 'react';\nimport { connect, ResolveThunks } from 'react-redux';\nimport { Container, Notification } from '@redux-devtools/ui';\nimport { clearNotification } from '../actions/index.js';\nimport Header from '../components/Header.js';\nimport Actions from './Actions.js';\nimport Settings from '../components/Settings/index.js';\nimport { CoreStoreState } from '../reducers/index.js';\n\ntype StateProps = ReturnType<typeof mapStateToProps>;\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ntype OwnProps = {\n  extraSettingsTabs?: { name: string; component: React.ComponentType }[];\n};\ntype Props = StateProps & DispatchProps & OwnProps;\n\nclass App extends Component<Props> {\n  render() {\n    const { extraSettingsTabs, section, theme, notification } = this.props;\n    let body;\n    switch (section) {\n      case 'Settings':\n        body = <Settings extraTabs={extraSettingsTabs} />;\n        break;\n      default:\n        body = <Actions />;\n    }\n\n    return (\n      <Container themeData={theme}>\n        <Header section={section} />\n        {body}\n        {notification && (\n          <Notification\n            type={notification.type}\n            onClose={this.props.clearNotification}\n          >\n            {notification.message}\n          </Notification>\n        )}\n      </Container>\n    );\n  }\n}\n\nconst mapStateToProps = (state: CoreStoreState) => ({\n  section: state.section,\n  theme: state.theme,\n  notification: state.notification,\n});\n\nconst actionCreators = {\n  clearNotification,\n};\n\nexport default connect(mapStateToProps, actionCreators)(App);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/containers/DevTools.tsx",
    "content": "import React, { Component } from 'react';\nimport { withTheme } from '@emotion/react';\nimport { LiftedAction, LiftedState } from '@redux-devtools/core';\nimport { Action } from 'redux';\nimport getMonitor from '../utils/getMonitor.js';\nimport { InitMonitorAction } from '../actions/index.js';\nimport { Features, State } from '../reducers/instances.js';\nimport { MonitorStateMonitorState } from '../reducers/monitor.js';\nimport { ThemeFromProvider } from '@redux-devtools/ui';\nimport { StateTreeSettings } from '../reducers/stateTreeSettings.js';\n\ninterface Props {\n  monitor: string;\n  liftedState: State;\n  monitorState: MonitorStateMonitorState | undefined;\n  dispatch: (\n    action: LiftedAction<unknown, Action<string>, unknown> | InitMonitorAction,\n  ) => void;\n  features: Features | undefined;\n  theme: ThemeFromProvider;\n  stateTreeSettings: StateTreeSettings;\n}\n\nclass DevTools extends Component<Props> {\n  monitorProps?: object;\n  Monitor?: React.ComponentType<\n    LiftedState<unknown, Action<string>, unknown>\n  > & {\n    update(\n      this: void,\n      monitorProps: unknown,\n      state: unknown | undefined,\n      action: Action<string>,\n    ): unknown;\n  };\n  preventRender?: boolean;\n\n  constructor(props: Props) {\n    super(props);\n    this.getMonitor(props, props.monitorState);\n  }\n\n  getMonitor(props: Props, skipUpdate?: unknown) {\n    const monitorElement = getMonitor(props);\n    this.monitorProps = monitorElement.props;\n    this.Monitor = monitorElement.type;\n\n    const update = this.Monitor!.update;\n    if (update) {\n      let newMonitorState;\n      const monitorState = props.monitorState;\n      if (\n        skipUpdate ||\n        (monitorState && monitorState.__overwritten__ === props.monitor)\n      ) {\n        newMonitorState = monitorState;\n      } else {\n        newMonitorState = update(\n          this.monitorProps,\n          undefined,\n          {} as Action<string>,\n        );\n        if (newMonitorState !== monitorState) {\n          this.preventRender = true;\n        }\n      }\n      this.dispatch({\n        type: '@@INIT_MONITOR',\n        newMonitorState,\n        update,\n        monitorProps: this.monitorProps,\n      });\n    }\n  }\n\n  UNSAFE_componentWillUpdate(nextProps: Props) {\n    if (nextProps.monitor !== this.props.monitor) this.getMonitor(nextProps);\n  }\n\n  shouldComponentUpdate(nextProps: Props) {\n    return (\n      nextProps.monitor !== this.props.monitor ||\n      nextProps.liftedState !== this.props.liftedState ||\n      nextProps.monitorState !== this.props.monitorState ||\n      nextProps.features !== this.props.features ||\n      nextProps.theme.scheme !== this.props.theme.scheme\n    );\n  }\n\n  dispatch = (\n    action: LiftedAction<unknown, Action<string>, unknown> | InitMonitorAction,\n  ) => {\n    this.props.dispatch(action);\n  };\n\n  render() {\n    if (this.preventRender) {\n      this.preventRender = false;\n      return null;\n    }\n\n    const liftedState = {\n      ...this.props.liftedState,\n      monitorState: this.props.monitorState,\n    };\n    const MonitorAsAny = this.Monitor as any;\n    return (\n      <div className={`monitor monitor-${this.props.monitor}`}>\n        <MonitorAsAny\n          {...liftedState}\n          {...this.monitorProps}\n          features={this.props.features}\n          dispatch={this.dispatch}\n          theme={this.props.theme}\n          sortStateTreeAlphabetically={\n            this.props.stateTreeSettings.sortAlphabetically\n          }\n          disableStateTreeCollection={\n            this.props.stateTreeSettings.disableCollection\n          }\n        />\n      </div>\n    );\n  }\n}\n\nexport default withTheme(DevTools);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/containers/monitors/ChartMonitorWrapper.tsx",
    "content": "import React, { Component } from 'react';\nimport { connect, ResolveThunks } from 'react-redux';\nimport {\n  ChartMonitor,\n  ChartMonitorAction,\n  ChartMonitorProps,\n  ChartMonitorState,\n} from '@redux-devtools/chart-monitor';\nimport type { HierarchyPointNode, Node } from 'd3-state-visualizer';\nimport { selectMonitorWithState } from '../../actions/index.js';\nimport { Action } from 'redux';\n\nexport function getPath(\n  obj: HierarchyPointNode<Node>,\n  inspectedStatePath: string[],\n) {\n  const parent = obj.parent;\n  if (!parent) return;\n  getPath(parent, inspectedStatePath);\n  let name = obj.data.name;\n  const item = /.+\\[(\\d+)]/.exec(name);\n  if (item) name = item[1];\n  inspectedStatePath.push(name);\n}\n\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ntype Props = DispatchProps;\n\nclass ChartMonitorWrapper extends Component<Props> {\n  static update: <S, A extends Action<string>>(\n    props: ChartMonitorProps<S, A>,\n    state: ChartMonitorState | undefined,\n    action: ChartMonitorAction,\n  ) => ChartMonitorState = ChartMonitor.update;\n\n  onClickText = (data: HierarchyPointNode<Node>) => {\n    const inspectedStatePath: string[] = [];\n    getPath(data, inspectedStatePath);\n    this.props.selectMonitorWithState('InspectorMonitor', {\n      inspectedStatePath,\n      tabName: 'State',\n      subTabName: data.children ? 'Chart' : 'Tree',\n      selectedActionId: null,\n      startActionId: null,\n      inspectedActionPath: [],\n    });\n  };\n\n  render() {\n    return (\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      <ChartMonitor\n        defaultIsVisible\n        invertTheme\n        onClickText={this.onClickText}\n        {...this.props}\n      />\n    );\n  }\n}\n\nconst actionCreators = {\n  selectMonitorWithState: selectMonitorWithState,\n};\n\nexport default connect(null, actionCreators)(ChartMonitorWrapper);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/containers/monitors/Dispatcher.tsx",
    "content": "// Based on https://github.com/YoruNoHikage/redux-devtools-dispatch\n\nimport React, { Component } from 'react';\nimport styled from '@emotion/styled';\nimport {\n  Button,\n  Select,\n  Editor,\n  Toolbar,\n  Base16Theme,\n} from '@redux-devtools/ui';\nimport { connect, ResolveThunks } from 'react-redux';\nimport { dispatchRemotely } from '../../actions/index.js';\nimport { Options } from '../../reducers/instances.js';\n\nexport const DispatcherContainer = styled.div`\n  display: flex;\n  flex-direction: column;\n  flex-shrink: 0;\n  padding-top: 2px;\n  background: ${(props: { theme?: Base16Theme }) => props.theme!.base01};\n`;\n\nexport const CodeContainer = styled.div`\n  height: 75px;\n  padding-right: 6px;\n  overflow: auto;\n`;\n\nexport const ActionContainer = styled.div`\n  display: table;\n  width: 100%;\n  color: ${(props: { theme?: Base16Theme }) => props.theme!.base06};\n\n  > div {\n    display: table-row;\n\n    > div:first-child {\n      width: 1px;\n      padding-left: 8px;\n      display: table-cell;\n      text-overflow: ellipsis;\n      white-space: nowrap;\n      overflow: hidden;\n    }\n\n    > div:nth-child(2) {\n      display: table-cell;\n      width: 100%;\n      padding: 6px;\n    }\n  }\n`;\n\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ninterface OwnProps {\n  options: Options;\n}\ntype Props = DispatchProps & OwnProps;\n\ninterface State {\n  selected: 'default' | number;\n  customAction: string;\n  args: string[];\n  rest: string;\n  changed: boolean;\n}\n\nclass Dispatcher extends Component<Props, State> {\n  state: State = {\n    selected: 'default',\n    customAction:\n      this.props.options.lib === 'redux' ? \"{\\n  type: ''\\n}\" : 'this.',\n    args: [],\n    rest: '[]',\n    changed: false,\n  };\n\n  UNSAFE_componentWillReceiveProps(nextProps: Props) {\n    if (\n      this.state.selected !== 'default' &&\n      !nextProps.options.actionCreators\n    ) {\n      this.setState({\n        selected: 'default',\n        args: [],\n      });\n    }\n  }\n\n  shouldComponentUpdate(nextProps: Props, nextState: State) {\n    return (\n      nextState !== this.state ||\n      nextProps.options.actionCreators !== this.props.options.actionCreators\n    );\n  }\n\n  selectActionCreator = (selected: 'default' | 'actions-help' | number) => {\n    if (selected === 'actions-help') {\n      window.open(\n        'https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/' +\n          'API/Arguments.md#actioncreators',\n      );\n      return;\n    }\n\n    const args: string[] = [];\n    if (selected !== 'default') {\n      args.length = this.props.options.actionCreators![selected].args.length;\n    }\n    this.setState({ selected, args, rest: '[]', changed: false });\n  };\n\n  handleArg = (argIndex: number) => (value: string) => {\n    const args = [\n      ...this.state.args.slice(0, argIndex),\n      (value || undefined)!,\n      ...this.state.args.slice(argIndex + 1),\n    ];\n    this.setState({ args, changed: true });\n  };\n\n  handleRest = (rest: string) => {\n    this.setState({ rest, changed: true });\n  };\n\n  handleCustomAction = (customAction: string) => {\n    this.setState({ customAction, changed: true });\n  };\n\n  dispatchAction = () => {\n    const { selected, customAction, args, rest } = this.state;\n\n    if (selected !== 'default') {\n      // remove trailing `undefined` arguments\n      let i = args.length - 1;\n      while (i >= 0 && typeof args[i] === 'undefined') {\n        args.pop();\n        i--;\n      }\n      this.props.dispatch({\n        name: this.props.options.actionCreators![selected].name,\n        selected,\n        args,\n        rest,\n      });\n    } else {\n      this.props.dispatch(customAction);\n    }\n    this.setState({ changed: false });\n  };\n\n  render() {\n    const actionCreators = this.props.options.actionCreators;\n    let actionElement;\n\n    if (this.state.selected === 'default' || !actionCreators) {\n      actionElement = (\n        <CodeContainer>\n          <Editor\n            value={this.state.customAction}\n            onChange={this.handleCustomAction}\n          />\n        </CodeContainer>\n      );\n    } else {\n      actionElement = (\n        <ActionContainer>\n          {actionCreators[this.state.selected].args.map((param, i) => (\n            <div key={`${param}${i}`}>\n              <div>{param}</div>\n              <Editor\n                lineNumbers={false}\n                value={this.state.args[i]}\n                onChange={this.handleArg(i)}\n              />\n            </div>\n          ))}\n          <div>\n            <div>...rest</div>\n            <Editor\n              lineNumbers={false}\n              value={this.state.rest}\n              onChange={this.handleRest}\n            />\n          </div>\n        </ActionContainer>\n      );\n    }\n\n    let options: {\n      value: 'default' | 'actions-help' | number;\n      label: string;\n    }[] = [{ value: 'default', label: 'Custom action' }];\n    if (actionCreators && actionCreators.length > 0) {\n      options = options.concat(\n        actionCreators.map(({ name, args }, i) => ({\n          value: i,\n          label: `${name}(${args.join(', ')})`,\n        })),\n      );\n    } else {\n      options.push({\n        value: 'actions-help',\n        label: 'Add your app built-in actions…',\n      });\n    }\n\n    return (\n      <DispatcherContainer>\n        {actionElement}\n        <Toolbar>\n          <Select\n            menuPlacement=\"top\"\n            onChange={(option) => this.selectActionCreator(option!.value)}\n            value={\n              options.find((option) => option.value === this.state.selected) ||\n              options.find((option) => option.value === 'default')\n            }\n            options={options}\n          />\n          <Button onClick={this.dispatchAction} primary={this.state.changed}>\n            Dispatch\n          </Button>\n        </Toolbar>\n      </DispatcherContainer>\n    );\n  }\n}\n\nconst actionCreators = {\n  dispatch: dispatchRemotely,\n};\n\nexport default connect(null, actionCreators)(Dispatcher);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/containers/monitors/InspectorWrapper/ChartTab.tsx",
    "content": "import React, { Component, RefCallback } from 'react';\nimport { connect, ResolveThunks } from 'react-redux';\nimport { withTheme } from '@emotion/react';\nimport { tree } from 'd3-state-visualizer';\nimport type { HierarchyPointNode, Node, Options } from 'd3-state-visualizer';\nimport { getPath } from '../ChartMonitorWrapper.js';\nimport { updateMonitorState } from '../../../actions/index.js';\nimport { ThemeFromProvider } from '@redux-devtools/ui';\n\nconst style = {\n  width: '100%',\n  height: '100%',\n};\n\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ninterface OwnProps {\n  data: unknown;\n  theme: ThemeFromProvider;\n}\ntype Props = DispatchProps & OwnProps;\n\nclass ChartTab extends Component<Props> {\n  node?: HTMLDivElement | null;\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  renderChart?: (nextState?: {} | null | undefined) => void;\n\n  shouldComponentUpdate() {\n    return false;\n  }\n\n  componentDidMount() {\n    this.createChart(this.props);\n  }\n\n  UNSAFE_componentWillReceiveProps(nextProps: Props) {\n    if (\n      this.props.theme.scheme !== nextProps.theme.scheme ||\n      nextProps.theme.light !== this.props.theme.light\n    ) {\n      this.node!.innerHTML = '';\n      this.createChart(nextProps);\n    } else if (nextProps.data !== this.props.data) {\n      // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n      this.renderChart!(nextProps.data as {} | null | undefined);\n    }\n  }\n\n  getRef: RefCallback<HTMLDivElement> = (node) => {\n    this.node = node;\n  };\n\n  createChart(props: Props) {\n    this.renderChart = tree(this.node!, this.getChartTheme(props.theme));\n    // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n    this.renderChart(props.data as {} | null | undefined);\n  }\n\n  getChartTheme(theme: ThemeFromProvider): Partial<Options> {\n    return {\n      heightBetweenNodesCoeff: 1,\n      widthBetweenNodesCoeff: 1.3,\n      tooltipOptions: {\n        styles: {\n          color: theme.base06,\n          'background-color': theme.base01,\n          opacity: '0.9',\n          'border-radius': '5px',\n          padding: '5px',\n        },\n        offset: { left: 30, top: 10 },\n        indentationSize: 2,\n      },\n      chartStyles: {\n        width: '100%',\n        height: '100%',\n      },\n      nodeStyleOptions: {\n        colors: {\n          default: theme.base0B,\n          collapsed: theme.base0B,\n          parent: theme.base0E,\n        },\n        radius: 7,\n      },\n      textStyleOptions: {\n        colors: {\n          default: theme.base0D,\n          hover: theme.base06,\n        },\n      },\n      onClickText: this.onClickText,\n    };\n  }\n\n  onClickText = (data: HierarchyPointNode<Node>) => {\n    const inspectedStatePath: string[] = [];\n    getPath(data, inspectedStatePath);\n    this.props.updateMonitorState({\n      inspectedStatePath,\n      subTabName: data.children ? 'Chart' : 'Tree',\n    });\n  };\n\n  render() {\n    return <div style={style} ref={this.getRef} />;\n  }\n}\n\nconst actionCreators = {\n  updateMonitorState,\n};\n\nconst ConnectedChartTab = connect(null, actionCreators)(ChartTab);\nexport default withTheme(ConnectedChartTab);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/containers/monitors/InspectorWrapper/RawTab.tsx",
    "content": "import React, { Component } from 'react';\nimport { Editor } from '@redux-devtools/ui';\nimport { stringify } from 'javascript-stringify';\n\ninterface Props {\n  data: unknown;\n}\n\nexport default class RawTab extends Component<Props> {\n  value?: string | undefined;\n\n  constructor(props: Props) {\n    super(props);\n    this.stringifyData(props);\n  }\n\n  shouldComponentUpdate(nextProps: Props) {\n    return nextProps.data !== this.value;\n  }\n\n  UNSAFE_componentWillUpdate(nextProps: Props) {\n    this.stringifyData(nextProps);\n  }\n\n  stringifyData(props: Props) {\n    this.value = stringify(props.data, null, 2);\n  }\n\n  render() {\n    return <Editor value={this.value} />;\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/containers/monitors/InspectorWrapper/SubTabs.tsx",
    "content": "import React, { Component } from 'react';\nimport { connect, ResolveThunks } from 'react-redux';\nimport { Tab, Tabs } from '@redux-devtools/ui';\nimport {\n  TabComponentProps,\n  StateTab,\n  ActionTab,\n  DiffTab,\n} from '@redux-devtools/inspector-monitor';\nimport { Action } from 'redux';\nimport { selectMonitorTab } from '../../../actions/index.js';\nimport RawTab from './RawTab.js';\nimport ChartTab from './ChartTab.js';\nimport VisualDiffTab from './VisualDiffTab.js';\nimport { CoreStoreState } from '../../../reducers/index.js';\nimport type { Delta } from 'jsondiffpatch';\n\ntype StateProps = ReturnType<typeof mapStateToProps>;\ntype DispatchProps = ResolveThunks<typeof actionCreators>;\ntype Props = StateProps &\n  DispatchProps &\n  TabComponentProps<unknown, Action<string>>;\n\nclass SubTabs extends Component<Props> {\n  tabs?: (Tab<Props> | Tab<{ data: unknown }> | Tab<{ data?: Delta }>)[];\n\n  constructor(props: Props) {\n    super(props);\n    this.updateTabs(props);\n  }\n\n  UNSAFE_componentWillReceiveProps(nextProps: Props) {\n    if (nextProps.parentTab !== this.props.parentTab) {\n      this.updateTabs(nextProps);\n    }\n  }\n\n  selector = () => {\n    switch (this.props.parentTab) {\n      case 'Action':\n        return { data: this.props.action };\n      case 'Diff':\n        return { data: this.props.delta };\n      default:\n        return { data: this.props.nextState };\n    }\n  };\n\n  updateTabs(props: Props) {\n    const parentTab = props.parentTab;\n\n    if (parentTab === 'Diff') {\n      this.tabs = [\n        {\n          name: 'Tree',\n          component: DiffTab,\n          selector: () => this.props,\n        },\n        {\n          name: 'Raw',\n          component: VisualDiffTab,\n          selector: this.selector as () => { data?: Delta },\n        },\n      ];\n      return;\n    }\n\n    this.tabs = [\n      {\n        name: 'Tree',\n        component: parentTab === 'Action' ? ActionTab : StateTab,\n        selector: () => this.props,\n      },\n      {\n        name: 'Chart',\n        component: ChartTab,\n        selector: this.selector,\n      },\n      {\n        name: 'Raw',\n        component: RawTab,\n        selector: this.selector,\n      },\n    ];\n  }\n\n  render() {\n    let selected = this.props.selected;\n    if (selected === 'Chart' && this.props.parentTab === 'Diff')\n      selected = 'Tree';\n\n    return (\n      <Tabs\n        tabs={this.tabs! as any}\n        selected={selected || 'Tree'}\n        onClick={this.props.selectMonitorTab}\n      />\n    );\n  }\n}\n\nconst mapStateToProps = (state: CoreStoreState) => ({\n  parentTab: state.monitor.monitorState!.tabName,\n  selected: state.monitor.monitorState!.subTabName,\n});\n\nconst actionCreators = {\n  selectMonitorTab,\n};\n\nexport default connect(mapStateToProps, actionCreators)(SubTabs);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/containers/monitors/InspectorWrapper/VisualDiffTab.tsx",
    "content": "import React, { Component } from 'react';\nimport type { Delta } from 'jsondiffpatch';\nimport * as htmlFormatter from 'jsondiffpatch/formatters/html';\nimport styled from '@emotion/styled';\nimport { Base16Theme, effects } from '@redux-devtools/ui';\n\nexport const StyledContainer = styled.div`\n  .jsondiffpatch-delta {\n    line-height: 14px;\n    font-size: 12px;\n    padding: 12px;\n    margin: 0;\n    display: inline-block;\n  }\n\n  .jsondiffpatch-delta pre {\n    font-size: 12px;\n    margin: 0;\n    padding: 2px 3px;\n    border-radius: 3px;\n    position: relative;\n    color: ${(props: { theme?: Base16Theme }) => props.theme!.base07};\n    display: inline-block;\n  }\n\n  ul.jsondiffpatch-delta {\n    list-style-type: none;\n    padding: 0 0 0 20px;\n    margin: 0;\n  }\n\n  .jsondiffpatch-delta ul {\n    list-style-type: none;\n    padding: 0 0 0 20px;\n    margin: 0;\n  }\n\n  .jsondiffpatch-left-value,\n  .jsondiffpatch-right-value {\n    vertical-align: top;\n  }\n\n  .jsondiffpatch-modified .jsondiffpatch-right-value:before {\n    vertical-align: top;\n    padding: 2px;\n    color: ${(props) => props.theme.base0E};\n    content: ' => ';\n  }\n\n  .jsondiffpatch-added .jsondiffpatch-value pre,\n  .jsondiffpatch-modified .jsondiffpatch-right-value pre,\n  .jsondiffpatch-textdiff-added {\n    background: ${(props: { theme?: Base16Theme }) =>\n      effects.color(props.theme!.base0B, 'alpha', 0.2)};\n  }\n\n  .jsondiffpatch-deleted pre,\n  .jsondiffpatch-modified .jsondiffpatch-left-value pre,\n  .jsondiffpatch-textdiff-deleted {\n    background: ${(props: { theme?: Base16Theme }) =>\n      effects.color(props.theme!.base08, 'alpha', 0.2)};\n    text-decoration: line-through;\n  }\n\n  .jsondiffpatch-unchanged,\n  .jsondiffpatch-movedestination {\n    color: gray;\n  }\n\n  .jsondiffpatch-unchanged,\n  .jsondiffpatch-movedestination > .jsondiffpatch-value {\n    transition: all 0.5s;\n    -webkit-transition: all 0.5s;\n    overflow-y: hidden;\n  }\n\n  .jsondiffpatch-unchanged-showing .jsondiffpatch-unchanged,\n  .jsondiffpatch-unchanged-showing\n    .jsondiffpatch-movedestination\n    > .jsondiffpatch-value {\n    max-height: 100px;\n  }\n\n  .jsondiffpatch-unchanged-hidden .jsondiffpatch-unchanged,\n  .jsondiffpatch-unchanged-hidden\n    .jsondiffpatch-movedestination\n    > .jsondiffpatch-value {\n    max-height: 0;\n  }\n\n  .jsondiffpatch-unchanged-hiding\n    .jsondiffpatch-movedestination\n    > .jsondiffpatch-value,\n  .jsondiffpatch-unchanged-hidden\n    .jsondiffpatch-movedestination\n    > .jsondiffpatch-value {\n    display: block;\n  }\n\n  .jsondiffpatch-unchanged-visible .jsondiffpatch-unchanged,\n  .jsondiffpatch-unchanged-visible\n    .jsondiffpatch-movedestination\n    > .jsondiffpatch-value {\n    max-height: 100px;\n  }\n\n  .jsondiffpatch-unchanged-hiding .jsondiffpatch-unchanged,\n  .jsondiffpatch-unchanged-hiding\n    .jsondiffpatch-movedestination\n    > .jsondiffpatch-value {\n    max-height: 0;\n  }\n\n  .jsondiffpatch-unchanged-showing .jsondiffpatch-arrow,\n  .jsondiffpatch-unchanged-hiding .jsondiffpatch-arrow {\n    display: none;\n  }\n\n  .jsondiffpatch-value {\n    display: inline-block;\n  }\n\n  .jsondiffpatch-property-name {\n    display: inline-block;\n    padding: 2px 0;\n    padding-right: 5px;\n    vertical-align: top;\n    color: ${(props) => props.theme.base0D};\n  }\n\n  .jsondiffpatch-property-name:after {\n    content: ': ';\n    color: ${(props) => props.theme.base07};\n  }\n\n  .jsondiffpatch-child-node-type-array > .jsondiffpatch-property-name:after {\n    content: ': [';\n  }\n\n  .jsondiffpatch-child-node-type-array:after {\n    content: '],';\n  }\n\n  div.jsondiffpatch-child-node-type-array:before {\n    content: '[';\n  }\n\n  div.jsondiffpatch-child-node-type-array:after {\n    content: ']';\n  }\n\n  .jsondiffpatch-child-node-type-object > .jsondiffpatch-property-name:after {\n    content: ': {';\n  }\n\n  .jsondiffpatch-child-node-type-object:after {\n    content: '},';\n  }\n\n  div.jsondiffpatch-child-node-type-object:before {\n    content: '{';\n  }\n\n  div.jsondiffpatch-child-node-type-object:after {\n    content: '}';\n  }\n\n  .jsondiffpatch-value pre:after {\n    color: ${(props) => props.theme.base07};\n    content: ',';\n  }\n\n  li:last-child > .jsondiffpatch-value pre:after,\n  .jsondiffpatch-modified > .jsondiffpatch-left-value pre:after {\n    content: '';\n  }\n\n  .jsondiffpatch-modified .jsondiffpatch-value {\n    display: inline-block;\n  }\n\n  .jsondiffpatch-modified .jsondiffpatch-right-value {\n    margin-left: 5px;\n  }\n\n  .jsondiffpatch-moved .jsondiffpatch-value {\n    display: none;\n  }\n\n  .jsondiffpatch-moved .jsondiffpatch-moved-destination {\n    display: inline-block;\n    background: ${(props) => props.theme.base0A};\n  }\n\n  .jsondiffpatch-moved .jsondiffpatch-moved-destination:before {\n    content: ' => ';\n  }\n\n  ul.jsondiffpatch-textdiff {\n    padding: 0;\n  }\n\n  .jsondiffpatch-textdiff-location {\n    display: inline-block;\n    min-width: 60px;\n  }\n\n  .jsondiffpatch-textdiff-line {\n    display: inline-block;\n  }\n\n  .jsondiffpatch-textdiff-line-number:after {\n    content: ',';\n  }\n\n  .jsondiffpatch-error {\n    background: red;\n    color: white;\n    font-weight: bold;\n  }\n`;\n\ninterface Props {\n  data?: Delta;\n}\n\nexport default class VisualDiffTab extends Component<Props> {\n  shouldComponentUpdate(nextProps: Props) {\n    return this.props.data !== nextProps.data;\n  }\n\n  render() {\n    let __html: string | undefined;\n    const data = this.props.data;\n    if (data) {\n      __html = htmlFormatter.format(data, undefined);\n    }\n\n    return <StyledContainer dangerouslySetInnerHTML={{ __html: __html! }} />;\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/containers/monitors/InspectorWrapper/index.tsx",
    "content": "import React, { Component } from 'react';\nimport { Action } from 'redux';\nimport {\n  DevtoolsInspectorAction,\n  DevtoolsInspectorProps,\n  DevtoolsInspectorState,\n  InspectorMonitor,\n  Tab,\n} from '@redux-devtools/inspector-monitor';\nimport { TraceTab } from '@redux-devtools/inspector-monitor-trace-tab';\nimport { TestTab } from '@redux-devtools/inspector-monitor-test-tab';\nimport { DATA_TYPE_KEY } from '../../../constants/dataTypes.js';\nimport SubTabs from './SubTabs.js';\n\nconst DEFAULT_TABS = [\n  {\n    name: 'Action',\n    component: SubTabs,\n  },\n  {\n    name: 'State',\n    component: SubTabs,\n  },\n  {\n    name: 'Diff',\n    component: SubTabs,\n  },\n  {\n    name: 'Trace',\n    component: TraceTab,\n  },\n];\n\ninterface Features {\n  test?: boolean;\n  skip?: boolean;\n}\ninterface Props {\n  features?: Features;\n}\n\nclass InspectorWrapper extends Component<Props> {\n  static update: (\n    props: DevtoolsInspectorProps<unknown, Action<string>>,\n    state: DevtoolsInspectorState | undefined,\n    action: DevtoolsInspectorAction,\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n  ) => DevtoolsInspectorState = InspectorMonitor.update;\n\n  render() {\n    const { features, ...rest } = this.props;\n    let tabs: () => Tab<unknown, Action<string>>[];\n    if (features && features.test) {\n      tabs = () => [\n        ...(DEFAULT_TABS as Tab<unknown, Action<string>>[]),\n        { name: 'Test', component: TestTab } as unknown as Tab<\n          unknown,\n          Action<string>\n        >,\n      ];\n    } else {\n      tabs = () => DEFAULT_TABS as Tab<unknown, Action<string>>[];\n    }\n\n    return (\n      <InspectorMonitor\n        dataTypeKey={DATA_TYPE_KEY}\n        invertTheme={false}\n        tabs={tabs}\n        hideActionButtons={!features!.skip}\n        hideMainButtons\n        {...rest}\n      />\n    );\n  }\n}\n\nexport default InspectorWrapper;\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/containers/monitors/Slider.tsx",
    "content": "import React, { Component } from 'react';\nimport styled from '@emotion/styled';\nimport { withTheme } from '@emotion/react';\nimport { SliderMonitor } from '@redux-devtools/slider-monitor';\nimport { LiftedAction } from '@redux-devtools/core';\nimport { Action } from 'redux';\nimport { Base16Theme, ThemeFromProvider } from '@redux-devtools/ui';\nimport { State } from '../../reducers/instances.js';\n\nconst SliderWrapper = styled.div`\n  border-color: ${(props: { theme?: Base16Theme }) => props.theme!.base02};\n  border-style: solid;\n  border-width: 1px 0;\n`;\n\ninterface Props {\n  liftedState: State;\n  dispatch: (action: LiftedAction<unknown, Action<string>, unknown>) => void;\n  theme: ThemeFromProvider;\n}\n\nclass Slider extends Component<Props> {\n  shouldComponentUpdate(nextProps: Props) {\n    return (\n      nextProps.liftedState !== this.props.liftedState ||\n      nextProps.theme.scheme !== this.props.theme.scheme\n    );\n  }\n  render() {\n    return (\n      <SliderWrapper className=\"slider\">\n        <SliderMonitor\n          {...this.props.liftedState}\n          // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n          // @ts-ignore\n          dispatch={this.props.dispatch}\n          theme={this.props.theme}\n          hideResetButton\n        />\n      </SliderWrapper>\n    );\n  }\n}\n\nexport default withTheme(Slider);\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/index.tsx",
    "content": "export * from './actions/index.js';\nexport { default as DispatcherButton } from './components/buttons/DispatcherButton.js';\nexport { default as ExportButton } from './components/buttons/ExportButton.js';\nexport { default as ImportButton } from './components/buttons/ImportButton.js';\nexport { default as PrintButton } from './components/buttons/PrintButton.js';\nexport { default as SliderButton } from './components/buttons/SliderButton.js';\nexport { default as Header } from './components/Header.js';\nexport { default as MonitorSelector } from './components/MonitorSelector.js';\nexport { default as Settings } from './components/Settings/index.js';\nexport { default as TopButtons } from './components/TopButtons.js';\nexport { default as App } from './containers/App.js';\nexport { default as DevTools } from './containers/DevTools.js';\nexport { default as Dispatcher } from './containers/monitors/Dispatcher.js';\nexport { default as SliderMonitor } from './containers/monitors/Slider.js';\nexport * from './constants/actionTypes.js';\nexport { default as middlewares } from './middlewares/index.js';\nexport * from './middlewares/exportState.js';\nexport * from './reducers/index.js';\nexport * from './reducers/instances.js';\nexport * from './reducers/monitor.js';\nexport * from './reducers/notification.js';\nexport * from './reducers/reports.js';\nexport * from './reducers/section.js';\nexport * from './reducers/theme.js';\nexport * from './reducers/stateTreeSettings.js';\nexport * from './utils/stringifyJSON.js';\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/middlewares/exportState.ts",
    "content": "import { stringifyJSON } from '../utils/stringifyJSON.js';\nimport {\n  UPDATE_STATE,\n  LIFTED_ACTION,\n  EXPORT,\n} from '../constants/actionTypes.js';\nimport { getActiveInstance } from '../reducers/instances.js';\nimport { Dispatch, Middleware } from 'redux';\nimport { CoreStoreAction } from '../actions/index.js';\nimport { CoreStoreState } from '../reducers/index.js';\n\nlet toExport: string | number | undefined;\n\nfunction download(state: string) {\n  const blob = new Blob([state], { type: 'octet/stream' });\n  const href = window.URL.createObjectURL(blob);\n  const a = document.createElement('a');\n  a.style.display = 'none';\n  a.download = 'state.json';\n  a.href = href;\n  document.body.appendChild(a);\n  a.click();\n  setTimeout(() => {\n    document.body.removeChild(a);\n    window.URL.revokeObjectURL(href);\n  }, 0);\n}\n\nexport const exportStateMiddleware: Middleware<\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  {},\n  CoreStoreState,\n  Dispatch<CoreStoreAction>\n> = (store) => (next) => (untypedAction) => {\n  const result = next(untypedAction);\n\n  const action = untypedAction as CoreStoreAction;\n  if (\n    toExport &&\n    action.type === UPDATE_STATE &&\n    action.request!.type === 'EXPORT'\n  ) {\n    const request = action.request!;\n    const id = request.instanceId || request.id;\n    if (id === toExport) {\n      toExport = undefined;\n      download(\n        JSON.stringify(\n          {\n            payload: request.payload,\n            preloadedState: request.committedState,\n          },\n          null,\n          '\\t',\n        ),\n      );\n    }\n  } else if (action.type === EXPORT) {\n    const instances = store.getState().instances;\n    const instanceId = getActiveInstance(instances);\n    const options = instances.options[instanceId];\n    if (options.features.export === true) {\n      download(stringifyJSON(instances.states[instanceId], options.serialize));\n    } else {\n      toExport = instanceId;\n      next({ type: LIFTED_ACTION, message: 'EXPORT', toExport: true });\n    }\n  }\n  return result;\n};\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/middlewares/index.ts",
    "content": "import { exportStateMiddleware } from './exportState.js';\n\nconst middlewares = [exportStateMiddleware];\n\nexport default middlewares;\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/reducers/index.ts",
    "content": "import { section, SectionState } from './section.js';\nimport { monitor, MonitorState } from './monitor.js';\nimport { notification, NotificationState } from './notification.js';\nimport { instances, InstancesState } from './instances.js';\nimport { reports, ReportsState } from './reports.js';\nimport { theme, ThemeState } from './theme.js';\nimport { stateTreeSettings, StateTreeSettings } from './stateTreeSettings.js';\n\nexport interface CoreStoreState {\n  readonly section: SectionState;\n  readonly theme: ThemeState;\n  readonly stateTreeSettings: StateTreeSettings;\n  readonly monitor: MonitorState;\n  readonly instances: InstancesState;\n  readonly reports: ReportsState;\n  readonly notification: NotificationState;\n}\n\nexport const coreReducers = {\n  section,\n  theme,\n  stateTreeSettings,\n  monitor,\n  instances,\n  reports,\n  notification,\n};\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/reducers/instances.ts",
    "content": "import { PerformAction } from '@redux-devtools/core';\nimport { Action } from 'redux';\nimport {\n  UPDATE_STATE,\n  SET_STATE,\n  LIFTED_ACTION,\n  SELECT_INSTANCE,\n  REMOVE_INSTANCE,\n  TOGGLE_PERSIST,\n  TOGGLE_SYNC,\n  SET_PERSIST,\n  CLEAR_INSTANCES,\n} from '../constants/actionTypes.js';\nimport parseJSON from '../utils/parseJSON.js';\nimport { recompute } from '../utils/updateState.js';\nimport {\n  ActionCreator,\n  LiftedActionDispatchAction,\n  Request,\n  CoreStoreAction,\n} from '../actions/index.js';\n\nexport interface Features {\n  lock?: boolean;\n  export?: string | boolean;\n  import?: string | boolean;\n  persist?: boolean;\n  pause?: boolean;\n  reorder?: boolean;\n  jump?: boolean;\n  skip?: boolean;\n  dispatch?: boolean;\n  sync?: boolean;\n  test?: boolean;\n}\n\nexport interface Options {\n  name?: string | number;\n  connectionId?: string | number;\n  explicitLib?: string;\n  lib?: string;\n  actionCreators?: ActionCreator[];\n  features: Features;\n  serialize?: boolean;\n}\n\nexport interface State {\n  actionsById: { [actionId: number]: PerformAction<Action<string>> };\n  computedStates: { state: unknown; error?: string }[];\n  currentStateIndex: number;\n  nextActionId: number;\n  skippedActionIds: number[];\n  stagedActionIds: number[];\n  committedState?: unknown;\n  isLocked?: boolean;\n  isPaused?: boolean;\n}\n\nexport interface InstancesState {\n  selected: string | number | null;\n  current: string | number;\n  sync: boolean;\n  connections: { [id: string]: (string | number)[] };\n  options: { [id: string]: Options };\n  states: { [id: string]: State };\n  persisted?: boolean;\n}\n\nexport const instancesInitialState: InstancesState = {\n  selected: null,\n  current: 'default',\n  sync: false,\n  connections: {},\n  options: { default: { features: {} } },\n  states: {\n    default: {\n      actionsById: {},\n      computedStates: [],\n      currentStateIndex: -1,\n      nextActionId: 0,\n      skippedActionIds: [],\n      stagedActionIds: [],\n    },\n  },\n};\n\nfunction updateState(\n  state: { [id: string]: State },\n  request: Request,\n  id: string | number,\n  serialize: boolean | undefined,\n) {\n  let payload: State = request.payload as State;\n  const actionsById = request.actionsById;\n  if (actionsById) {\n    payload = {\n      ...payload,\n      actionsById: parseJSON(actionsById, serialize),\n      computedStates: parseJSON(request.computedStates, serialize),\n    } as State;\n    if (request.type === 'STATE' && request.committedState) {\n      payload.committedState = payload.computedStates[0].state;\n    }\n  } else {\n    payload = parseJSON(payload as unknown as string, serialize) as State;\n  }\n\n  let newState;\n  const liftedState = state[id] || state.default;\n  const action = ((request.action && parseJSON(request.action, serialize)) ||\n    {}) as PerformAction<Action<string>>;\n\n  switch (request.type) {\n    case 'INIT':\n      newState = recompute(state.default, payload, {\n        action: { type: '@@INIT' },\n        timestamp: (action as { timestamp?: number }).timestamp || Date.now(),\n      });\n      break;\n    case 'ACTION': {\n      const isExcess = request.isExcess;\n      const nextActionId = request.nextActionId || liftedState.nextActionId + 1;\n      const maxAge = request.maxAge;\n      if (Array.isArray(action)) {\n        // Batched actions\n        newState = liftedState;\n        for (let i = 0; i < action.length; i++) {\n          newState = recompute(\n            newState,\n            request.batched ? payload : (payload as unknown as State[])[i],\n            action[i] as PerformAction<Action<string>>,\n            newState.nextActionId + 1,\n            maxAge,\n            isExcess,\n          );\n        }\n      } else {\n        newState = recompute(\n          liftedState,\n          payload,\n          action,\n          nextActionId,\n          maxAge,\n          isExcess,\n        );\n      }\n      break;\n    }\n    case 'STATE':\n      newState = payload;\n      if (newState.computedStates.length <= newState.currentStateIndex) {\n        newState.currentStateIndex = newState.computedStates.length - 1;\n      }\n      break;\n    case 'PARTIAL_STATE': {\n      const maxAge = request.maxAge;\n      const nextActionId = payload.nextActionId;\n      const stagedActionIds = payload.stagedActionIds;\n      let computedStates = payload.computedStates;\n      let oldActionsById;\n      let oldComputedStates;\n      let committedState;\n      if (nextActionId > maxAge) {\n        const oldStagedActionIds = liftedState.stagedActionIds;\n        const excess = oldStagedActionIds.indexOf(stagedActionIds[1]);\n        let key;\n        if (excess > 0) {\n          oldComputedStates = liftedState.computedStates.slice(excess - 1);\n          oldActionsById = { ...liftedState.actionsById };\n          for (let i = 1; i < excess; i++) {\n            key = oldStagedActionIds[i];\n            if (key) delete oldActionsById[key];\n          }\n          committedState = computedStates[0].state;\n        } else {\n          oldActionsById = liftedState.actionsById;\n          oldComputedStates = liftedState.computedStates;\n          committedState = liftedState.committedState;\n        }\n      } else {\n        oldActionsById = liftedState.actionsById;\n        oldComputedStates = liftedState.computedStates;\n        committedState = liftedState.committedState;\n      }\n      computedStates = [...oldComputedStates, ...computedStates];\n      const statesCount = computedStates.length;\n      let currentStateIndex = payload.currentStateIndex;\n      if (statesCount <= currentStateIndex) currentStateIndex = statesCount - 1;\n\n      newState = {\n        ...liftedState,\n        actionsById: { ...oldActionsById, ...payload.actionsById },\n        computedStates,\n        currentStateIndex,\n        nextActionId,\n        stagedActionIds,\n        committedState,\n      };\n      break;\n    }\n    case 'LIFTED':\n      newState = liftedState;\n      break;\n    default:\n      return state;\n  }\n\n  if (request.liftedState) newState = { ...newState, ...request.liftedState };\n  return { ...state, [id]: newState };\n}\n\nexport function dispatchAction(\n  state: InstancesState,\n  { action }: LiftedActionDispatchAction,\n) {\n  if (action.type === 'JUMP_TO_STATE' || action.type === 'JUMP_TO_ACTION') {\n    const id = state.selected || state.current;\n    const liftedState = state.states[id];\n    const currentStateIndex =\n      action.type === 'JUMP_TO_STATE'\n        ? action.index\n        : liftedState.stagedActionIds.indexOf(action.actionId);\n    return {\n      ...state,\n      states: {\n        ...state.states,\n        [id]: { ...liftedState, currentStateIndex },\n      },\n    };\n  }\n  return state;\n}\n\nfunction removeState(state: InstancesState, connectionId: string | number) {\n  const instanceIds = state.connections[connectionId];\n  if (!instanceIds) return state;\n\n  const connections = { ...state.connections };\n  const options = { ...state.options };\n  const states = { ...state.states };\n  let selected = state.selected;\n  let current = state.current;\n  let sync = state.sync;\n\n  delete connections[connectionId];\n  instanceIds.forEach((id) => {\n    if (id === selected) {\n      selected = null;\n      sync = false;\n    }\n    if (id === current) {\n      const inst = Object.keys(connections)[0];\n      if (inst) current = connections[inst][0];\n      else current = 'default';\n    }\n    delete options[id];\n    delete states[id];\n  });\n  return {\n    selected,\n    current,\n    sync,\n    connections,\n    options,\n    states,\n  };\n}\n\nfunction init(\n  { type, action, name, libConfig = {} }: Request,\n  connectionId: string | number,\n  current: string | number,\n): Options {\n  let lib;\n  let actionCreators;\n  let creators = libConfig.actionCreators || action;\n  if (typeof creators === 'string') creators = JSON.parse(creators);\n  if (Array.isArray(creators)) actionCreators = creators;\n  if (type === 'STATE') lib = 'redux';\n  return {\n    name: libConfig.name || name || current,\n    connectionId,\n    explicitLib: libConfig.type,\n    lib,\n    actionCreators,\n    features: libConfig.features\n      ? libConfig.features\n      : {\n          lock: lib === 'redux',\n          export: libConfig.type === 'redux' ? 'custom' : true,\n          import: 'custom',\n          persist: true,\n          pause: true,\n          reorder: true,\n          jump: true,\n          skip: true,\n          dispatch: true,\n          sync: true,\n          test: true,\n        },\n    serialize: libConfig.serialize,\n  };\n}\n\nexport function instances(\n  state = instancesInitialState,\n  action: CoreStoreAction,\n): InstancesState {\n  switch (action.type) {\n    case UPDATE_STATE: {\n      const { request } = action;\n      if (!request) return state;\n      const connectionId = (action.id || request.id)!;\n      const current = request.instanceId || connectionId;\n      let connections = state.connections;\n      let options = state.options;\n\n      if (typeof state.options[current] === 'undefined') {\n        connections = {\n          ...state.connections,\n          [connectionId]: [...(connections[connectionId] || []), current],\n        };\n        options = {\n          ...options,\n          [current]: init(request, connectionId, current),\n        };\n      }\n\n      return {\n        ...state,\n        current,\n        connections,\n        options,\n        states: updateState(\n          state.states,\n          request,\n          current,\n          options[current].serialize,\n        ),\n      };\n    }\n    case SET_STATE:\n      return {\n        ...state,\n        states: {\n          ...state.states,\n          [getActiveInstance(state)]: action.newState,\n        },\n      };\n    case TOGGLE_PERSIST:\n      return { ...state, persisted: !state.persisted };\n    case SET_PERSIST:\n      return { ...state, persisted: action.payload };\n    case TOGGLE_SYNC:\n      return { ...state, sync: !state.sync };\n    case SELECT_INSTANCE:\n      return { ...state, selected: action.selected, sync: false };\n    case REMOVE_INSTANCE:\n      return removeState(state, action.id);\n    case LIFTED_ACTION: {\n      if (action.message === 'DISPATCH') return dispatchAction(state, action);\n      if (action.message === 'IMPORT') {\n        const id = state.selected || state.current;\n        if (state.options[id].features.import === true) {\n          return {\n            ...state,\n            states: {\n              ...state.states,\n              [id]: parseJSON(action.state) as State,\n            },\n          };\n        }\n      }\n      return state;\n    }\n    case CLEAR_INSTANCES:\n      return instancesInitialState;\n    default:\n      return state;\n  }\n}\n\nexport const getActiveInstance = (instances: InstancesState) =>\n  instances.selected || instances.current;\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/reducers/monitor.ts",
    "content": "import { REHYDRATE } from 'redux-persist';\nimport {\n  MONITOR_ACTION,\n  SELECT_MONITOR,\n  UPDATE_MONITOR_STATE,\n  TOGGLE_SLIDER,\n  TOGGLE_DISPATCHER,\n} from '../constants/actionTypes.js';\nimport { MonitorActionAction, CoreStoreAction } from '../actions/index.js';\n\nexport interface MonitorStateMonitorState {\n  inspectedStatePath?: string[];\n  tabName?: string;\n  subTabName?: string;\n  selectedActionId?: number | null;\n  startActionId?: number | null;\n  inspectedActionPath?: string[];\n  __overwritten__?: string;\n}\nexport interface MonitorState {\n  selected: string;\n  monitorState?: MonitorStateMonitorState | undefined;\n  sliderIsOpen: boolean;\n  dispatcherIsOpen: boolean;\n}\n\nconst initialState: MonitorState = {\n  selected: 'InspectorMonitor',\n  monitorState: undefined,\n  sliderIsOpen: true,\n  dispatcherIsOpen: false,\n};\n\nexport function dispatchMonitorAction(\n  state: MonitorState,\n  action: MonitorActionAction,\n): MonitorState {\n  return {\n    ...state,\n    monitorState: (action.action.newMonitorState ||\n      action.monitorReducer(\n        action.monitorProps,\n        state.monitorState,\n        action.action,\n      )) as MonitorStateMonitorState,\n  };\n}\n\nexport function monitor(\n  state = initialState,\n  action: CoreStoreAction,\n): MonitorState {\n  switch (action.type) {\n    case MONITOR_ACTION:\n      return dispatchMonitorAction(state, action);\n    case SELECT_MONITOR: {\n      let monitorState = state.monitorState;\n      if (action.monitorState) {\n        monitorState = {\n          ...action.monitorState,\n          __overwritten__: action.monitor,\n        };\n      }\n      return {\n        ...state,\n        monitorState,\n        selected: action.monitor,\n      };\n    }\n    case UPDATE_MONITOR_STATE: {\n      let inspectedStatePath = state.monitorState!.inspectedStatePath!;\n      if (action.nextState.inspectedStatePath) {\n        inspectedStatePath = [\n          ...inspectedStatePath.slice(0, -1),\n          ...action.nextState.inspectedStatePath,\n        ];\n      }\n      return {\n        ...state,\n        monitorState: {\n          ...state.monitorState,\n          ...action.nextState,\n          inspectedStatePath,\n        },\n      };\n    }\n    case TOGGLE_SLIDER:\n      return {\n        ...state,\n        sliderIsOpen: !state.sliderIsOpen,\n      };\n    case TOGGLE_DISPATCHER:\n      return {\n        ...state,\n        dispatcherIsOpen: !state.dispatcherIsOpen,\n      };\n    case REHYDRATE: {\n      const rehydratedState = action.payload as\n        | {\n            readonly monitor: MonitorState;\n          }\n        | undefined;\n      if (!rehydratedState) return state;\n      if (\n        rehydratedState.monitor.monitorState &&\n        (typeof rehydratedState.monitor.monitorState.selectedActionId ===\n          'number' ||\n          typeof rehydratedState.monitor.monitorState.startActionId ===\n            'number')\n      ) {\n        return {\n          ...rehydratedState.monitor,\n          monitorState: {\n            ...rehydratedState.monitor.monitorState,\n            selectedActionId: null,\n            startActionId: null,\n          },\n        };\n      }\n      return rehydratedState.monitor;\n    }\n    default:\n      return state;\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/reducers/notification.ts",
    "content": "import {\n  SHOW_NOTIFICATION,\n  CLEAR_NOTIFICATION,\n  LIFTED_ACTION,\n  ERROR,\n} from '../constants/actionTypes.js';\nimport { CoreStoreAction } from '../actions/index.js';\n\ninterface Notification {\n  readonly type: 'error';\n  readonly message: string;\n}\nexport type NotificationState = Notification | null;\n\nexport function notification(\n  state: NotificationState = null,\n  action: CoreStoreAction,\n): NotificationState {\n  switch (action.type) {\n    case SHOW_NOTIFICATION:\n      return action.notification;\n    case ERROR:\n      return { type: 'error', message: action.payload };\n    case LIFTED_ACTION:\n      return null;\n    case CLEAR_NOTIFICATION:\n      return null;\n    default:\n      return state;\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/reducers/reports.ts",
    "content": "import {\n  UPDATE_REPORTS /* , GET_REPORT_SUCCESS */,\n} from '../constants/actionTypes.js';\nimport { CoreStoreAction } from '../actions/index.js';\n\nexport interface Data {\n  id: unknown;\n}\n\nexport interface ReportsState {\n  data: Data[];\n}\n\nconst initialState: ReportsState = {\n  data: [],\n};\n\nexport function reports(\n  state = initialState,\n  action: CoreStoreAction,\n): ReportsState {\n  /* if (action.type === GET_REPORT_SUCCESS) {\n    const id = action.data.id;\n    return {\n      ...state,\n      data: state.data.map(d => (d.id === id ? action.data : d))\n    };\n  } else */ if (action.type !== UPDATE_REPORTS) return state;\n\n  const request = action.request;\n  switch (request.type) {\n    case 'list':\n      return {\n        ...state,\n        data: request.data,\n      };\n    case 'add':\n      return {\n        ...state,\n        data: [...state.data, request.data],\n      };\n    case 'remove':\n      return {\n        ...state,\n        data: state.data.filter((d) => d.id !== request.id),\n      };\n    default:\n      return state;\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/reducers/section.ts",
    "content": "import { CHANGE_SECTION } from '../constants/actionTypes.js';\nimport { CoreStoreAction } from '../actions/index.js';\n\nexport type SectionState = string;\n\nexport function section(state = 'Actions', action: CoreStoreAction) {\n  if (action.type === CHANGE_SECTION) {\n    return action.section;\n  }\n  return state;\n}\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/reducers/stateTreeSettings.ts",
    "content": "import { CHANGE_STATE_TREE_SETTINGS } from '../constants/actionTypes.js';\nimport { CoreStoreAction } from '../actions/index.js';\n\nexport interface StateTreeSettings {\n  readonly sortAlphabetically: boolean;\n  readonly disableCollection: boolean;\n}\n\nexport function stateTreeSettings(\n  state: StateTreeSettings = {\n    sortAlphabetically: false,\n    disableCollection: false,\n  },\n  action: CoreStoreAction,\n) {\n  if (action.type === CHANGE_STATE_TREE_SETTINGS) {\n    return {\n      sortAlphabetically: action.sortAlphabetically,\n      disableCollection: action.disableCollection,\n    };\n  }\n  return state;\n}\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/reducers/theme.ts",
    "content": "import { SchemeName, ThemeName } from '@redux-devtools/ui';\nimport { CHANGE_THEME } from '../constants/actionTypes.js';\nimport { CoreStoreAction } from '../actions/index.js';\n\nexport interface ThemeState {\n  readonly theme: ThemeName;\n  readonly scheme: SchemeName;\n  readonly colorPreference: 'auto' | 'light' | 'dark';\n}\n\nexport function theme(\n  state: ThemeState = {\n    theme: 'default',\n    scheme: 'default',\n    colorPreference: 'auto',\n  },\n  action: CoreStoreAction,\n) {\n  if (action.type === CHANGE_THEME) {\n    return {\n      theme: action.theme,\n      scheme: action.scheme,\n      colorPreference: action.colorPreference,\n    };\n  }\n  return state;\n}\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/utils/commitExcessActions.ts",
    "content": "// Based on https://github.com/gaearon/redux-devtools/pull/241\n/* eslint-disable no-param-reassign */\n\nimport { State } from '../reducers/instances.js';\n\nexport default function commitExcessActions(liftedState: State, n = 1) {\n  // Auto-commits n-number of excess actions.\n  let excess = n;\n  let idsToDelete = liftedState.stagedActionIds.slice(1, excess + 1);\n\n  for (let i = 0; i < idsToDelete.length; i++) {\n    if (liftedState.computedStates[i + 1].error) {\n      // Stop if error is found. Commit actions up to error.\n      excess = i;\n      idsToDelete = liftedState.stagedActionIds.slice(1, excess + 1);\n      break;\n    } else {\n      delete liftedState.actionsById[idsToDelete[i]];\n    }\n  }\n\n  liftedState.skippedActionIds = liftedState.skippedActionIds.filter(\n    (id) => !idsToDelete.includes(id),\n  );\n  liftedState.stagedActionIds = [\n    0,\n    ...liftedState.stagedActionIds.slice(excess + 1),\n  ];\n  liftedState.committedState = liftedState.computedStates[excess].state;\n  liftedState.computedStates = liftedState.computedStates.slice(excess);\n  liftedState.currentStateIndex =\n    liftedState.currentStateIndex > excess\n      ? liftedState.currentStateIndex - excess\n      : 0;\n}\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/utils/getMonitor.tsx",
    "content": "import React from 'react';\nimport { LogMonitor } from '@redux-devtools/log-monitor';\nimport ChartMonitorWrapper from '../containers/monitors/ChartMonitorWrapper.js';\nimport InspectorWrapper from '../containers/monitors/InspectorWrapper/index.js';\nimport { RtkQueryMonitor } from '@redux-devtools/rtk-query-monitor';\n\nexport const monitors = [\n  { value: 'InspectorMonitor', name: 'Inspector' },\n  { value: 'LogMonitor', name: 'Log monitor' },\n  { value: 'ChartMonitor', name: 'Chart' },\n  { value: 'RtkQueryMonitor', name: 'RTK Query' },\n];\n\nexport default function getMonitor({ monitor }: { monitor: string }) {\n  switch (monitor) {\n    case 'LogMonitor':\n      return (\n        <LogMonitor preserveScrollTop={false} hideMainButtons markStateDiff />\n      );\n    case 'ChartMonitor':\n      return <ChartMonitorWrapper />;\n    case 'RtkQueryMonitor':\n      return <RtkQueryMonitor />;\n    default:\n      return <InspectorWrapper />;\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/utils/parseJSON.ts",
    "content": "import jsan from 'jsan';\nimport { DATA_TYPE_KEY, DATA_REF_KEY } from '../constants/dataTypes.js';\n\nexport function reviver(key: string, value: unknown) {\n  if (\n    typeof value === 'object' &&\n    value !== null &&\n    '__serializedType__' in value &&\n    typeof (value as any).data === 'object'\n  ) {\n    const data = (value as any).data;\n    data[DATA_TYPE_KEY] = (value as any).__serializedType__;\n    if ('__serializedRef__' in value)\n      data[DATA_REF_KEY] = (value as any).__serializedRef__;\n    /*\n    if (Array.isArray(data)) {\n      data.__serializedType__ = value.__serializedType__;\n    } else {\n      Object.defineProperty(data, '__serializedType__', {\n        value: value.__serializedType__\n      });\n    }\n    */\n    return data;\n  }\n  return value;\n}\n\nexport default function parseJSON(\n  data: string | undefined,\n  serialize?: boolean,\n) {\n  if (typeof data !== 'string') return data;\n  try {\n    return serialize ? jsan.parse(data, reviver) : jsan.parse(data);\n  } catch (e) {\n    if (process.env.NODE_ENV !== 'production')\n      /* eslint-disable-next-line no-console */\n      console.error(data + 'is not a valid JSON', e);\n    return undefined;\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/utils/stringifyJSON.ts",
    "content": "import jsan from 'jsan';\nimport { DATA_TYPE_KEY, DATA_REF_KEY } from '../constants/dataTypes.js';\n\nfunction replacer(key: string, value: unknown) {\n  if (typeof value === 'object' && value !== null && DATA_TYPE_KEY in value) {\n    const __serializedType__ = (value as any)[DATA_TYPE_KEY];\n    const clone = { ...value };\n    delete (clone as any)[DATA_TYPE_KEY]; // eslint-disable-line no-param-reassign\n    const r = { data: clone, __serializedType__ };\n    if (DATA_REF_KEY in value)\n      (r as any).__serializedRef__ = (clone as any)[DATA_REF_KEY];\n    return r;\n  }\n  return value;\n}\n\nexport function stringifyJSON(data: unknown, serialize: boolean | undefined) {\n  return serialize\n    ? jsan.stringify(data, replacer, null as unknown as undefined, true)\n    : jsan.stringify(data);\n}\n"
  },
  {
    "path": "packages/redux-devtools-app-core/src/utils/updateState.ts",
    "content": "import commitExcessActions from './commitExcessActions.js';\nimport { State } from '../reducers/instances.js';\nimport { Action } from 'redux';\nimport { PerformAction } from '@redux-devtools/core';\n\nexport function recompute(\n  previousLiftedState: State,\n  storeState: State,\n  action:\n    | PerformAction<Action<string>>\n    | { action: Action<string>; timestamp?: number; stack?: string },\n  nextActionId = 1,\n  maxAge?: number,\n  isExcess?: boolean,\n) {\n  const actionId = nextActionId - 1;\n  const liftedState = { ...previousLiftedState };\n\n  if (\n    liftedState.currentStateIndex ===\n    liftedState.stagedActionIds.length - 1\n  ) {\n    liftedState.currentStateIndex++;\n  }\n  liftedState.stagedActionIds = [...liftedState.stagedActionIds, actionId];\n  liftedState.actionsById = { ...liftedState.actionsById };\n  if ((action as PerformAction<Action<string>>).type === 'PERFORM_ACTION') {\n    liftedState.actionsById[actionId] = action as PerformAction<Action<string>>;\n  } else {\n    liftedState.actionsById[actionId] = {\n      action: action.action || action,\n      timestamp: action.timestamp || Date.now(),\n      stack: action.stack,\n      type: 'PERFORM_ACTION',\n    };\n  }\n  liftedState.nextActionId = nextActionId;\n  liftedState.computedStates = [\n    ...liftedState.computedStates,\n    { state: storeState },\n  ];\n\n  if (isExcess) commitExcessActions(liftedState);\n  else if (maxAge) {\n    const excess = liftedState.stagedActionIds.length - maxAge;\n    if (excess > 0) commitExcessActions(liftedState, excess);\n  }\n\n  return liftedState;\n}\n"
  },
  {
    "path": "packages/redux-devtools-app-core/test/__mocks__/styleMock.ts",
    "content": "export default {};\n"
  },
  {
    "path": "packages/redux-devtools-app-core/test/app.spec.tsx",
    "content": "import { jest } from '@jest/globals';\nimport React from 'react';\nimport { Provider } from 'react-redux';\nimport { createStore, applyMiddleware, Reducer } from 'redux';\nimport { render, screen, within } from '@testing-library/react';\nimport App from '../src/containers/App.js';\nimport { exportStateMiddleware } from '../src/middlewares/exportState.js';\nimport { coreReducers } from '../src/reducers/index.js';\nimport { DATA_TYPE_KEY } from '../src/constants/dataTypes.js';\nimport { stringifyJSON } from '../src/utils/stringifyJSON.js';\nimport { combineReducers } from 'redux';\nimport { CoreStoreAction, CoreStoreState } from '../src/index.js';\n\nObject.defineProperty(window, 'matchMedia', {\n  writable: true,\n  value: jest.fn().mockImplementation((query) => ({\n    matches: false,\n    media: query,\n    onchange: null,\n    addListener: jest.fn(), // deprecated\n    removeListener: jest.fn(), // deprecated\n    addEventListener: jest.fn(),\n    removeEventListener: jest.fn(),\n    dispatchEvent: jest.fn(),\n  })),\n});\n\nconst store = createStore(\n  combineReducers(coreReducers) as Reducer<\n    CoreStoreState,\n    CoreStoreAction,\n    Partial<CoreStoreState>\n  >,\n  applyMiddleware(exportStateMiddleware),\n);\n\ndescribe('App container', () => {\n  it(\"should render inspector monitor's wrapper\", () => {\n    render(\n      <Provider store={store}>\n        <App />\n      </Provider>,\n    );\n    expect(screen.getByTestId('inspector')).toBeDefined();\n  });\n\n  it('should contain an empty action list', () => {\n    render(\n      <Provider store={store}>\n        <App />\n      </Provider>,\n    );\n    const actionList = screen.getByTestId('actionList');\n    expect(within(actionList).queryByRole('button')).not.toBeInTheDocument();\n  });\n});\n\ndescribe('stringifyJSON', () => {\n  it('should not mutate the source object', () => {\n    const src = {\n      isTest: true,\n      [DATA_TYPE_KEY]: 'Test',\n    };\n\n    const result = {\n      data: {\n        isTest: true,\n      },\n      __serializedType__: 'Test',\n    };\n\n    expect(stringifyJSON(src, true)).toEqual(JSON.stringify(result));\n    expect(src).toEqual({\n      isTest: true,\n      [DATA_TYPE_KEY]: 'Test',\n    });\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-app-core/test/setup.ts",
    "content": "import '@testing-library/jest-dom';\n"
  },
  {
    "path": "packages/redux-devtools-app-core/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\",\n    \"types\": [\"node\"]\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-app-core/tsconfig.test.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"jest\"]\n  },\n  \"include\": [\"src\", \"test\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-chart-monitor/CHANGELOG.md",
    "content": "# Change Log\n\n## 6.0.0\n\n### Major Changes\n\n- 12849a4: Convert monitors to ESM\n\n### Patch Changes\n\n- Updated dependencies [804d6bd]\n  - @redux-devtools/core@5.0.0\n\n## 5.1.1\n\n### Patch Changes\n\n- Updated dependencies [91f21b2]\n  - @redux-devtools/core@4.1.1\n\n## 5.1.0\n\n### Minor Changes\n\n- 6830118: Add React 19 to peer deps\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - @redux-devtools/core@4.1.0\n\n## 5.0.2\n\n### Patch Changes\n\n- Updated dependencies [bbb1a40]\n  - react-base16-styling@0.10.0\n\n## 5.0.1\n\n### Patch Changes\n\n- Updated dependencies [191d419]\n  - d3-state-visualizer@3.0.0\n\n## 5.0.0\n\n### Major Changes\n\n- 5cfe3e5: Update min required React version to 16.8.4\n\n### Patch Changes\n\n- Updated dependencies [decc035]\n  - @redux-devtools/core@4.0.0\n\n## 4.1.0\n\n### Minor Changes\n\n- 6fc18ed7: Add new Redux version to peer dependencies\n\n### Patch Changes\n\n- 7f5bddbd: Widen peer dependencies\n\n## 4.0.1\n\n### Patch Changes\n\n- 65205f90: Replace Action<unknown> with Action<string>\n- Updated dependencies [65205f90]\n  - @redux-devtools/core@3.13.2\n\n## 4.0.0\n\n### Major Changes\n\n- b323f77d: Upgrade D3\n  - Split `style` option into `chartStyles`, `nodeStyleOptions`, `textStyleOptions`, and `linkStyles`.\n  - The shape of the argument passed to the `onClickText` option has been updated.\n\n### Patch Changes\n\n- Updated dependencies [b323f77d]\n  - d3-state-visualizer@2.0.0\n\n## 3.0.1\n\n### Patch Changes\n\n- a55ba302: Fix peer dependencies on @redux-devtools/core\n- Updated dependencies [a55ba302]\n  - @redux-devtools/core@3.13.1\n\n## 3.0.0\n\n### Minor Changes\n\n- 8a7eae4: Add React 18 to peerDependencies range\n\n### Patch Changes\n\n- Updated dependencies [8a7eae4]\n  - @redux-devtools/core@3.13.0\n\n## 2.1.1\n\n### Patch Changes\n\n- Updated dependencies [4891bf6]\n  - @redux-devtools/core@3.12.0\n\n## 2.0.0\n\n- Adds ESM build (https://github.com/reduxjs/redux-devtools/pull/997) and switches the default export to a named export in order to ensure that the CommonJS output and the ESM output are [interchangeable](https://rollupjs.org/guide/en/#outputexports):\n\n```diff\n- import ChartMonitor from '@redux-devtools/chart-monitor';\n+ import { ChartMonitor } from '@redux-devtools/chart-monitor';\n```\n\n## [1.9.0](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/chart-monitor@1.8.0...@redux-devtools/chart-monitor@1.9.0) (2021-03-06)\n\n### Features\n\n- update peer dependencies to allow react@^17 ([#703](https://github.com/reduxjs/redux-devtools/issues/703)) ([2aaa9c1](https://github.com/reduxjs/redux-devtools/commit/2aaa9c10a383e3a7ab20b3ab14639781fd7bb2eb))\n\n## 1.8.0 (2021-03-06)\n\n### Features\n\n- **redux-devtools-chart-monitor:** convert to TypeScript ([#642](https://github.com/reduxjs/redux-devtools/issues/642)) ([761baba](https://github.com/reduxjs/redux-devtools/commit/761baba0aa0f4dc672f8771f4b12bed3863557f7))\n\n## [1.7.2](https://github.com/reduxjs/redux-devtools/compare/redux-devtools-chart-monitor@1.7.1...redux-devtools-chart-monitor@1.7.2) (2020-09-07)\n\n**Note:** Version bump only for package redux-devtools-chart-monitor\n\n## 1.7.1 (2020-08-14)\n\n**Note:** Version bump only for package redux-devtools-chart-monitor\n"
  },
  {
    "path": "packages/redux-devtools-chart-monitor/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 romseguy\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/redux-devtools-chart-monitor/README.md",
    "content": "# Redux DevTools Chart Monitor\n\nA chart monitor for [Redux DevTools](https://github.com/gaearon/redux-devtools).\n\nCreated by [@romseguy](https://github.com/romseguy) and merged from [`reduxjs/redux-devtools-chart-monitor`](https://github.com/reduxjs/redux-devtools-chart-monitor).\n\nIt shows a real-time view of the store aka the current state of the app.\n\n:rocket: Now with immutable-js support.\n\n[Demo](http://romseguy.github.io/redux-store-visualizer/) [(Source)](https://github.com/romseguy/redux-store-visualizer)\n\n![Chart Monitor](https://camo.githubusercontent.com/19aebaeba929e97f97225115c49dc994299cb76e/687474703a2f2f692e696d6775722e636f6d2f4d53677655366c2e676966)\n\n### Installation\n\n```\nyarn add @redux-devtools/chart-monitor\n```\n\n### Usage\n\nYou can use `ChartMonitor` as the only monitor in your app:\n\n##### `containers/DevTools.js`\n\n```js\nimport React from 'react';\nimport { createDevTools } from '@redux-devtools/core';\nimport { ChartMonitor } from '@redux-devtools/chart-monitor';\n\nexport default createDevTools(<ChartMonitor />);\n```\n\nThen you can render `<DevTools>` to any place inside app or even into a separate popup window.\n\nAlternatively, you can use it together with [`DockMonitor`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-dock-monitor) to make it dockable.  \nConsult the [`DockMonitor` README](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-dock-monitor) for details of this approach.\n\n[Read how to start using Redux DevTools.](https://github.com/reduxjs/redux-devtools)\n\n### Features\n\n### Props\n\n#### ChartMonitor props\n\nYou can read the React component [propTypes](https://github.com/reduxjs/redux-devtools/blob/master/packages/redux-devtools-chart-monitor/src/Chart.js#L11) in addition to the details below:\n\n| Name                      | Description                                                                                                                                                                                                                                                                                                                                                                                                                    |\n| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `defaultIsVisible`        | By default, set to `true`.                                                                                                                                                                                                                                                                                                                                                                                                     |\n| `transitionDuration`      | By default, set to `750`, in milliseconds.                                                                                                                                                                                                                                                                                                                                                                                     |\n| `heightBetweenNodesCoeff` | By default, set to `1`.                                                                                                                                                                                                                                                                                                                                                                                                        |\n| `widthBetweenNodesCoeff`  | By default, set to `1.3`.                                                                                                                                                                                                                                                                                                                                                                                                      |\n| `isSorted`                | By default, set to `false`.                                                                                                                                                                                                                                                                                                                                                                                                    |\n| `chartStyles`             | {<br>&nbsp;&nbsp;width: '100%', height: '100%', // i.e fullscreen for [`DockMonitor`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-dock-monitor)<br>}                                                                                                                                                                                                                                         |\n| `textStyleOptions`        | {<br>&nbsp;&nbsp;colors: {<br>&nbsp;&nbsp;&nbsp;&nbsp;default: `theme.base0D`,<br>&nbsp;&nbsp;&nbsp;&nbsp;hover: `theme.base06`,<br>&nbsp;&nbsp;},<br>}                                                                                                                                                                                                                                                                        |\n| `nodeStyleOptions`        | {<br>&nbsp;&nbsp;colors: {<br>&nbsp;&nbsp;&nbsp;&nbsp;default: `theme.base0B`,<br>&nbsp;&nbsp;&nbsp;&nbsp;collapsed: `theme.base0B`,<br>&nbsp;&nbsp;&nbsp;&nbsp;parent: `theme.base0E`,<br>&nbsp;&nbsp;},<br>&nbsp;&nbsp;radius: 7,<br>}                                                                                                                                                                                       |\n| `onClickText`             | Function called with a reference to the clicked node as first argument when clicking on the text next to a node.                                                                                                                                                                                                                                                                                                               |\n| `tooltipOptions`          | {<br>&nbsp;&nbsp;disabled: false,<br>&nbsp;&nbsp;indentationSize: 2,<br>&nbsp;&nbsp;styles: {<br>&nbsp;&nbsp;&nbsp;&nbsp;'background-color': `theme.base06`,<br>&nbsp;&nbsp;&nbsp;&nbsp;'opacity': '0.7',<br>&nbsp;&nbsp;&nbsp;&nbsp;'border-radius': '5px',<br>&nbsp;&nbsp;&nbsp;&nbsp;'padding': '5px',<br>&nbsp;&nbsp;},<br>}<br>[More info](https://github.com/reduxjs/redux-devtools/tree/master/packages/d3tooltip#api). |\n\n#### Redux DevTools props\n\n| Name          | Description                                                                                                                                                                                                                                                                                                                         |\n| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `theme`       | Either a string referring to one of the themes provided by [redux-devtools-themes](https://github.com/gaearon/redux-devtools-themes) (feel free to contribute!) or a custom object of the same format. Optional. By default, set to [`'nicinabox'`](https://github.com/gaearon/redux-devtools-themes/blob/master/src/nicinabox.js). |\n| `invertTheme` | Boolean value that will invert the colors of the selected theme. Optional. By default, set to `false`                                                                                                                                                                                                                               |\n| `select`      | A function that selects the slice of the state for DevTools to show. For example, `state => state.thePart.iCare.about`. Optional. By default, set to `state => state`.                                                                                                                                                              |\n\n### License\n\nMIT\n"
  },
  {
    "path": "packages/redux-devtools-chart-monitor/eslint.config.mjs",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTsReact from '../../eslint.ts.react.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTsReact(import.meta.dirname),\n  {\n    ignores: ['lib'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-chart-monitor/package.json",
    "content": "{\n  \"name\": \"@redux-devtools/chart-monitor\",\n  \"version\": \"6.0.0\",\n  \"description\": \"Chart monitor for Redux DevTools\",\n  \"keywords\": [\n    \"redux\",\n    \"devtools\",\n    \"flux\",\n    \"react\",\n    \"chart\"\n  ],\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-chart-monitor\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"romseguy\",\n  \"files\": [\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": \"./lib/index.js\",\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run type-check && pnpm run lint\"\n  },\n  \"dependencies\": {\n    \"d3-state-visualizer\": \"workspace:^\",\n    \"deepmerge\": \"^4.3.1\",\n    \"react-base16-styling\": \"workspace:^\"\n  },\n  \"devDependencies\": {\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@types/react\": \"^19.2.14\",\n    \"react\": \"^19.2.4\",\n    \"redux\": \"^5.0.1\",\n    \"rimraf\": \"^6.1.3\",\n    \"typescript\": \"~5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@types/react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react\": \"^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"redux\": \"^3.4.0 || ^4.0.0 || ^5.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-chart-monitor/src/Chart.tsx",
    "content": "import React, { Component, createRef } from 'react';\nimport { tree } from 'd3-state-visualizer';\nimport type { Options } from 'd3-state-visualizer';\nimport { base16Themes } from 'react-base16-styling';\nimport type { Base16Theme } from 'react-base16-styling';\nimport { Action, Dispatch } from 'redux';\nimport { LiftedAction, LiftedState } from '@redux-devtools/core';\nimport { ChartMonitorState } from './reducers.js';\n\nconst wrapperStyle = {\n  width: '100%',\n  height: '100%',\n};\n\nexport interface Props<S, A extends Action<string>>\n  extends LiftedState<S, A, ChartMonitorState>, Options {\n  dispatch: Dispatch<LiftedAction<S, A, ChartMonitorState>>;\n  preserveScrollTop: boolean;\n  select: (state: S) => unknown;\n  theme: keyof typeof base16Themes | Base16Theme;\n  invertTheme: boolean;\n\n  state: S | null;\n  defaultIsVisible?: boolean;\n}\n\nclass Chart<S, A extends Action<string>> extends Component<Props<S, A>> {\n  divRef = createRef<HTMLDivElement>();\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  renderChart?: (state?: {} | null | undefined) => void;\n\n  componentDidMount() {\n    const { select, state, defaultIsVisible } = this.props;\n    this.renderChart = tree(this.divRef.current!, this.props);\n    if (defaultIsVisible) {\n      // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n      this.renderChart(select(state!) as {} | null | undefined);\n    }\n  }\n\n  UNSAFE_componentWillReceiveProps(nextProps: Props<S, A>) {\n    const { state, select, monitorState } = nextProps;\n\n    if (monitorState.isVisible !== false) {\n      // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n      this.renderChart!(select(state!) as {} | null | undefined);\n    }\n  }\n\n  render() {\n    return <div style={wrapperStyle} ref={this.divRef} />;\n  }\n}\n\nexport default Chart;\n"
  },
  {
    "path": "packages/redux-devtools-chart-monitor/src/ChartMonitor.tsx",
    "content": "import React, { CSSProperties, PureComponent } from 'react';\nimport { base16Themes } from 'react-base16-styling';\nimport type { Base16Theme } from 'react-base16-styling';\nimport {\n  ActionCreators,\n  LiftedAction,\n  LiftedState,\n} from '@redux-devtools/core';\nimport deepmerge from 'deepmerge';\nimport { Action, Dispatch } from 'redux';\nimport type { Options } from 'd3-state-visualizer';\n\nimport reducer, { ChartMonitorState } from './reducers.js';\nimport Chart, { Props } from './Chart.js';\n\nconst { reset, rollback, commit, sweep, toggleAction } = ActionCreators;\n\nconst styles: { container: CSSProperties } = {\n  container: {\n    fontFamily: 'monaco, Consolas, Lucida Console, monospace',\n    position: 'relative',\n    overflowY: 'hidden',\n    width: '100%',\n    height: '100%',\n    minWidth: 300,\n  },\n};\n\nfunction invertColors(theme: Base16Theme) {\n  return {\n    ...theme,\n    base00: theme.base07,\n    base01: theme.base06,\n    base02: theme.base05,\n    base03: theme.base04,\n    base04: theme.base03,\n    base05: theme.base02,\n    base06: theme.base01,\n    base07: theme.base00,\n  };\n}\n\nexport interface ChartMonitorProps<S, A extends Action<string>>\n  extends LiftedState<S, A, ChartMonitorState>, Options {\n  dispatch: Dispatch<LiftedAction<S, A, ChartMonitorState>>;\n  preserveScrollTop: boolean;\n  select: (state: S) => unknown;\n  theme: keyof typeof base16Themes | Base16Theme;\n  invertTheme: boolean;\n\n  defaultIsVisible?: boolean;\n}\n\nclass ChartMonitor<S, A extends Action<string>> extends PureComponent<\n  ChartMonitorProps<S, A>\n> {\n  static update = reducer;\n\n  static defaultProps = {\n    select: (state: unknown) => state,\n    theme: 'nicinabox',\n    preserveScrollTop: true,\n    invertTheme: false,\n  };\n\n  handleRollback = () => {\n    this.props.dispatch(rollback());\n  };\n\n  handleSweep = () => {\n    this.props.dispatch(sweep());\n  };\n\n  handleCommit = () => {\n    this.props.dispatch(commit());\n  };\n\n  handleToggleAction = (id: number) => {\n    this.props.dispatch(toggleAction(id));\n  };\n\n  handleReset = () => {\n    this.props.dispatch(reset());\n  };\n\n  getTheme() {\n    const { theme, invertTheme } = this.props;\n    if (typeof theme !== 'string') {\n      return invertTheme ? invertColors(theme) : theme;\n    }\n\n    if (typeof base16Themes[theme] !== 'undefined') {\n      return invertTheme\n        ? invertColors(base16Themes[theme])\n        : base16Themes[theme];\n    }\n\n    console.warn(\n      'DevTools theme ' + theme + ' not found, defaulting to nicinabox',\n    );\n    return invertTheme\n      ? invertColors(base16Themes.nicinabox)\n      : base16Themes.nicinabox;\n  }\n\n  getChartOptions(props = this.props): Props<S, A> {\n    const { computedStates } = props;\n    const theme = this.getTheme();\n\n    const defaultOptions = {\n      state: computedStates.length\n        ? computedStates[props.currentStateIndex].state\n        : null,\n      isSorted: false,\n      heightBetweenNodesCoeff: 1,\n      widthBetweenNodesCoeff: 1.3,\n      tooltipOptions: {\n        disabled: false,\n        offset: { left: 30, top: 10 },\n        indentationSize: 2,\n        styles: {\n          'background-color': theme.base06,\n          opacity: '0.7',\n          'border-radius': '5px',\n          padding: '5px',\n        },\n      },\n      chartStyles: {\n        width: '100%',\n        height: '100%',\n      },\n      nodeStyleOptions: {\n        colors: {\n          default: theme.base0B,\n          collapsed: theme.base0B,\n          parent: theme.base0E,\n        },\n        radius: 7,\n      },\n      textStyleOptions: {\n        colors: {\n          default: theme.base0D,\n          hover: theme.base06,\n        },\n      },\n    };\n\n    return deepmerge(defaultOptions, props);\n  }\n\n  render() {\n    const theme = this.getTheme();\n\n    return (\n      <div style={{ ...styles.container, backgroundColor: theme.base07 }}>\n        <Chart {...this.getChartOptions()} />\n      </div>\n    );\n  }\n}\n\nexport default ChartMonitor;\n"
  },
  {
    "path": "packages/redux-devtools-chart-monitor/src/actions.ts",
    "content": "export const TOGGLE_VISIBILITY =\n  '@@redux-devtools-log-monitor/TOGGLE_VISIBILITY';\ninterface ToggleVisibilityAction {\n  type: typeof TOGGLE_VISIBILITY;\n}\nexport type ChartMonitorAction = ToggleVisibilityAction;\n"
  },
  {
    "path": "packages/redux-devtools-chart-monitor/src/index.ts",
    "content": "export {\n  default as ChartMonitor,\n  type ChartMonitorProps,\n} from './ChartMonitor.js';\nexport { type ChartMonitorAction } from './actions.js';\nexport { type ChartMonitorState } from './reducers.js';\n"
  },
  {
    "path": "packages/redux-devtools-chart-monitor/src/reducers.ts",
    "content": "import { Action } from 'redux';\nimport { ChartMonitorAction, TOGGLE_VISIBILITY } from './actions.js';\nimport { ChartMonitorProps } from './ChartMonitor.js';\n\nfunction toggleVisibility<S, A extends Action<string>>(\n  props: ChartMonitorProps<S, A>,\n  state = props.defaultIsVisible,\n  action: ChartMonitorAction,\n): boolean {\n  if (action.type === TOGGLE_VISIBILITY) {\n    return !state;\n  }\n\n  if (props.defaultIsVisible !== undefined) {\n    return props.defaultIsVisible;\n  }\n\n  return true;\n}\n\nexport interface ChartMonitorState {\n  isVisible?: boolean;\n}\n\nexport default function reducer<S, A extends Action<string>>(\n  props: ChartMonitorProps<S, A>,\n  state: ChartMonitorState | undefined = {},\n  action: ChartMonitorAction,\n) {\n  return {\n    isVisible: toggleVisibility(props, state.isVisible, action),\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-chart-monitor/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-cli/CHANGELOG.md",
    "content": "# Change Log\n\n## 5.0.0\n\n### Major Changes\n\n- 56de415: Require Node.js 20\n\n### Patch Changes\n\n- Updated dependencies [6481386]\n  - @redux-devtools/app@8.0.0\n\n## 4.0.4\n\n### Patch Changes\n\n- Updated dependencies [6163276]\n  - @redux-devtools/app@7.0.0\n\n## 4.0.3\n\n### Patch Changes\n\n- @redux-devtools/app@6.2.2\n\n## 4.0.2\n\n### Patch Changes\n\n- @redux-devtools/app@6.2.1\n\n## 4.0.1\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - @redux-devtools/app@6.2.0\n\n## 4.0.0\n\n### Major Changes\n\n- 4dd0dd2: Require Node.js 18\n\n## 3.0.4\n\n### Patch Changes\n\n- Updated dependencies [5cfe3e5]\n  - @redux-devtools/app@6.0.0\n\n## 3.0.3\n\n### Patch Changes\n\n- Updated dependencies [158ba2c]\n  - @redux-devtools/app@5.0.0\n\n## 3.0.2\n\n### Patch Changes\n\n- Updated dependencies [e57bcb39]\n  - @redux-devtools/app@4.0.0\n\n## 3.0.1\n\n### Patch Changes\n\n- Updated dependencies [57751ff9]\n  - @redux-devtools/app@3.0.0\n\n## 3.0.0\n\n### Major Changes\n\n- 81ba239e: Dropped support for Node.js 14.\n\n### Patch Changes\n\n- @redux-devtools/app@2.2.2\n\n## 2.0.0\n\n### Major Changes\n\n- 7e129988: Convert @redux-devtools/cli to ESM. Please [read this](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c) for more info about ESM.\n  Update supported Node versions from `>=14.15.0` to `^14.13.1 || ^16.13.0 || >=18.12.0`.\n\n### Patch Changes\n\n- a7729dae: Updates `--open` flag to respect protocol and host when provided\n\n## 1.0.7\n\n### Patch Changes\n\n- ab3c0e2: Avoid persisting the selected action index between sessions\n- Updated dependencies [ab3c0e2]\n  - @redux-devtools/app@2.1.3\n\n## [1.0.0-9](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/cli@1.0.0-8...@redux-devtools/cli@1.0.0-9) (2021-06-11)\n\n**Note:** Version bump only for package @redux-devtools/cli\n\n## [1.0.0-8](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/cli@1.0.0-7...@redux-devtools/cli@1.0.0-8) (2021-06-11)\n\n### Bug Fixes\n\n- **cli:** fix starting Electron app ([#729](https://github.com/reduxjs/redux-devtools/issues/729)) ([457a201](https://github.com/reduxjs/redux-devtools/commit/457a201232d96a5c28dbaf3f8a42259a35b2b364))\n\n## [1.0.0-7](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/cli@1.0.0-6...@redux-devtools/cli@1.0.0-7) (2021-04-06)\n\n### Bug Fixes\n\n- **cli:** include dist directory in publish ([#707](https://github.com/reduxjs/redux-devtools/issues/707)) ([95c8c55](https://github.com/reduxjs/redux-devtools/commit/95c8c5520d7ad4d087edcbda2ab500436feffc4a))\n\n## [1.0.0-6](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/cli@1.0.0-5...@redux-devtools/cli@1.0.0-6) (2021-03-06)\n\n**Note:** Version bump only for package @redux-devtools/cli\n\n## 1.0.0-5 (2021-03-06)\n\n### Bug Fixes\n\n- **cli:** resolve dependency issues ([#666](https://github.com/reduxjs/redux-devtools/issues/666)) ([e39e439](https://github.com/reduxjs/redux-devtools/commit/e39e43968b445ecbdcdab515050c5338cadabbe6))\n- **redux-devtools-cli:** forward port to spawned electron ([#564](https://github.com/reduxjs/redux-devtools/issues/564)) ([a1c2f06](https://github.com/reduxjs/redux-devtools/commit/a1c2f068b53ad205d448baa86003c3313f7ab2d1))\n\n## [1.0.0-4](https://github.com/reduxjs/redux-devtools/compare/redux-devtools-cli@1.0.0-3...redux-devtools-cli@1.0.0-4) (2020-09-07)\n\n**Note:** Version bump only for package redux-devtools-cli\n\n## [1.0.0-3](https://github.com/reduxjs/redux-devtools/compare/redux-devtools-cli@1.0.0-2...redux-devtools-cli@1.0.0-3) (2020-08-14)\n\n### Bug Fixes\n\n- **redux-devtools-cli:** forward port to spawned electron ([#564](https://github.com/reduxjs/redux-devtools/issues/564)) ([a1c2f06](https://github.com/reduxjs/redux-devtools/commit/a1c2f068b53ad205d448baa86003c3313f7ab2d1))\n"
  },
  {
    "path": "packages/redux-devtools-cli/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 Mihail Diordiev\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/redux-devtools-cli/README.md",
    "content": "# Redux DevTools Command Line Interface\n\nBridge for remote debugging via [Redux DevTools extension](https://github.com/zalmoxisus/redux-devtools-extension), [Remote Redux DevTools](https://github.com/zalmoxisus/remote-redux-devtools) or [RemoteDev](https://github.com/zalmoxisus/remotedev).\n\n### Usage\n\n#### Install the package globally\n\nwith npm:\n\n```\nnpm install -g @redux-devtools/cli\n```\n\nor with yarn:\n\n```\nyarn global add @redux-devtools/cli\n```\n\nand start as:\n\n```\nredux-devtools --hostname=localhost --port=8000\n```\n\n> Note the package is called `@redux-devtools/cli` not `redux-devtools` (the latter is a React component).\n\n#### Or add in your project\n\nwith npm:\n\n```\nnpm install --save-dev @redux-devtools/cli\n```\n\nor with yarn:\n\n```\nyarn add --dev @redux-devtools/cli\n```\n\nand add to `package.json`:\n\n```\n\"scripts\": {\n  \"redux-devtools\": \"redux-devtools --hostname=localhost --port=8000\"\n}\n```\n\nSo, you can start redux-devtools server by running `npm run redux-devtools`.\n\n##### Import in your `server.js` script you use for starting a development server:\n\n```js\nvar reduxDevTools = require('@redux-devtools/cli');\nreduxDevTools({ hostname: 'localhost', port: 8000 });\n```\n\nSo, you can start redux-devtools server together with your dev server.\n\n### Open Redux DevTools\n\nYou can add `--open` argument (or set it as `electron`) to open Redux DevTools as a standalone application:\n\n```\nredux-devtools --open\n```\n\nSet it as `browser` to open as a web app in the default browser instead:\n\n```\nredux-devtools --open=browser\n```\n\nTo specify the browser:\n\n```\nredux-devtools --open=firefox\n```\n\n### Connection settings\n\nSet `hostname` and `port` to the values you want. `hostname` by default is `localhost` and `port` is `8000`.\n\nTo use WSS, set `protocol` argument to `https` and provide `key`, `cert` and `passphrase` arguments.\n\n#### Available options\n\n| Console argument | description                                                                                                                                                                                                                                                   | default value |\n| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |\n| `--hostname`     | hostname                                                                                                                                                                                                                                                      | localhost     |\n| `--port`         | port                                                                                                                                                                                                                                                          | 8000          |\n| `--protocol`     | protocol                                                                                                                                                                                                                                                      | http          |\n| `--key`          | the key file for [running an https server](https://github.com/SocketCluster/socketcluster#using-over-https) (`--protocol` must be set to 'https')                                                                                                             | -             |\n| `--cert`         | the cert file for [running an https server](https://github.com/SocketCluster/socketcluster#using-over-https) (`--protocol` must be set to 'https')                                                                                                            | -             |\n| `--passphrase`   | the key passphrase for [running an https server](https://github.com/SocketCluster/socketcluster#using-over-https) (`--protocol` must be set to 'https')                                                                                                       | -             |\n| `--dbOptions`    | database configuration, can be whether an object or a path (string) to json configuration file (by default it uses our `./defaultDbOptions.json` file. Set `migrate` key to `true` to use our migrations file. [More details bellow](#save-reports-and-logs). | -             |\n| `--logLevel`     | the socket server log level - 0=none, 1=error, 2=warn, 3=info                                                                                                                                                                                                 | 3             |\n| `--wsEngine`     | the socket server web socket engine - ws or uws (sc-uws)                                                                                                                                                                                                      | ws            |\n| `--open`         | open Redux DevTools as a standalone application or as web app. See [Open Redux DevTools](#open-redux-devtools) for details.                                                                                                                                   | false         |\n\n### Inject to React Native local server\n\n##### Add in your React Native app's `package.json`:\n\n```\n\"scripts\": {\n  \"redux-devtools\": \"redux-devtools --hostname=localhost --port=8000 --injectserver=reactnative\"\n}\n```\n\nThe `injectserver` value can be `reactnative` or `macos` ([react-native-macos](https://github.com/ptmt/react-native-macos)), it used `reactnative` by default.\n\nThen, we can start React Native server and Redux DevTools server with one command (`npm start`).\n\n##### Revert the injection\n\nAdd in your React Native app's `package.json`:\n\n```\n\"scripts\": {\n  \"redux-devtools-revert\": \"redux-devtools --revert=reactnative\"\n}\n```\n\nOr just run `$(npm bin)/redux-devtools --revert`.\n\n### Connect from Android device or emulator\n\n> Note that if you're using `injectserver` argument explained above, this step is not necessary.\n\nIf you're running an Android 5.0+ device connected via USB or an Android emulator, use [adb command line tool](http://developer.android.com/tools/help/adb.html) to setup port forwarding from the device to your computer:\n\n```\nadb reverse tcp:8000 tcp:8000\n```\n\nIf you're still use Android 4.0, you should use `10.0.2.2` (Genymotion: `10.0.3.2`) instead of `localhost` in [remote-redux-devtools](https://github.com/zalmoxisus/remote-redux-devtools#storeconfigurestorejs) or [remotedev](https://github.com/zalmoxisus/remotedev#usage).\n\n### Save reports and logs\n\nYou can store reports via [`redux-remotedev`](https://github.com/zalmoxisus/redux-remotedev) and get them replicated with [Redux DevTools extension](https://github.com/zalmoxisus/redux-devtools-extension) or [Remote Redux DevTools](https://github.com/zalmoxisus/remote-redux-devtools). You can get action history right in the extension just by clicking the link from a report. Open `http://localhost:8000/graphql` (assuming you're using `localhost` as host and `8000`) to explore in GraphQL. Reports are posted to `http://localhost:8000/`. See examples in [tests](https://github.com/zalmoxisus/remotedev-server/blob/937cfa1f0ac9dc12ebf7068eeaa8b03022ec33bc/test/integration.spec.js#L110-L165).\n\nRedux DevTools server is database agnostic using `knex` schema. By default everything is stored in the memory using sqlite database. See [`defaultDbOptions.json`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-cli/defaultDbOptions.json) for example of sqlite. You can replace `\"connection\": { \"filename\": \":memory:\" },` with your file name (instead of `:memory:`) to persist teh database. Here's an example for PostgreSQL:\n\n```\n{\n  \"client\": \"pg\",\n  \"connection\": { \"user\": \"myuser\", \"password\": \"mypassword\", \"database\": \"mydb\" },\n  \"debug\": false,\n  \"migrate\": true\n}\n```\n\n### Advanced\n\n- [Writing your integration for a native application](https://github.com/reduxjs/redux-devtools/blob/master/docs/Integrations/Remote.md)\n\n### License\n\nMIT\n"
  },
  {
    "path": "packages/redux-devtools-cli/app/electron.cjs",
    "content": "// Based on https://github.com/electron/electron-quick-start\n\nconst { app, BrowserWindow } = require('electron');\nconst argv = require('minimist')(process.argv.slice(2));\n\nfunction createWindow() {\n  const mainWindow = new BrowserWindow({\n    width: 800,\n    height: 600,\n  });\n\n  const port = argv.port ? argv.port : 8000;\n  const host = argv.host ? argv.host : 'localhost';\n  const protocol = argv.protocol ? argv.protocol : 'http';\n\n  mainWindow.loadURL(protocol + '://' + host + ':' + port);\n}\n\napp.whenReady().then(() => {\n  createWindow();\n\n  app.on('activate', function () {\n    if (BrowserWindow.getAllWindows().length === 0) createWindow();\n  });\n});\n\napp.on('window-all-closed', function () {\n  if (process.platform !== 'darwin') app.quit();\n});\n"
  },
  {
    "path": "packages/redux-devtools-cli/app/index.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Redux DevTools</title>\n    <style>\n      html {\n        min-width: 350px;\n        min-height: 300px;\n      }\n      body {\n        position: fixed;\n        overflow: hidden;\n        height: 100%;\n        width: 100%;\n        margin: 0;\n        padding: 0;\n      }\n      #root {\n        height: 100%;\n      }\n      #root > div {\n        height: 100%;\n      }\n    </style>\n    <link href=\"/redux-devtools-app.min.css\" rel=\"stylesheet\" />\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script src=\"/react.production.min.js\"></script>\n    <script src=\"/react-dom.production.min.js\"></script>\n    <script src=\"/redux-devtools-app.min.js\"></script>\n    <script src=\"/port.js\"></script>\n    <script>\n      const container = document.querySelector('#root');\n      const element = React.createElement(ReduxDevToolsApp.Root, {\n        socketOptions: {\n          hostname: location.hostname,\n          port: reduxDevToolsPort,\n          autoReconnect: true,\n        },\n      });\n      ReactDOM.createRoot(container).render(element);\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/redux-devtools-cli/app/package.json",
    "content": "{\n  \"private\": true,\n  \"name\": \"@redux-devtools/cli\",\n  \"version\": \"0.0.1\",\n  \"main\": \"electron.cjs\",\n  \"description\": \"Remote Redux DevTools\",\n  \"authors\": \"Mihail Diordiev\"\n}\n"
  },
  {
    "path": "packages/redux-devtools-cli/bin/redux-devtools.js",
    "content": "#! /usr/bin/env node\n\nimport '../dist/bin/redux-devtools.js';\n"
  },
  {
    "path": "packages/redux-devtools-cli/defaultDbOptions.json",
    "content": "{\n  \"client\": \"sqlite3\",\n  \"connection\": { \"filename\": \":memory:\" },\n  \"useNullAsDefault\": true,\n  \"debug\": false,\n  \"migrate\": true\n}\n"
  },
  {
    "path": "packages/redux-devtools-cli/eslint.config.mjs",
    "content": "import globals from 'globals';\nimport eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTs from '../../eslint.ts.config.base.mjs';\nimport eslintTsJest from '../../eslint.ts.jest.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTs(import.meta.dirname),\n  ...eslintTsJest(import.meta.dirname),\n  {\n    ignores: ['dist', 'jest.config.ts', 'umd'],\n  },\n  {\n    languageOptions: {\n      globals: {\n        ...globals.nodeBuiltin,\n      },\n    },\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-cli/jest.config.ts",
    "content": "import { createDefaultEsmPreset, type JestConfigWithTsJest } from 'ts-jest';\n\nconst presetConfig = createDefaultEsmPreset({\n  tsconfig: 'tsconfig.test.json',\n});\n\nconst jestConfig: JestConfigWithTsJest = {\n  ...presetConfig,\n  moduleNameMapper: {\n    '^(\\\\.{1,2}/.*)\\\\.js$': '$1',\n  },\n};\n\nexport default jestConfig;\n"
  },
  {
    "path": "packages/redux-devtools-cli/package.json",
    "content": "{\n  \"name\": \"@redux-devtools/cli\",\n  \"version\": \"5.0.0\",\n  \"description\": \"CLI for remote debugging with Redux DevTools.\",\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-cli\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)\",\n  \"files\": [\n    \"bin\",\n    \"dist\",\n    \"src\",\n    \"app\",\n    \"index.js\",\n    \"defaultDbOptions.json\"\n  ],\n  \"type\": \"module\",\n  \"main\": \"dist/index.js\",\n  \"types\": \"dist/index.d.ts\",\n  \"bin\": {\n    \"redux-devtools\": \"bin/redux-devtools.js\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc && ncp ./src/api/schema_def.graphql ./dist/api/schema_def.graphql\",\n    \"start\": \"node ./bin/redux-devtools.js\",\n    \"start:electron\": \"node ./bin/redux-devtools.js --open\",\n    \"clean\": \"rimraf dist\",\n    \"test\": \"node --experimental-vm-modules node_modules/jest/bin/jest.js\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run type-check && pnpm run lint && pnpm run test\"\n  },\n  \"engines\": {\n    \"node\": \">=20\"\n  },\n  \"dependencies\": {\n    \"@apollo/server\": \"^5.2.0\",\n    \"@as-integrations/express5\": \"^1.1.2\",\n    \"@emotion/react\": \"^11.14.0\",\n    \"@emotion/styled\": \"^11.14.1\",\n    \"@redux-devtools/app\": \"workspace:^\",\n    \"@reduxjs/toolkit\": \"^2.11.2\",\n    \"@types/react\": \"^19.2.14\",\n    \"body-parser\": \"^2.2.2\",\n    \"chalk\": \"^5.6.2\",\n    \"cors\": \"^2.8.6\",\n    \"cross-spawn\": \"^7.0.6\",\n    \"electron\": \"^41.0.2\",\n    \"express\": \"^5.2.1\",\n    \"get-port\": \"^7.1.0\",\n    \"graphql\": \"^16.13.1\",\n    \"knex\": \"^3.1.0\",\n    \"lodash-es\": \"^4.17.23\",\n    \"minimist\": \"^1.2.8\",\n    \"morgan\": \"^1.10.1\",\n    \"open\": \"^11.0.0\",\n    \"react\": \"^19.2.4\",\n    \"react-dom\": \"^19.2.4\",\n    \"react-is\": \"^19.2.4\",\n    \"semver\": \"^7.7.4\",\n    \"socketcluster-server\": \"^20.0.0\",\n    \"sqlite3\": \"^6.0.1\",\n    \"uuid\": \"^13.0.0\"\n  },\n  \"devDependencies\": {\n    \"@jest/globals\": \"^30.3.0\",\n    \"@types/body-parser\": \"^1.19.6\",\n    \"@types/cors\": \"^2.8.19\",\n    \"@types/cross-spawn\": \"^6.0.6\",\n    \"@types/express\": \"^5.0.6\",\n    \"@types/jest\": \"^30.0.0\",\n    \"@types/lodash-es\": \"^4.17.12\",\n    \"@types/minimist\": \"^1.2.5\",\n    \"@types/morgan\": \"^1.9.10\",\n    \"@types/node\": \"^24.12.0\",\n    \"@types/semver\": \"^7.7.1\",\n    \"@types/socketcluster-client\": \"^20.0.0\",\n    \"@types/socketcluster-server\": \"^20.0.0\",\n    \"@types/supertest\": \"^7.2.0\",\n    \"@types/uuid\": \"^11.0.0\",\n    \"globals\": \"^17.4.0\",\n    \"jest\": \"^30.3.0\",\n    \"ncp\": \"^2.0.0\",\n    \"rimraf\": \"^6.1.3\",\n    \"socketcluster-client\": \"^20.0.1\",\n    \"supertest\": \"^7.2.2\",\n    \"ts-jest\": \"^29.4.6\",\n    \"typescript\": \"~5.9.3\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-cli/src/api/schema.ts",
    "content": "import fs from 'fs';\nimport type { Store } from '../store.js';\n\nexport const schema = fs.readFileSync(\n  new URL('./schema_def.graphql', import.meta.url),\n  'utf8',\n);\n\nexport const resolvers = {\n  Query: {\n    reports: function report(\n      source: unknown,\n      args: unknown,\n      context: { store: Store },\n    ) {\n      return context.store.listAll();\n    },\n    report: function report(\n      source: unknown,\n      args: { id: string },\n      context: { store: Store },\n    ) {\n      return context.store.get(args.id);\n    },\n  },\n};\n"
  },
  {
    "path": "packages/redux-devtools-cli/src/api/schema_def.graphql",
    "content": "# A list of options for the type of the report\nenum ReportType {\n  STATE\n  ACTION\n  STATES\n  ACTIONS\n}\n\ntype Report {\n  # Report ID\n  id: ID!\n  # Type of the report, can be: STATE, ACTION, STATES, ACTIONS\n  type: ReportType\n  # Briefly what happened\n  title: String\n  # Details supplied by the user\n  description: String\n  # The last dispatched action before the report was sent\n  action: String\n  # Stringified actions or the state or both, which should be loaded the application to reproduce the exact behavior\n  payload: String\n  # Stringified preloaded state object. Could be the initial state of the app or committed state (after dispatching COMMIT action or reaching maxAge)\n  preloadedState: String\n  # Screenshot url or blob as a string\n  screenshot: String\n  # User Agent String\n  userAgent: String\n  # Application version to group the reports and versioning\n  version: String\n  # Used to identify the user who sent the report\n  userId: String\n  # More detailed data about the user, usually it's a stringified object\n  user: String\n  # Everything else you want to send\n  meta: String\n  # Error message which invoked sending the report\n  exception: String\n  # Id to identify the store in case there are multiple stores\n  instanceId: String\n  # Timestamp when the report was added\n  added: String\n  # Id to identify the application (from apps table)\n  appId: ID\n}\n\n# Explore GraphQL query schema\ntype Query {\n  # List all reports\n  reports: [Report]\n  # Get a report by ID\n  report(\n    # Report ID\n    id: ID!\n  ): Report\n}\n\nschema {\n  query: Query\n  #mutation: Mutation\n}\n"
  },
  {
    "path": "packages/redux-devtools-cli/src/bin/injectServer.ts",
    "content": "import fs from 'fs';\nimport path from 'path';\nimport semver from 'semver';\nimport type { Options } from '../options.js';\n\nconst name = '@redux-devtools/cli';\nconst startFlag = '/* ' + name + ' start */';\nconst endFlag = '/* ' + name + ' end */';\nconst serverFlags: { [moduleName: string]: { [version: string]: string } } = {\n  'react-native': {\n    '0.0.1': '    _server(argv, config, resolve, reject);',\n    '0.31.0':\n      \"  runServer(args, config, () => console.log('\\\\nReact packager ready.\\\\n'));\",\n    '0.44.0-rc.0': '  runServer(args, config, startedCallback, readyCallback);',\n    '0.46.0-rc.0':\n      '  runServer(runServerArgs, configT, startedCallback, readyCallback);',\n    '0.57.0': '  runServer(args, configT);',\n  },\n  'react-native-desktop': {\n    '0.0.1': '    _server(argv, config, resolve, reject);',\n  },\n};\n\nfunction getModuleVersion(modulePath: string): string {\n  return JSON.parse(\n    fs.readFileSync(path.join(modulePath, 'package.json'), 'utf-8'),\n  ).version;\n}\n\nfunction getServerFlag(moduleName: string, version: string): string {\n  const flags = serverFlags[moduleName || 'react-native'];\n  const versions = Object.keys(flags);\n  let flag;\n  for (let i = 0; i < versions.length; i++) {\n    if (semver.gte(version, versions[i])) {\n      flag = flags[versions[i]];\n    }\n  }\n  return flag as string;\n}\n\nexport const dir = 'local-cli/server';\nexport const file = 'server.js';\nexport const fullPath = path.join(dir, file);\n\nexport function inject(\n  modulePath: string,\n  options: Options,\n  moduleName: string,\n) {\n  const filePath = path.join(modulePath, fullPath);\n  if (!fs.existsSync(filePath)) return false;\n\n  const serverFlag = getServerFlag(moduleName, getModuleVersion(modulePath));\n  const code = [\n    startFlag,\n    '    require(\"' + name + '\")(' + JSON.stringify(options) + ')',\n    '      .then(_remotedev =>',\n    '        _remotedev.ready.then(() => {',\n    '          if (!_remotedev.portAlreadyUsed) console.log(\"-\".repeat(80));',\n    '      ' + serverFlag,\n    '        })',\n    '      );',\n    endFlag,\n  ].join('\\n');\n\n  const serverCode = fs.readFileSync(filePath, 'utf-8');\n  let start = serverCode.indexOf(startFlag); // already injected ?\n  let end = serverCode.indexOf(endFlag) + endFlag.length;\n  if (start === -1) {\n    start = serverCode.indexOf(serverFlag);\n    end = start + serverFlag.length;\n  }\n  fs.writeFileSync(\n    filePath,\n    serverCode.substr(0, start) +\n      code +\n      serverCode.substr(end, serverCode.length),\n  );\n  return true;\n}\n\nexport function revert(\n  modulePath: string,\n  options: Options,\n  moduleName: string,\n) {\n  const filePath = path.join(modulePath, fullPath);\n  if (!fs.existsSync(filePath)) return false;\n\n  const serverFlag = getServerFlag(moduleName, getModuleVersion(modulePath));\n  const serverCode = fs.readFileSync(filePath, 'utf-8');\n  const start = serverCode.indexOf(startFlag); // already injected ?\n  const end = serverCode.indexOf(endFlag) + endFlag.length;\n  if (start !== -1) {\n    fs.writeFileSync(\n      filePath,\n      serverCode.substr(0, start) +\n        serverFlag +\n        serverCode.substr(end, serverCode.length),\n    );\n  }\n  return true;\n}\n"
  },
  {
    "path": "packages/redux-devtools-cli/src/bin/openApp.ts",
    "content": "import open from 'open';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport { createRequire } from 'module';\nimport spawn from 'cross-spawn';\nimport type { Options } from '../options.js';\n\nconst require = createRequire(import.meta.url);\n\nexport default async function openApp(app: true | string, options: Options) {\n  if (app === true || app === 'electron') {\n    try {\n      const port = options.port ? `--port=${options.port}` : '';\n      const host = options.host ? `--host=${options.host}` : '';\n      const protocol = options.protocol ? `--protocol=${options.protocol}` : '';\n\n      // eslint-disable-next-line @typescript-eslint/no-var-requires\n      spawn(require('electron') as string, [\n        path.join(\n          path.dirname(fileURLToPath(import.meta.url)),\n          '..',\n          '..',\n          'app',\n        ),\n        port,\n        host,\n        protocol,\n      ]);\n    } catch (error) {\n      /* eslint-disable no-console */\n      if ((error as Error).message === \"Cannot find module 'electron'\") {\n        // TODO: Move electron to dev-dependences to make our package installation faster when not needed.\n        console.log(\n          '   \\x1b[1;31m[Warn]\\x1b[0m Electron module not installed.\\n',\n        );\n        /*\n        We will use \"npm\" to install Electron via \"npm install -D\".\n        Do you want to install 'electron' (yes/no): yes\n        Installing 'electron' (running 'npm install -D webpack-cli')...\n        */\n      } else {\n        console.log(error);\n      }\n      /* eslint-enable no-console */\n    }\n    return;\n  }\n\n  await open(\n    `${options.protocol}://${options.host ?? 'localhost'}:${options.port}/`,\n    app !== 'browser' ? { app: { name: app } } : undefined,\n  );\n}\n"
  },
  {
    "path": "packages/redux-devtools-cli/src/bin/redux-devtools.ts",
    "content": "#! /usr/bin/env node\nimport fs from 'fs';\nimport path from 'path';\nimport parseArgs from 'minimist';\nimport chalk from 'chalk';\nimport * as injectServer from './injectServer.js';\nimport getOptions from '../options.js';\nimport server from '../index.js';\nimport openApp from './openApp.js';\n\nconst argv = parseArgs(process.argv.slice(2));\n\nconst options = getOptions(argv);\n\nfunction readFile(filePath: string) {\n  return fs.readFileSync(path.resolve(process.cwd(), filePath), 'utf-8');\n}\n\nif (argv.protocol === 'https') {\n  argv.key = argv.key ? readFile(argv.key as string) : null;\n  argv.cert = argv.cert ? readFile(argv.cert as string) : null;\n}\n\nfunction log(pass: boolean, msg: string) {\n  const prefix = pass ? chalk.green.bgBlack('PASS') : chalk.red.bgBlack('FAIL');\n  const color = pass ? chalk.blue : chalk.red;\n  console.log(prefix, color(msg)); // eslint-disable-line no-console\n}\n\nfunction getModuleName(type: string) {\n  switch (type) {\n    case 'macos':\n      return 'react-native-macos';\n    // react-native-macos is renamed from react-native-desktop\n    case 'desktop':\n      return 'react-native-desktop';\n    case 'reactnative':\n    default:\n      return 'react-native';\n  }\n}\n\nfunction getModulePath(moduleName: string) {\n  return path.join(process.cwd(), 'node_modules', moduleName);\n}\n\nfunction getModule(type: string) {\n  let moduleName = getModuleName(type);\n  let modulePath = getModulePath(moduleName);\n  if (type === 'desktop' && !fs.existsSync(modulePath)) {\n    moduleName = getModuleName('macos');\n    modulePath = getModulePath(moduleName);\n  }\n  return {\n    name: moduleName,\n    path: modulePath,\n  };\n}\n\nfunction injectRN(type: string, msg: string) {\n  const module = getModule(type);\n  const fn = type === 'revert' ? injectServer.revert : injectServer.inject;\n  const pass = fn(module.path, options, module.name);\n  log(\n    pass,\n    msg +\n      (pass\n        ? '.'\n        : ', the file `' +\n          path.join(module.name, injectServer.fullPath) +\n          '` not found.'),\n  );\n\n  process.exit(pass ? 0 : 1);\n}\n\nif (argv.revert) {\n  injectRN(\n    argv.revert as string,\n    'Revert injection of ReduxDevTools server from React Native local server',\n  );\n}\nif (argv.injectserver) {\n  injectRN(\n    argv.injectserver as string,\n    'Inject ReduxDevTools server into React Native local server',\n  );\n}\n\nconst response = await server(argv);\nif (argv.open && argv.open !== 'false') {\n  await response.ready;\n  await openApp(argv.open as string, options);\n}\n"
  },
  {
    "path": "packages/redux-devtools-cli/src/db/connector.ts",
    "content": "import path from 'path';\nimport { fileURLToPath } from 'url';\nimport knex from 'knex';\nimport type { Knex } from 'knex';\nimport { AGServer } from 'socketcluster-server';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\ntype KnexFunction = <TRecord extends {} = any, TResult = unknown[]>(\n  config: Knex.Config | string,\n) => Knex<TRecord, TResult>;\n\nexport default function connector(options: AGServer.AGServerOptions) {\n  const dbOptions = options.dbOptions as Knex.Config;\n  dbOptions.useNullAsDefault = true;\n  if (!(dbOptions as any).migrate) {\n    return (knex as unknown as KnexFunction)(dbOptions);\n  }\n\n  dbOptions.migrations = {\n    directory: path.join(\n      path.dirname(fileURLToPath(import.meta.url)),\n      'migrations',\n    ),\n  };\n  dbOptions.seeds = {\n    directory: path.join(path.dirname(fileURLToPath(import.meta.url)), 'seeds'),\n  };\n  const knexInstance = (knex as unknown as KnexFunction)(dbOptions);\n\n  /* eslint-disable no-console */\n  knexInstance.migrate\n    .latest({ loadExtensions: ['.js'] })\n    .then(function () {\n      return knexInstance.seed.run({ loadExtensions: ['.js'] });\n    })\n    .then(function () {\n      console.log('   \\x1b[0;32m[Done]\\x1b[0m Migrations are finished\\n');\n    })\n    .catch(function (error) {\n      console.error(error);\n    });\n  /* eslint-enable no-console */\n\n  return knexInstance;\n}\n"
  },
  {
    "path": "packages/redux-devtools-cli/src/db/migrations/index.ts",
    "content": "import { Knex } from 'knex';\n\nexport function up(knex: Knex) {\n  return Promise.all([\n    knex.schema.createTable('remotedev_reports', function (table) {\n      table.uuid('id').primary();\n      table.string('type');\n      table.string('title');\n      table.string('description');\n      table.string('action');\n      table.text('payload', 'longtext');\n      table.text('preloadedState', 'longtext');\n      table.text('screenshot', 'longtext');\n      table.string('userAgent');\n      table.string('version');\n      table.string('user');\n      table.string('userId');\n      table.string('instanceId');\n      table.string('meta');\n      table.string('exception');\n      table.timestamp('added').defaultTo(knex.fn.now());\n      table\n        .uuid('appId')\n        .references('id')\n        .inTable('remotedev_apps')\n        .onDelete('CASCADE')\n        .onUpdate('CASCADE')\n        .defaultTo('78626c31-e16b-4528-b8e5-f81301b627f4');\n    }),\n    knex.schema.createTable('remotedev_payloads', function (table) {\n      table.uuid('id').primary();\n      table.text('state');\n      table.text('action');\n      table.timestamp('added').defaultTo(knex.fn.now());\n      table\n        .uuid('reportId')\n        .references('id')\n        .inTable('remotedev_reports')\n        .onDelete('CASCADE')\n        .onUpdate('CASCADE');\n    }),\n    knex.schema.createTable('remotedev_apps', function (table) {\n      table.uuid('id').primary();\n      table.string('title');\n      table.string('description');\n      table.string('url');\n      table.timestamps(false, true);\n    }),\n    knex.schema.createTable('remotedev_users', function (table) {\n      table.uuid('id').primary();\n      table.string('name');\n      table.string('login');\n      table.string('email');\n      table.string('avatarUrl');\n      table.string('profileUrl');\n      table.string('oauthId');\n      table.string('oauthType');\n      table.string('token');\n      table.timestamps(false, true);\n    }),\n    knex.schema.createTable('remotedev_users_apps', function (table) {\n      table.boolean('readOnly').defaultTo(false);\n      table.uuid('userId');\n      table.uuid('appId');\n      table.primary(['userId', 'appId']);\n      table\n        .foreign('userId')\n        .references('id')\n        .inTable('remotedev_users')\n        .onDelete('CASCADE')\n        .onUpdate('CASCADE');\n      table\n        .foreign('appId')\n        .references('id')\n        .inTable('remotedev_apps')\n        .onDelete('CASCADE')\n        .onUpdate('CASCADE');\n    }),\n  ]);\n}\n\nexport function down(knex: Knex) {\n  return Promise.all([\n    knex.schema.dropTable('remotedev_reports'),\n    knex.schema.dropTable('remotedev_apps'),\n  ]);\n}\n"
  },
  {
    "path": "packages/redux-devtools-cli/src/db/seeds/index.ts",
    "content": "import { Knex } from 'knex';\n\nexport function seed(knex: Knex) {\n  return Promise.all([knex('remotedev_apps').del()]).then(function () {\n    return Promise.all([\n      knex('remotedev_apps').insert({\n        id: '78626c31-e16b-4528-b8e5-f81301b627f4',\n        title: 'Default',\n      }),\n    ]);\n  });\n}\n"
  },
  {
    "path": "packages/redux-devtools-cli/src/index.ts",
    "content": "import express from 'express';\nimport http from 'http';\nimport getPort from 'get-port';\nimport socketClusterServer from 'socketcluster-server';\nimport getOptions from './options.js';\nimport routes from './routes.js';\nimport createStore from './store.js';\n\n// const LOG_LEVEL_NONE = 0;\n// const LOG_LEVEL_ERROR = 1;\nconst LOG_LEVEL_WARN = 2;\nconst LOG_LEVEL_INFO = 3;\n\nexport default async function (argv: { [arg: string]: any }): Promise<{\n  portAlreadyUsed?: boolean;\n  ready: Promise<void>;\n}> {\n  const options = Object.assign(getOptions(argv), {\n    allowClientPublish: false,\n  });\n  const port = options.port;\n  const logLevel =\n    options.logLevel === undefined ? LOG_LEVEL_INFO : options.logLevel;\n  // Check port already used\n  const p = await getPort({ port });\n  if (port !== p) {\n    if (logLevel >= LOG_LEVEL_WARN) {\n      console.log(`[ReduxDevTools] Server port ${port} is already used.`);\n    }\n    return {\n      portAlreadyUsed: true,\n      ready: Promise.resolve(),\n    };\n  }\n\n  if (logLevel >= LOG_LEVEL_INFO) {\n    console.log('[ReduxDevTools] Start server...');\n    console.log('-'.repeat(80) + '\\n');\n  }\n  const httpServer = http.createServer();\n  const agServer = socketClusterServer.attach(httpServer, options);\n\n  const app = express();\n  // eslint-disable-next-line @typescript-eslint/no-misused-promises\n  httpServer.on('request', app);\n  const store = createStore(options);\n  app.use(routes(options, store, agServer));\n\n  agServer.setMiddleware(\n    agServer.MIDDLEWARE_INBOUND,\n    // eslint-disable-next-line @typescript-eslint/no-misused-promises\n    async (middlewareStream) => {\n      for await (const action of middlewareStream) {\n        if (action.type === action.TRANSMIT) {\n          const channel = action.receiver;\n          const data = action.data;\n          if (\n            channel.substring(0, 3) === 'sc-' ||\n            channel === 'respond' ||\n            channel === 'log'\n          ) {\n            void agServer.exchange.transmitPublish(channel, data);\n          } else if (channel === 'log-noid') {\n            void agServer.exchange.transmitPublish('log', {\n              id: action.socket.id,\n              data: data,\n            });\n          }\n        } else if (action.type === action.SUBSCRIBE) {\n          if (action.channel === 'report') {\n            store\n              .list()\n              .then(function (data) {\n                void agServer.exchange.transmitPublish('report', {\n                  type: 'list',\n                  data: data,\n                });\n              })\n              .catch(function (error) {\n                console.error(error);\n              });\n          }\n        }\n        action.allow();\n      }\n    },\n  );\n\n  void (async () => {\n    for await (const { socket } of agServer.listener('connection')) {\n      let channelToWatch: string, channelToEmit: string;\n      void (async () => {\n        for await (const request of socket.procedure('login')) {\n          const credentials = request.data;\n          if (credentials === 'master') {\n            channelToWatch = 'respond';\n            channelToEmit = 'log';\n          } else {\n            channelToWatch = 'log';\n            channelToEmit = 'respond';\n          }\n          request.end(channelToWatch);\n        }\n      })();\n      void (async () => {\n        for await (const request of socket.procedure('getReport')) {\n          const id = request.data as string;\n          store\n            .get(id)\n            .then(function (data) {\n              request.end(data);\n            })\n            .catch(function (error) {\n              console.error(error);\n            });\n        }\n      })();\n      void (async () => {\n        for await (const data of socket.listener('disconnect')) {\n          const channel = agServer.exchange.channel('sc-' + socket.id);\n          channel.unsubscribe();\n          void agServer.exchange.transmitPublish(channelToEmit!, {\n            id: socket.id,\n            type: 'DISCONNECTED',\n          });\n        }\n      })();\n    }\n  })();\n\n  httpServer.listen(options.port);\n  return {\n    ready: (async () => {\n      await agServer.listener('ready' as 'error').once();\n    })(),\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-cli/src/options.ts",
    "content": "import fs from 'fs';\n\ninterface ProtocolOptions {\n  key: string | undefined;\n  cert: string | undefined;\n  passphrase: string | undefined;\n}\n\ninterface DbOptions {\n  client: string;\n  connection: {\n    filename: string;\n  };\n  useNullAsDefault: boolean;\n  debug: boolean;\n  migrate: boolean;\n}\n\nexport interface Options {\n  host: string | undefined;\n  port: number;\n  protocol: 'http' | 'https';\n  protocolOptions: ProtocolOptions | undefined;\n  dbOptions: DbOptions;\n  maxRequestBody: string;\n  logHTTPRequests?: boolean;\n  logLevel: 0 | 1 | 3 | 2;\n  wsEngine: string;\n}\n\nexport default function getOptions(argv: { [arg: string]: any }): Options {\n  let dbOptions = argv.dbOptions;\n  if (typeof dbOptions === 'string') {\n    dbOptions = JSON.parse(fs.readFileSync(dbOptions, 'utf8'));\n  } else if (typeof dbOptions === 'undefined') {\n    dbOptions = JSON.parse(\n      fs.readFileSync(\n        new URL('../defaultDbOptions.json', import.meta.url),\n        'utf8',\n      ),\n    );\n  }\n\n  return {\n    host:\n      argv.hostname || process.env.npm_package_remotedev_hostname || undefined,\n    port: Number(argv.port || process.env.npm_package_remotedev_port) || 8000,\n    protocol:\n      argv.protocol || process.env.npm_package_remotedev_protocol || 'http',\n    protocolOptions: !(argv.protocol === 'https')\n      ? undefined\n      : {\n          key: argv.key || process.env.npm_package_remotedev_key || undefined,\n          cert:\n            argv.cert || process.env.npm_package_remotedev_cert || undefined,\n          passphrase:\n            argv.passphrase ||\n            process.env.npm_package_remotedev_passphrase ||\n            undefined,\n        },\n    dbOptions: dbOptions,\n    maxRequestBody: argv.passphrase || '16mb',\n    logHTTPRequests: argv.logHTTPRequests,\n    logLevel: argv.logLevel || 3,\n    wsEngine:\n      argv.wsEngine || process.env.npm_package_remotedev_wsengine || 'ws',\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-cli/src/routes.ts",
    "content": "import path from 'path';\nimport { createRequire } from 'module';\nimport { fileURLToPath } from 'url';\nimport express from 'express';\nimport type { Router } from 'express';\nimport morgan from 'morgan';\nimport * as http from 'http';\nimport bodyParser from 'body-parser';\nimport cors from 'cors';\nimport { AGServer } from 'socketcluster-server';\nimport { ApolloServer } from '@apollo/server';\nimport { expressMiddleware } from '@as-integrations/express5';\nimport type { AddData, ReportBaseFields, Store } from './store.js';\nimport { resolvers, schema } from './api/schema.js';\n\nconst app = express.Router();\n\nconst require = createRequire(import.meta.url);\n\nfunction serveUmdModule(name: string) {\n  app.use(\n    express.static(\n      path.dirname(require.resolve(name + '/package.json')) + '/umd',\n    ),\n  );\n}\n\ninterface Context {\n  store?: Store;\n}\n\nfunction routes(\n  options: AGServer.AGServerOptions,\n  store: Store,\n  scServer: AGServer,\n): Router {\n  const limit = options.maxRequestBody;\n  const logHTTPRequests = options.logHTTPRequests;\n\n  if (logHTTPRequests) {\n    if (typeof logHTTPRequests === 'object')\n      app.use(\n        morgan(\n          'combined',\n          logHTTPRequests as morgan.Options<\n            http.IncomingMessage,\n            http.ServerResponse\n          >,\n        ),\n      );\n    else app.use(morgan('combined'));\n  }\n\n  const server = new ApolloServer<Context>({\n    typeDefs: schema,\n    resolvers,\n  });\n  server\n    .start()\n    .then(() => {\n      app.use(\n        '/graphql',\n        cors<cors.CorsRequest>(),\n        bodyParser.json(),\n        expressMiddleware(server, {\n          context: () => Promise.resolve({ store }),\n        }),\n      );\n    })\n    .catch((error) => {\n      console.error(error);\n    });\n\n  serveUmdModule('react');\n  serveUmdModule('react-dom');\n  serveUmdModule('@redux-devtools/app');\n\n  app.get('/port.js', function (req, res) {\n    res.send(`reduxDevToolsPort = ${options.port}`);\n  });\n  app.get('/{*splat}', function (req, res) {\n    res.sendFile(\n      path.join(\n        path.dirname(fileURLToPath(import.meta.url)),\n        '../app/index.html',\n      ),\n    );\n  });\n\n  app.use(cors({ methods: 'POST' }));\n  app.use(bodyParser.json({ limit: limit }));\n  app.use(bodyParser.urlencoded({ limit: limit, extended: false }));\n\n  app.post('/', function (req, res) {\n    if (!req.body) {\n      res.status(404).end();\n      return;\n    }\n    switch (req.body.op) {\n      case 'get':\n        store\n          .get(req.body.id as string)\n          .then(function (r) {\n            res.send(r || {});\n          })\n          .catch(function (error) {\n            console.error(error);\n            res.sendStatus(500);\n          });\n        break;\n      case 'list':\n        store\n          .list(req.body.query as string, req.body.fields as string[])\n          .then(function (r) {\n            res.send(r);\n          })\n          .catch(function (error) {\n            console.error(error);\n            res.sendStatus(500);\n          });\n        break;\n      default:\n        store\n          .add(req.body as AddData)\n          .then(function (r) {\n            res.send({\n              id: (r as ReportBaseFields).id,\n              error: (r as { error: string }).error,\n            });\n            void scServer.exchange.transmitPublish('report', {\n              type: 'add',\n              data: r,\n            });\n          })\n          .catch(function (error) {\n            console.error(error);\n            res.status(500).send({});\n          });\n    }\n  });\n  return app;\n}\n\nexport default routes;\n"
  },
  {
    "path": "packages/redux-devtools-cli/src/store.ts",
    "content": "import { v4 as uuidV4 } from 'uuid';\nimport { pick } from 'lodash-es';\nimport { AGServer } from 'socketcluster-server';\nimport { Knex } from 'knex';\nimport connector from './db/connector.js';\n\nconst reports = 'remotedev_reports';\n// var payloads = 'remotedev_payloads';\nlet knex: Knex;\n\nconst baseFields = ['id', 'title', 'added'];\n\nfunction error(msg: string): Promise<{ error: string }> {\n  return new Promise(function (resolve) {\n    return resolve({ error: msg });\n  });\n}\n\ntype ReportType = 'STATE' | 'ACTION' | 'STATES' | 'ACTIONS';\n\nexport interface Report {\n  id: string;\n  type: ReportType | null;\n  title: string | null;\n  description: string | null;\n  action: string | null;\n  payload: string;\n  preloadedState: string | null;\n  screenshot: string | null;\n  userAgent: string | null;\n  version: string | null;\n  userId: string | null;\n  user: string | null;\n  meta: string | null;\n  exception: string | null;\n  instanceId: string | null;\n  added: string | null;\n  appId?: string | null;\n}\n\nexport interface ReportBaseFields {\n  id: string;\n  title: string | null;\n  added: string | null;\n}\n\nfunction list(query?: string, fields?: string[]): Promise<ReportBaseFields[]> {\n  const r = knex.select(fields || baseFields).from(reports);\n  if (query) return r.where(query);\n  return r;\n}\n\nfunction listAll(query?: string): Promise<Report[]> {\n  const r = knex.select().from(reports);\n  if (query) return r.where(query);\n  return r;\n}\n\nfunction get(id: string): Promise<Report | { error: string }> {\n  if (!id) return error('No id specified.');\n\n  return knex(reports).where('id', id).first();\n}\n\nexport interface AddData {\n  type: ReportType | null;\n  title: string | null;\n  description: string | null;\n  action: string | null;\n  payload: string;\n  preloadedState: string | null;\n  screenshot: string | null;\n  version: string | null;\n  userAgent: string | null;\n  userId: string | null;\n  user: { id: string } | string | null;\n  instanceId: string | null;\n  meta: string | null;\n  exception?: Error;\n  appId?: string | null;\n}\n\nfunction add(data: AddData): Promise<ReportBaseFields | { error: string }> {\n  if (!data.type || !data.payload) {\n    return error(\"Required parameters aren't specified.\");\n  }\n  if (data.type !== 'ACTIONS' && data.type !== 'STATE') {\n    return error('Type ' + data.type + ' is not supported yet.');\n  }\n\n  const reportId = uuidV4();\n  const report: Report = {\n    id: reportId,\n    type: data.type,\n    title:\n      data.title || (data.exception && data.exception.message) || data.action,\n    description: data.description,\n    action: data.action,\n    payload: data.payload,\n    preloadedState: data.preloadedState,\n    screenshot: data.screenshot,\n    version: data.version,\n    userAgent: data.userAgent,\n    user: data.user as string,\n    userId:\n      typeof data.user === 'object'\n        ? (data.user as { id: string }).id\n        : data.user,\n    instanceId: data.instanceId,\n    meta: data.meta,\n    exception: composeException(data.exception),\n    added: new Date().toISOString(),\n  };\n  if (data.appId) report.appId = data.appId; // TODO check if the id exists and we have access to link it\n  /*\n  var payload = {\n    id: uuid.v4(),\n    reportId: reportId,\n    state: data.payload\n  };\n  */\n\n  return knex\n    .insert(report)\n    .into(reports)\n    .then(function () {\n      return byBaseFields(report);\n    });\n}\n\nfunction byBaseFields(data: Report): ReportBaseFields {\n  return pick(data, baseFields) as ReportBaseFields;\n}\n\nexport interface Store {\n  list: (query?: string, fields?: string[]) => Promise<ReportBaseFields[]>;\n  listAll: (query?: string) => Promise<Report[]>;\n  get: (id: string) => Promise<Report | { error: string }>;\n  add: (data: AddData) => Promise<ReportBaseFields | { error: string }>;\n}\n\nfunction createStore(options: AGServer.AGServerOptions): Store {\n  knex = connector(options);\n\n  return {\n    list: list,\n    listAll: listAll,\n    get: get,\n    add: add,\n  };\n}\n\nfunction composeException(exception: Error | undefined) {\n  let message = '';\n\n  if (exception) {\n    message = 'Exception thrown: ';\n    if (exception.message) message += exception.message;\n    if (exception.stack) message += '\\n' + exception.stack;\n  }\n  return message;\n}\n\nexport default createStore;\n"
  },
  {
    "path": "packages/redux-devtools-cli/test/integration.spec.ts",
    "content": "import { jest } from '@jest/globals';\nimport childProcess from 'child_process';\nimport request from 'supertest';\nimport socketClusterClient from 'socketcluster-client';\n\njest.setTimeout(10000);\n\ndescribe('Server', function () {\n  let scServer: childProcess.ChildProcess;\n  beforeAll(async function () {\n    scServer = childProcess.fork(\n      import.meta.dirname + '/../bin/redux-devtools.js',\n    );\n    await new Promise((resolve) => setTimeout(resolve, 5000));\n  });\n\n  afterAll(function () {\n    if (scServer) {\n      scServer.kill();\n    }\n  });\n\n  describe('Express backend', function () {\n    it('loads main page', function () {\n      return new Promise<void>((done) => {\n        // eslint-disable-next-line @typescript-eslint/no-floating-promises\n        request('http://localhost:8000')\n          .get('/')\n          .expect('Content-Type', /text\\/html/)\n          .expect(200)\n          .then(function (res: { text: string }) {\n            expect(res.text).toMatch(/<title>Redux DevTools<\\/title>/);\n            done();\n          });\n      });\n    });\n\n    it('resolves an inexistent url', function () {\n      return new Promise((done) => {\n        // eslint-disable-next-line @typescript-eslint/no-floating-promises\n        request('http://localhost:8000/jreerfr/123')\n          .get('/')\n          .expect('Content-Type', /text\\/html/)\n          .expect(200, done);\n      });\n    });\n  });\n\n  describe('Realtime monitoring', function () {\n    let socket: socketClusterClient.AGClientSocket,\n      socket2: socketClusterClient.AGClientSocket,\n      channel;\n    beforeAll(function () {\n      socket = socketClusterClient.create({\n        hostname: 'localhost',\n        port: 8000,\n      });\n      socket.connect();\n      void (async () => {\n        for await (const data of socket.listener('error')) {\n          console.error('Socket1 error', data.error); // eslint-disable-line no-console\n        }\n      })();\n      socket2 = socketClusterClient.create({\n        hostname: 'localhost',\n        port: 8000,\n      });\n      socket2.connect();\n      void (async () => {\n        for await (const data of socket2.listener('error')) {\n          console.error('Socket2 error', data.error); // eslint-disable-line no-console\n        }\n      })();\n    });\n\n    afterAll(function () {\n      socket.disconnect();\n      socket2.disconnect();\n    });\n\n    it('should connect', async function () {\n      const data = await socket.listener('connect').once();\n      expect(data.id).toBeTruthy();\n    });\n\n    it('should login', async function () {\n      try {\n        const channelName = (await socket.invoke('login', 'master')) as string;\n        expect(channelName).toBe('respond');\n        channel = socket.subscribe(channelName);\n        expect(channel.SUBSCRIBED).toBe('subscribed');\n      } catch (error) {\n        console.log(error);\n      }\n    });\n\n    it('should send message', async function () {\n      const data = {\n        type: 'ACTION',\n        payload: {\n          todos: 'do some',\n        },\n        action: {\n          timestamp: 1483349708506,\n          action: {\n            type: 'ADD_TODO',\n            text: 'hggg',\n          },\n        },\n        instanceId: 'tAmA7H5fclyWhvizAAAi',\n        name: 'LoggerInstance',\n        id: 'tAmA7H5fclyWhvizAAAi',\n      };\n\n      try {\n        const channelName = (await socket.invoke('login', '')) as string;\n        expect(channelName).toBe('log');\n        const channel2 = socket2.subscribe(channelName);\n        expect(channel2.SUBSCRIBED).toBe('subscribed');\n        const message = await channel2.listener('subscribe').once();\n        expect(message).toEqual(data);\n      } catch (error) {\n        console.log(error);\n      }\n    });\n  });\n\n  describe('REST backend', function () {\n    let id: string;\n    const report = {\n      type: 'ACTIONS',\n      title: 'Test report',\n      description: 'Test body report',\n      action: 'SOME_FINAL_ACTION',\n      payload: '[{\"type\":\"ADD_TODO\",\"text\":\"hi\"},{\"type\":\"SOME_FINAL_ACTION\"}]',\n      preloadedState:\n        '{\"todos\":[{\"text\":\"Use Redux\",\"completed\":false,\"id\":0}]}',\n      userAgent:\n        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) ' +\n        'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36',\n    };\n    it('should add a report', async function () {\n      const res = await request('http://localhost:8000')\n        .post('/')\n        .send(report)\n        .set('Accept', 'application/json')\n        .expect('Content-Type', /application\\/json/)\n        .expect(200);\n      id = res.body.id;\n      expect(id).toBeTruthy();\n    });\n\n    it('should get the report', async function () {\n      const res = await request('http://localhost:8000')\n        .post('/')\n        .send({\n          op: 'get',\n          id: id,\n        })\n        .set('Accept', 'application/json')\n        .expect('Content-Type', /application\\/json/)\n        .expect(200);\n      expect(res.body).toMatchObject(report);\n    });\n\n    it('should list reports', async function () {\n      const res = await request('http://localhost:8000')\n        .post('/')\n        .send({\n          op: 'list',\n        })\n        .set('Accept', 'application/json')\n        .expect('Content-Type', /application\\/json/)\n        .expect(200);\n      expect(res.body).toHaveLength(1);\n      expect(res.body[0].id).toBe(id);\n      expect(res.body[0].title).toBe('Test report');\n      expect(res.body[0].added).toBeTruthy();\n    });\n  });\n\n  describe('GraphQL backend', function () {\n    it('should get the report', async function () {\n      const res = await request('http://localhost:8000')\n        .post('/graphql')\n        .send({\n          query: '{ reports { id, type, title } }',\n        })\n        .set('Accept', 'application/json')\n        .expect('Content-Type', /application\\/json/)\n        .expect(200);\n      const reports = res.body.data.reports;\n      expect(reports).toHaveLength(1);\n      expect(reports[0].id).toBeTruthy();\n      expect(reports[0].title).toBe('Test report');\n      expect(reports[0].type).toBe('ACTIONS');\n    });\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-cli/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.base.json\",\n  \"compilerOptions\": {\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"outDir\": \"dist\"\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-cli/tsconfig.test.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"jest\"]\n  },\n  \"include\": [\"src\", \"test\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-dock-monitor/CHANGELOG.md",
    "content": "# Change Log\n\n## 5.0.0\n\n### Major Changes\n\n- 12849a4: Convert monitors to ESM\n\n### Patch Changes\n\n- Updated dependencies [804d6bd]\n  - @redux-devtools/core@5.0.0\n\n## 4.1.1\n\n### Patch Changes\n\n- Updated dependencies [91f21b2]\n  - @redux-devtools/core@4.1.1\n\n## 4.1.0\n\n### Minor Changes\n\n- 6830118: Add React 19 to peer deps\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - react-dock@0.8.0\n  - @redux-devtools/core@4.1.0\n\n## 4.0.1\n\n### Patch Changes\n\n- Updated dependencies [bbb1a40]\n  - react-dock@0.7.0\n\n## 4.0.0\n\n### Major Changes\n\n- 5cfe3e5: Update min required React version to 16.8.4\n\n### Patch Changes\n\n- Updated dependencies [decc035]\n  - @redux-devtools/core@4.0.0\n\n## 3.1.0\n\n### Minor Changes\n\n- 6fc18ed7: Add new Redux version to peer dependencies\n\n### Patch Changes\n\n- 7f5bddbd: Widen peer dependencies\n\n## 3.0.2\n\n### Patch Changes\n\n- 65205f90: Replace Action<unknown> with Action<string>\n- Updated dependencies [65205f90]\n  - @redux-devtools/core@3.13.2\n\n## 3.0.1\n\n### Patch Changes\n\n- a55ba302: Fix peer dependencies on @redux-devtools/core\n- Updated dependencies [a55ba302]\n  - @redux-devtools/core@3.13.1\n\n## 3.0.0\n\n### Minor Changes\n\n- 8a7eae4: Add React 18 to peerDependencies range\n\n### Patch Changes\n\n- Updated dependencies [8a7eae4]\n  - react-dock@0.6.0\n  - @redux-devtools/core@3.13.0\n\n## 2.1.1\n\n### Patch Changes\n\n- Updated dependencies [4891bf6]\n  - @redux-devtools/core@3.12.0\n\n## 2.0.0\n\n- Adds ESM build (https://github.com/reduxjs/redux-devtools/pull/997) and switches the default export to a named export in order to ensure that the CommonJS output and the ESM output are [interchangeable](https://rollupjs.org/guide/en/#outputexports):\n\n```diff\n- import DockMonitor from '@redux-devtools/dock-monitor';\n+ import { DockMonitor } from '@redux-devtools/dock-monitor';\n```\n\n## [1.4.0](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/dock-monitor@1.3.0...@redux-devtools/dock-monitor@1.4.0) (2021-03-06)\n\n### Features\n\n- update peer dependencies to allow react@^17 ([#703](https://github.com/reduxjs/redux-devtools/issues/703)) ([2aaa9c1](https://github.com/reduxjs/redux-devtools/commit/2aaa9c10a383e3a7ab20b3ab14639781fd7bb2eb))\n\n## 1.3.0 (2021-03-06)\n\n### Features\n\n- **redux-devtools:** convert counter example to TypeScript ([#616](https://github.com/reduxjs/redux-devtools/issues/616)) ([f1e3f4f](https://github.com/reduxjs/redux-devtools/commit/f1e3f4f8340dea288de5229006acf9dc1ef1cccf))\n- **redux-devtools-dock-monitor:** convert to TypeScript ([#609](https://github.com/reduxjs/redux-devtools/issues/609)) ([b4ec7f8](https://github.com/reduxjs/redux-devtools/commit/b4ec7f86fc165683bd1e8b5ffc3f0690f670642c))\n- **redux-devtools-serialize:** convert to TypeScript ([#621](https://github.com/reduxjs/redux-devtools/issues/621)) ([d586f19](https://github.com/reduxjs/redux-devtools/commit/d586f1955a3648883107f8c981ee17eeb4c013a3))\n\n## [1.2.0](https://github.com/reduxjs/redux-devtools/compare/redux-devtools-dock-monitor@1.1.4...redux-devtools-dock-monitor@1.2.0) (2020-09-07)\n\n### Features\n\n- **redux-devtools:** convert counter example to TypeScript ([#616](https://github.com/reduxjs/redux-devtools/issues/616)) ([f1e3f4f](https://github.com/reduxjs/redux-devtools/commit/f1e3f4f8340dea288de5229006acf9dc1ef1cccf))\n- **redux-devtools-dock-monitor:** convert to TypeScript ([#609](https://github.com/reduxjs/redux-devtools/issues/609)) ([b4ec7f8](https://github.com/reduxjs/redux-devtools/commit/b4ec7f86fc165683bd1e8b5ffc3f0690f670642c))\n- **redux-devtools-serialize:** convert to TypeScript ([#621](https://github.com/reduxjs/redux-devtools/issues/621)) ([d586f19](https://github.com/reduxjs/redux-devtools/commit/d586f1955a3648883107f8c981ee17eeb4c013a3))\n\n## 1.1.4 (2020-08-14)\n\n**Note:** Version bump only for package redux-devtools-dock-monitor\n"
  },
  {
    "path": "packages/redux-devtools-dock-monitor/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Dan Abramov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/redux-devtools-dock-monitor/README.md",
    "content": "# Redux DevTools Dock Monitor\n\nA resizable and movable dock for [Redux DevTools](https://github.com/reduxjs/redux-devtools).  \nPowered by [React Dock](https://github.com/reduxjs/redux-devtools/tree/main/packages/react-dock).\n\n![](http://i.imgur.com/QbNzNW4.gif)\n\n### Installation\n\n```\nyarn add @redux-devtools/dock-monitor\n```\n\n### Usage\n\nWrap any other Redux DevTools monitor in `DockMonitor` to make it dockable to different screen edges.\nFor example, you can use it together with [`LogMonitor`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-log-monitor):\n\n##### `containers/DevTools.js`\n\n```js\nimport React from 'react';\nimport { createDevTools } from '@redux-devtools/core';\nimport { LogMonitor } from '@redux-devtools/log-monitor';\nimport { SliderMonitor } from '@redux-devtools/slider-monitor';\nimport { DockMonitor } from '@redux-devtools/dock-monitor';\n\nexport default createDevTools(\n  <DockMonitor\n    toggleVisibilityKey=\"ctrl-h\"\n    changePositionKey=\"ctrl-q\"\n    changeMonitorKey=\"ctrl-m\"\n  >\n    <LogMonitor />\n    <SliderMonitor />\n  </DockMonitor>,\n);\n```\n\n[Read how to start using Redux DevTools.](https://github.com/reduxjs/redux-devtools)\n\n#### Multiple Monitors\n\nYou can put more than one monitor inside `<DockMonitor>`. There will still be a single dock, but you will be able to switch between different monitors by pressing a key specified as `changeMonitorKey` prop.\n\n### Props\n\n| Name                  | Description                                                                                                                                                                                                              |\n| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `children`            | Any valid Redux DevTools monitor. Required.                                                                                                                                                                              |\n| `toggleVisibilityKey` | A key or a key combination that toggles the dock visibility. Must be recognizable by [parse-key](https://github.com/thlorenz/parse-key) (for example, `'ctrl-h'`). Required.                                             |\n| `changePositionKey`   | A key or a key combination that toggles the dock position. Must be recognizable by [parse-key](https://github.com/thlorenz/parse-key) (for example, `'ctrl-w'`). Required.                                               |\n| `changeMonitorKey`    | A key or a key combination that switches the currently visible monitor. Must be recognizable by [parse-key](https://github.com/thlorenz/parse-key) (for example, `'ctrl-m'`). Required if you use more than one monitor. |\n| `fluid`               | When `true`, the dock size is a fraction of the window size, fixed otherwise. Optional. By default set to `true`.                                                                                                        |\n| `defaultSize`         | Size of the dock. When `fluid` is `true`, a float (`0.5` means half the window size). When `fluid` is `false`, a width in pixels. Optional. By default set to `0.3` (3/10th of the window size).                         |\n| `defaultPosition`     | Where the dock appears on the screen. Valid values: `'left'`, `'top'`, `'right'`, `'bottom'`. Optional. By default set to `'right'`.                                                                                     |\n| `defaultIsVisible`    | Defines whether dock should be open by default. A value of `true` means that it's open when the page/app loads.                                                                                                          |\n\nThe current size and the position are persisted between sessions with `persistState()` enhancer from Redux DevTools.\n\n### License\n\nMIT\n"
  },
  {
    "path": "packages/redux-devtools-dock-monitor/eslint.config.mjs",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTsReact from '../../eslint.ts.react.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTsReact(import.meta.dirname),\n  {\n    ignores: ['lib'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-dock-monitor/package.json",
    "content": "{\n  \"name\": \"@redux-devtools/dock-monitor\",\n  \"version\": \"5.0.0\",\n  \"description\": \"A resizable and movable dock for Redux DevTools monitors\",\n  \"keywords\": [\n    \"redux\",\n    \"devtools\",\n    \"flux\",\n    \"react\",\n    \"hot reloading\",\n    \"time travel\",\n    \"live edit\"\n  ],\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-dock-monitor\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Dan Abramov <dan.abramov@me.com> (http://github.com/gaearon)\",\n  \"files\": [\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": \"./lib/index.js\",\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run type-check && pnpm run lint\"\n  },\n  \"dependencies\": {\n    \"parse-key\": \"^0.2.1\",\n    \"react-dock\": \"workspace:^\"\n  },\n  \"devDependencies\": {\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@types/parse-key\": \"^0.2.2\",\n    \"@types/react\": \"^19.2.14\",\n    \"react\": \"^19.2.4\",\n    \"redux\": \"^5.0.1\",\n    \"rimraf\": \"^6.1.3\",\n    \"typescript\": \"~5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@types/react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react\": \"^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"redux\": \"^3.4.0 || ^4.0.0 || ^5.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-dock-monitor/src/DockMonitor.tsx",
    "content": "import React, { cloneElement, Children, Component } from 'react';\nimport { Dock } from 'react-dock';\nimport { Action, Dispatch } from 'redux';\nimport { LiftedState, Monitor } from '@redux-devtools/core';\nimport {\n  toggleVisibility,\n  changeMonitor,\n  changePosition,\n  changeSize,\n  DockMonitorAction,\n} from './actions.js';\nimport reducer, { DockMonitorState } from './reducers.js';\nimport parseKey from 'parse-key';\n\ninterface KeyObject {\n  name: string;\n  ctrl: boolean;\n  meta: boolean;\n  shift: boolean;\n  alt: boolean;\n  sequence: string;\n}\n\ninterface ExternalProps<S, A extends Action<string>> {\n  defaultPosition: 'left' | 'top' | 'right' | 'bottom';\n  defaultIsVisible: boolean;\n  defaultSize: number;\n  toggleVisibilityKey: string;\n  changePositionKey: string;\n  changeMonitorKey?: string;\n  fluid: boolean;\n\n  dispatch: Dispatch<DockMonitorAction>;\n\n  children:\n    | Monitor<S, A, LiftedState<S, A, unknown>, unknown, Action<string>>\n    | Monitor<S, A, LiftedState<S, A, unknown>, unknown, Action<string>>[];\n}\n\ninterface DefaultProps {\n  defaultIsVisible: boolean;\n  defaultPosition: 'left' | 'top' | 'right' | 'bottom';\n  defaultSize: number;\n  fluid: boolean;\n}\n\nexport interface DockMonitorProps<\n  S,\n  A extends Action<string>,\n> extends LiftedState<S, A, DockMonitorState> {\n  defaultPosition: 'left' | 'top' | 'right' | 'bottom';\n  defaultIsVisible: boolean;\n  defaultSize: number;\n  toggleVisibilityKey: string;\n  changePositionKey: string;\n  changeMonitorKey?: string;\n  fluid: boolean;\n\n  dispatch: Dispatch<DockMonitorAction>;\n\n  children:\n    | Monitor<S, A, LiftedState<S, A, unknown>, unknown, Action<string>>\n    | Monitor<S, A, LiftedState<S, A, unknown>, unknown, Action<string>>[];\n}\n\nclass DockMonitor<S, A extends Action<string>> extends Component<\n  DockMonitorProps<S, A>\n> {\n  static update = reducer;\n\n  static defaultProps: DefaultProps = {\n    defaultIsVisible: true,\n    defaultPosition: 'right',\n    defaultSize: 0.3,\n    fluid: true,\n  };\n\n  constructor(props: DockMonitorProps<S, A>) {\n    super(props);\n\n    const childrenCount = Children.count(props.children);\n    if (childrenCount === 0) {\n      // eslint-disable-next-line no-console\n      console.error(\n        '<DockMonitor> requires at least one monitor inside. ' +\n          'Why don’t you try <LogMonitor>? You can get it at ' +\n          'https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-log-monitor.',\n      );\n    } else if (childrenCount > 1 && !props.changeMonitorKey) {\n      // eslint-disable-next-line no-console\n      console.error(\n        'You specified multiple monitors inside <DockMonitor> ' +\n          'but did not provide `changeMonitorKey` prop to change them. ' +\n          'Try specifying <DockMonitor changeMonitorKey=\"ctrl-m\" /> ' +\n          'and then press Ctrl-M.',\n      );\n    }\n  }\n\n  componentDidMount() {\n    window.addEventListener('keydown', this.handleKeyDown);\n  }\n\n  componentWillUnmount() {\n    window.removeEventListener('keydown', this.handleKeyDown);\n  }\n\n  matchesKey(key: KeyObject | undefined, event: KeyboardEvent) {\n    if (!key) {\n      return false;\n    }\n\n    const charCode = event.keyCode || event.which;\n    const char = String.fromCharCode(charCode);\n    return (\n      key.name.toUpperCase() === char.toUpperCase() &&\n      key.alt === event.altKey &&\n      key.ctrl === event.ctrlKey &&\n      key.meta === event.metaKey &&\n      key.shift === event.shiftKey\n    );\n  }\n\n  handleKeyDown = (e: KeyboardEvent) => {\n    // Ignore regular keys when focused on a field\n    // and no modifiers are active.\n    if (\n      !e.ctrlKey &&\n      !e.metaKey &&\n      !e.altKey &&\n      ((e.target! as { tagName?: string }).tagName === 'INPUT' ||\n        (e.target! as { tagName?: string }).tagName === 'SELECT' ||\n        (e.target! as { tagName?: string }).tagName === 'TEXTAREA' ||\n        (e.target! as { isContentEditable?: boolean }).isContentEditable)\n    ) {\n      return;\n    }\n\n    const visibilityKey = parseKey(this.props.toggleVisibilityKey);\n    const positionKey = parseKey(this.props.changePositionKey);\n\n    let monitorKey;\n    if (this.props.changeMonitorKey) {\n      monitorKey = parseKey(this.props.changeMonitorKey);\n    }\n\n    if (this.matchesKey(visibilityKey, e)) {\n      e.preventDefault();\n      this.props.dispatch(toggleVisibility());\n    } else if (this.matchesKey(positionKey, e)) {\n      e.preventDefault();\n      this.props.dispatch(changePosition());\n    } else if (this.matchesKey(monitorKey, e)) {\n      e.preventDefault();\n      this.props.dispatch(changeMonitor());\n    }\n  };\n\n  handleSizeChange = (requestedSize: number) => {\n    this.props.dispatch(changeSize(requestedSize));\n  };\n\n  renderChild(\n    child: Monitor<S, A, LiftedState<S, A, unknown>, unknown, Action<string>>,\n    index: number,\n    otherProps: Omit<\n      DockMonitorProps<S, A>,\n      'monitorState' | 'children' | 'fluid'\n    >,\n  ) {\n    const { monitorState } = this.props;\n    const { childMonitorIndex, childMonitorStates } = monitorState;\n\n    if (index !== childMonitorIndex) {\n      return null;\n    }\n\n    return cloneElement(child, {\n      monitorState: childMonitorStates[index],\n      ...otherProps,\n    });\n  }\n\n  render() {\n    const { monitorState, children, fluid, ...rest } = this.props;\n    const { position, isVisible, size } = monitorState;\n\n    return (\n      <Dock\n        position={position}\n        isVisible={isVisible}\n        size={size}\n        fluid={fluid}\n        onSizeChange={this.handleSizeChange}\n        dimMode=\"none\"\n      >\n        {Children.map(children, (child, index) =>\n          this.renderChild(child, index, rest),\n        )}\n      </Dock>\n    );\n  }\n}\n\nexport default DockMonitor as unknown as React.ComponentType<\n  ExternalProps<unknown, Action<string>>\n> & {\n  update(\n    monitorProps: ExternalProps<unknown, Action<string>>,\n    state: DockMonitorState | undefined,\n    action: DockMonitorAction,\n  ): DockMonitorState;\n  defaultProps: DefaultProps;\n};\n"
  },
  {
    "path": "packages/redux-devtools-dock-monitor/src/actions.ts",
    "content": "export const TOGGLE_VISIBILITY =\n  '@@redux-devtools-log-monitor/TOGGLE_VISIBILITY';\ninterface ToggleVisibilityAction {\n  type: typeof TOGGLE_VISIBILITY;\n}\nexport function toggleVisibility(): ToggleVisibilityAction {\n  return { type: TOGGLE_VISIBILITY };\n}\n\nexport const CHANGE_POSITION = '@@redux-devtools-log-monitor/CHANGE_POSITION';\ninterface ChangePositionAction {\n  type: typeof CHANGE_POSITION;\n}\nexport function changePosition(): ChangePositionAction {\n  return { type: CHANGE_POSITION };\n}\n\nexport const CHANGE_SIZE = '@@redux-devtools-log-monitor/CHANGE_SIZE';\ninterface ChangeSizeAction {\n  type: typeof CHANGE_SIZE;\n  size: number;\n}\nexport function changeSize(size: number): ChangeSizeAction {\n  return { type: CHANGE_SIZE, size: size };\n}\n\nexport const CHANGE_MONITOR = '@@redux-devtools-log-monitor/CHANGE_MONITOR';\ninterface ChangeMonitorAction {\n  type: typeof CHANGE_MONITOR;\n}\nexport function changeMonitor(): ChangeMonitorAction {\n  return { type: CHANGE_MONITOR };\n}\n\nexport type DockMonitorAction =\n  | ToggleVisibilityAction\n  | ChangePositionAction\n  | ChangeSizeAction\n  | ChangeMonitorAction;\n"
  },
  {
    "path": "packages/redux-devtools-dock-monitor/src/constants.ts",
    "content": "export const POSITIONS = ['left', 'top', 'right', 'bottom'] as const;\n"
  },
  {
    "path": "packages/redux-devtools-dock-monitor/src/index.ts",
    "content": "export { default as DockMonitor } from './DockMonitor.js';\n"
  },
  {
    "path": "packages/redux-devtools-dock-monitor/src/reducers.ts",
    "content": "import { Children } from 'react';\nimport { Action } from 'redux';\nimport {\n  CHANGE_MONITOR,\n  CHANGE_POSITION,\n  CHANGE_SIZE,\n  DockMonitorAction,\n  TOGGLE_VISIBILITY,\n} from './actions.js';\nimport { POSITIONS } from './constants.js';\nimport { DockMonitorProps } from './DockMonitor.js';\n\nexport interface DockMonitorState {\n  position: 'left' | 'top' | 'right' | 'bottom';\n  size: number;\n  isVisible: boolean;\n  childMonitorStates: unknown[];\n  childMonitorIndex: number;\n}\n\nfunction position<S, A extends Action<string>>(\n  props: DockMonitorProps<S, A>,\n  state = props.defaultPosition,\n  action: DockMonitorAction,\n) {\n  return action.type === CHANGE_POSITION\n    ? POSITIONS[(POSITIONS.indexOf(state) + 1) % POSITIONS.length]\n    : state;\n}\n\nfunction size<S, A extends Action<string>>(\n  props: DockMonitorProps<S, A>,\n  state = props.defaultSize,\n  action: DockMonitorAction,\n) {\n  return action.type === CHANGE_SIZE ? action.size : state;\n}\n\nfunction isVisible<S, A extends Action<string>>(\n  props: DockMonitorProps<S, A>,\n  state = props.defaultIsVisible,\n  action: DockMonitorAction,\n) {\n  return action.type === TOGGLE_VISIBILITY ? !state : state;\n}\n\nfunction childMonitorStates<S, A extends Action<string>>(\n  props: DockMonitorProps<S, A>,\n  state: unknown[] = [],\n  action: DockMonitorAction,\n) {\n  return Children.map(props.children, (child, index) =>\n    child.type.update(child.props, state[index], action),\n  );\n}\n\nfunction childMonitorIndex<S, A extends Action<string>>(\n  props: DockMonitorProps<S, A>,\n  state = 0,\n  action: DockMonitorAction,\n) {\n  switch (action.type) {\n    case CHANGE_MONITOR:\n      return (state + 1) % Children.count(props.children);\n    default:\n      return state;\n  }\n}\n\nexport default function reducer<S, A extends Action<string>>(\n  props: DockMonitorProps<S, A>,\n  state: Partial<DockMonitorState> = {},\n  action: DockMonitorAction,\n): DockMonitorState {\n  if (!state.childMonitorStates) {\n    Children.forEach(props.children, (child, index) => {\n      if (typeof child.type.update !== 'function') {\n        // eslint-disable-next-line no-console\n        console.error(\n          `Child of <DockMonitor> with the index ${index} ` +\n            `(${\n              child.type.displayName ||\n              child.type.name ||\n              (child.type as unknown as string)\n            }) ` +\n            'does not appear to be a valid Redux DevTools monitor.',\n        );\n      }\n    });\n  }\n\n  return {\n    position: position(props, state.position, action),\n    isVisible: isVisible(props, state.isVisible, action),\n    size: size(props, state.size, action),\n    childMonitorIndex: childMonitorIndex(\n      props,\n      state.childMonitorIndex,\n      action,\n    ),\n    childMonitorStates: childMonitorStates(\n      props,\n      state.childMonitorStates,\n      action,\n    ),\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-dock-monitor/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-extension/CHANGELOG.md",
    "content": "# Change Log\n\n## 4.0.0\n\n### Major Changes\n\n- 6481386: Convert remaining packages to ESM\n\n## 3.3.0\n\n### Minor Changes\n\n- a3f86a42: Add Redux 5 to peerDependency range of extension package\n\n## 3.2.6\n\n### Patch Changes\n\n- 65205f90: Replace Action<unknown> with Action<string>\n\n## 3.2.5\n\n### Patch Changes\n\n- a0716740: Fix types for other exports from `@redux-devtools/extension`.\n\n## 3.2.4\n\n### Patch Changes\n\n- 07456db4: Propagate store enhancer generic type when using composeWithDevTools\n\n## 3.2.3\n\n### Patch Changes\n\n- 6cf1865f: Fix type for serialize option\n\n## 3.2.2\n\n### Patch Changes\n\n- 2ec10f0: v3.0.0 had an unintentional breaking change of changing the location of the secondary entrypoints. These secondary exports are now exported from the main entrypoint (https://github.com/reduxjs/redux-devtools/pull/1075) and should be imported like so:\n\n  ```diff\n  - import { composeWithDevTools, devToolsEnhancer } from 'redux-devtools-extension/developmentOnly';\n  - import { composeWithDevTools, devToolsEnhancer } from 'redux-devtools-extension/logOnly';\n  - import { composeWithDevTools, devToolsEnhancer } from 'redux-devtools-extension/logOnlyInProduction';\n  + import {\n  +   composeWithDevToolsDevelopmentOnly,\n  +   devToolsEnhancerDevelopmentOnly,\n  +   composeWithDevToolsLogOnly,\n  +   devToolsEnhancerLogOnly,\n  +   composeWithDevToolsLogOnlyInProduction,\n  +   devToolsEnhancerLogOnlyInProduction,\n  + } from '@redux-devtools/extension';\n  ```\n\n## 3.2.1\n\n### Patch Changes\n\n- a25551f: Fix files included in publish\n\n## 3.0.0\n\n- **BREAKING** Rename `redux-devtools-extension` package to `@redux-devtools/extension` (https://github.com/reduxjs/redux-devtools/pull/948).\n- **BREAKING** The secondary exports are now exported from the main entrypoint (https://github.com/reduxjs/redux-devtools/pull/1075) (NOTE: this will only work in `@redux-devtools/extension@3.2.2` or later):\n\n```diff\n- import { composeWithDevTools, devToolsEnhancer } from 'redux-devtools-extension/developmentOnly';\n- import { composeWithDevTools, devToolsEnhancer } from 'redux-devtools-extension/logOnly';\n- import { composeWithDevTools, devToolsEnhancer } from 'redux-devtools-extension/logOnlyInProduction';\n+ import {\n+   composeWithDevToolsDevelopmentOnly,\n+   devToolsEnhancerDevelopmentOnly,\n+   composeWithDevToolsLogOnly,\n+   devToolsEnhancerLogOnly,\n+   composeWithDevToolsLogOnlyInProduction,\n+   devToolsEnhancerLogOnlyInProduction,\n+ } from '@redux-devtools/extension';\n```\n\n- Deprecate `actionsBlacklist` and `actionsWhitelist` in favor of `actionsDenylist` and `actionsAllowlist` (https://github.com/reduxjs/redux-devtools/pull/851).\n\n## 2.13.9 (2021-03-06)\n\n**Note:** Version bump only for package redux-devtools-extension\n"
  },
  {
    "path": "packages/redux-devtools-extension/README.md",
    "content": "# Redux DevTools Extension's helper\n\n[![Join the chat at https://gitter.im/zalmoxisus/redux-devtools-extension](https://badges.gitter.im/zalmoxisus/redux-devtools-extension.svg)](https://gitter.im/zalmoxisus/redux-devtools-extension?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)\n\n## Usage\n\nInstall:\n\n```\nyarn add @redux-devtools/extension\n```\n\nand use like that:\n\n```js\nimport { createStore, applyMiddleware } from 'redux';\nimport { composeWithDevTools } from '@redux-devtools/extension';\n\nconst store = createStore(\n  reducer,\n  composeWithDevTools(\n    applyMiddleware(...middleware),\n    // other store enhancers if any\n  ),\n);\n```\n\nor if needed to apply [extension’s options](https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/API/Arguments.md):\n\n```js\nimport { createStore, applyMiddleware } from 'redux';\nimport { composeWithDevTools } from '@redux-devtools/extension';\n\nconst composeEnhancers = composeWithDevTools({\n  // Specify here name, actionsDenylist, actionsCreators and other options\n});\nconst store = createStore(\n  reducer,\n  composeEnhancers(\n    applyMiddleware(...middleware),\n    // other store enhancers if any\n  ),\n);\n```\n\nThere are just a [few lines of code](https://github.com/reduxjs/redux-devtools/blob/main/packages/redux-devtools-extension/src/index.ts). If you don’t want to allow the extension in production, just use `composeWithDevToolsDevelopmentOnly` instead of `composeWithDevTools`.\n\n## License\n\nMIT\n"
  },
  {
    "path": "packages/redux-devtools-extension/eslint.config.mjs",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTs from '../../eslint.ts.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTs(import.meta.dirname),\n  {\n    ignores: ['lib'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-extension/package.json",
    "content": "{\n  \"name\": \"@redux-devtools/extension\",\n  \"version\": \"4.0.0\",\n  \"description\": \"Wrappers for Redux DevTools Extension.\",\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-extension\",\n  \"license\": \"MIT\",\n  \"author\": \"Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)\",\n  \"files\": [\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": \"./lib/index.js\",\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run type-check && pnpm run lint\"\n  },\n  \"devDependencies\": {\n    \"redux\": \"^5.0.1\",\n    \"rimraf\": \"^6.1.3\",\n    \"typescript\": \"~5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"redux\": \"^3.1.0 || ^4.0.0 || ^5.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-extension/src/developmentOnly.ts",
    "content": "import { compose } from 'redux';\nimport type { StoreEnhancer } from 'redux';\nimport type {\n  Config,\n  EnhancerOptions,\n  InferComposedStoreExt,\n  ReduxDevtoolsExtensionCompose,\n} from './index.js';\n\ndeclare const process: {\n  env: {\n    NODE_ENV: string;\n  };\n};\n\nfunction extensionComposeStub(\n  config: Config,\n): <StoreEnhancers extends readonly StoreEnhancer[]>(\n  ...funcs: StoreEnhancers\n) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;\nfunction extensionComposeStub<StoreEnhancers extends readonly StoreEnhancer[]>(\n  ...funcs: StoreEnhancers\n): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;\nfunction extensionComposeStub(...funcs: [Config] | StoreEnhancer[]) {\n  if (funcs.length === 0) return undefined;\n  if (typeof funcs[0] === 'object') return compose;\n  return compose(...(funcs as StoreEnhancer[]));\n}\n\nexport const composeWithDevTools: ReduxDevtoolsExtensionCompose =\n  process.env.NODE_ENV !== 'production' &&\n  typeof window !== 'undefined' &&\n  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__\n    ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__\n    : extensionComposeStub;\n\nexport const devToolsEnhancer: (options?: EnhancerOptions) => StoreEnhancer =\n  process.env.NODE_ENV !== 'production' &&\n  typeof window !== 'undefined' &&\n  window.__REDUX_DEVTOOLS_EXTENSION__\n    ? window.__REDUX_DEVTOOLS_EXTENSION__\n    : function () {\n        return function (noop) {\n          return noop;\n        };\n      };\n"
  },
  {
    "path": "packages/redux-devtools-extension/src/index.ts",
    "content": "import { compose } from 'redux';\nimport type { Action, ActionCreator, StoreEnhancer } from 'redux';\n\nexport interface EnhancerOptions {\n  /**\n   * the instance name to be showed on the monitor page. Default value is `document.title`.\n   * If not specified and there's no document title, it will consist of `tabId` and `instanceId`.\n   */\n  name?: string;\n  /**\n   * action creators functions to be available in the Dispatcher.\n   */\n  actionCreators?: ActionCreator<any>[] | { [key: string]: ActionCreator<any> };\n  /**\n   * if more than one action is dispatched in the indicated interval, all new actions will be collected and sent at once.\n   * It is the joint between performance and speed. When set to `0`, all actions will be sent instantly.\n   * Set it to a higher value when experiencing perf issues (also `maxAge` to a lower value).\n   *\n   * @default 500 ms.\n   */\n  latency?: number;\n  /**\n   * (> 1) - maximum allowed actions to be stored in the history tree. The oldest actions are removed once maxAge is reached. It's critical for performance.\n   *\n   * @default 50\n   */\n  maxAge?: number;\n  /**\n   * Customizes how actions and state are serialized and deserialized. Can be a boolean or object. If given a boolean, the behavior is the same as if you\n   * were to pass an object and specify `options` as a boolean. Giving an object allows fine-grained customization using the `replacer` and `reviver`\n   * functions.\n   */\n  serialize?:\n    | boolean\n    | {\n        /**\n         * - `undefined` - will use regular `JSON.stringify` to send data (it's the fast mode).\n         * - `false` - will handle also circular references.\n         * - `true` - will handle also date, regex, undefined, error objects, symbols, maps, sets and functions.\n         * - object, which contains `date`, `regex`, `undefined`, `error`, `symbol`, `map`, `set` and `function` keys.\n         *   For each of them you can indicate if to include (by setting as `true`).\n         *   For `function` key you can also specify a custom function which handles serialization.\n         *   See [`jsan`](https://github.com/kolodny/jsan) for more details.\n         */\n        options?:\n          | undefined\n          | boolean\n          | {\n              date?: true;\n              regex?: true;\n              undefined?: true;\n              error?: true;\n              symbol?: true;\n              map?: true;\n              set?: true;\n              function?: true | ((fn: (...args: any[]) => any) => string);\n            };\n        /**\n         * [JSON replacer function](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The_replacer_parameter) used for both actions and states stringify.\n         * In addition, you can specify a data type by adding a [`__serializedType__`](https://github.com/zalmoxisus/remotedev-serialize/blob/master/helpers/index.js#L4)\n         * key. So you can deserialize it back while importing or persisting data.\n         * Moreover, it will also [show a nice preview showing the provided custom type](https://cloud.githubusercontent.com/assets/7957859/21814330/a17d556a-d761-11e6-85ef-159dd12f36c5.png):\n         */\n        replacer?: (key: string, value: unknown) => any;\n        /**\n         * [JSON `reviver` function](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Using_the_reviver_parameter)\n         * used for parsing the imported actions and states. See [`remotedev-serialize`](https://github.com/zalmoxisus/remotedev-serialize/blob/master/immutable/serialize.js#L8-L41)\n         * as an example on how to serialize special data types and get them back.\n         */\n        reviver?: (key: string, value: unknown) => any;\n        /**\n         * Automatically serialize/deserialize immutablejs via [remotedev-serialize](https://github.com/zalmoxisus/remotedev-serialize).\n         * Just pass the Immutable library. It will support all ImmutableJS structures. You can even export them into a file and get them back.\n         * The only exception is `Record` class, for which you should pass this in addition the references to your classes in `refs`.\n         */\n        immutable?: unknown;\n        /**\n         * ImmutableJS `Record` classes used to make possible restore its instances back when importing, persisting...\n         */\n        refs?: (new (data: any) => unknown)[];\n      };\n  /**\n   * function which takes `action` object and id number as arguments, and should return `action` object back.\n   */\n  actionSanitizer?: <A extends Action>(action: A, id: number) => A;\n  /**\n   * function which takes `state` object and index as arguments, and should return `state` object back.\n   */\n  stateSanitizer?: <S>(state: S, index: number) => S;\n  /**\n   * *string or array of strings as regex* - actions types to be hidden / shown in the monitors (while passed to the reducers).\n   * If `actionsWhitelist` specified, `actionsBlacklist` is ignored.\n   * @deprecated Use actionsDenylist instead.\n   */\n  actionsBlacklist?: string | string[];\n  /**\n   * *string or array of strings as regex* - actions types to be hidden / shown in the monitors (while passed to the reducers).\n   * If `actionsWhitelist` specified, `actionsBlacklist` is ignored.\n   * @deprecated Use actionsAllowlist instead.\n   */\n  actionsWhitelist?: string | string[];\n  /**\n   * *string or array of strings as regex* - actions types to be hidden / shown in the monitors (while passed to the reducers).\n   * If `actionsAllowlist` specified, `actionsDenylist` is ignored.\n   */\n  actionsDenylist?: string | string[];\n  /**\n   * *string or array of strings as regex* - actions types to be hidden / shown in the monitors (while passed to the reducers).\n   * If `actionsAllowlist` specified, `actionsDenylist` is ignored.\n   */\n  actionsAllowlist?: string | string[];\n  /**\n   * called for every action before sending, takes `state` and `action` object, and returns `true` in case it allows sending the current data to the monitor.\n   * Use it as a more advanced version of `actionsDenylist`/`actionsAllowlist` parameters.\n   */\n  predicate?: <S, A extends Action>(state: S, action: A) => boolean;\n  /**\n   * if specified as `false`, it will not record the changes till clicking on `Start recording` button.\n   * Available only for Redux enhancer, for others use `autoPause`.\n   *\n   * @default true\n   */\n  shouldRecordChanges?: boolean;\n  /**\n   * if specified, whenever clicking on `Pause recording` button and there are actions in the history log, will add this action type.\n   * If not specified, will commit when paused. Available only for Redux enhancer.\n   *\n   * @default \"@@PAUSED\"\"\n   */\n  pauseActionType?: string;\n  /**\n   * auto pauses when the extension’s window is not opened, and so has zero impact on your app when not in use.\n   * Not available for Redux enhancer (as it already does it but storing the data to be sent).\n   *\n   * @default false\n   */\n  autoPause?: boolean;\n  /**\n   * if specified as `true`, it will not allow any non-monitor actions to be dispatched till clicking on `Unlock changes` button.\n   * Available only for Redux enhancer.\n   *\n   * @default false\n   */\n  shouldStartLocked?: boolean;\n  /**\n   * if set to `false`, will not recompute the states on hot reloading (or on replacing the reducers). Available only for Redux enhancer.\n   *\n   * @default true\n   */\n  shouldHotReload?: boolean;\n  /**\n   * if specified as `true`, whenever there's an exception in reducers, the monitors will show the error message, and next actions will not be dispatched.\n   *\n   * @default false\n   */\n  shouldCatchErrors?: boolean;\n  /**\n   * If you want to restrict the extension, specify the features you allow.\n   * If not specified, all of the features are enabled. When set as an object, only those included as `true` will be allowed.\n   * Note that except `true`/`false`, `import` and `export` can be set as `custom` (which is by default for Redux enhancer), meaning that the importing/exporting occurs on the client side.\n   * Otherwise, you'll get/set the data right from the monitor part.\n   */\n  features?: {\n    /**\n     * start/pause recording of dispatched actions\n     */\n    pause?: boolean;\n    /**\n     * lock/unlock dispatching actions and side effects\n     */\n    lock?: boolean;\n    /**\n     * persist states on page reloading\n     */\n    persist?: boolean;\n    /**\n     * export history of actions in a file\n     */\n    export?: boolean | 'custom';\n    /**\n     * import history of actions from a file\n     */\n    import?: boolean | 'custom';\n    /**\n     * jump back and forth (time travelling)\n     */\n    jump?: boolean;\n    /**\n     * skip (cancel) actions\n     */\n    skip?: boolean;\n    /**\n     * drag and drop actions in the history list\n     */\n    reorder?: boolean;\n    /**\n     * dispatch custom actions or action creators\n     */\n    dispatch?: boolean;\n    /**\n     * generate tests for the selected actions\n     */\n    test?: boolean;\n  };\n  /**\n   * Set to true or a stacktrace-returning function to record call stack traces for dispatched actions.\n   * Defaults to false.\n   */\n  trace?: boolean | (<A extends Action>(action: A) => string);\n  /**\n   * The maximum number of stack trace entries to record per action. Defaults to 10.\n   */\n  traceLimit?: number;\n}\n\nexport interface Config extends EnhancerOptions {\n  type?: string;\n}\n\ninterface ConnectResponse {\n  init: (state: unknown) => void;\n  send: (action: Action<string>, state: unknown) => void;\n}\n\ninterface ReduxDevtoolsExtension {\n  (config?: Config): StoreEnhancer;\n  connect: (preConfig: Config) => ConnectResponse;\n}\n\nexport type InferComposedStoreExt<StoreEnhancers> = StoreEnhancers extends [\n  infer HeadStoreEnhancer,\n  ...infer RestStoreEnhancers,\n]\n  ? HeadStoreEnhancer extends StoreEnhancer<infer StoreExt>\n    ? StoreExt & InferComposedStoreExt<RestStoreEnhancers>\n    : never\n  : // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n    {};\n\nexport interface ReduxDevtoolsExtensionCompose {\n  (\n    config: Config,\n  ): <StoreEnhancers extends readonly StoreEnhancer[]>(\n    ...funcs: StoreEnhancers\n  ) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;\n  <StoreEnhancers extends readonly StoreEnhancer[]>(\n    ...funcs: StoreEnhancers\n  ): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;\n}\n\ndeclare global {\n  interface Window {\n    __REDUX_DEVTOOLS_EXTENSION__?: ReduxDevtoolsExtension;\n    __REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: ReduxDevtoolsExtensionCompose;\n  }\n}\n\nfunction extensionComposeStub(\n  config: Config,\n): <StoreEnhancers extends readonly StoreEnhancer[]>(\n  ...funcs: StoreEnhancers\n) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;\nfunction extensionComposeStub<StoreEnhancers extends readonly StoreEnhancer[]>(\n  ...funcs: StoreEnhancers\n): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;\nfunction extensionComposeStub(...funcs: [Config] | StoreEnhancer[]) {\n  if (funcs.length === 0) return undefined;\n  if (typeof funcs[0] === 'object') return compose;\n  return compose(...(funcs as StoreEnhancer[]));\n}\n\nexport const composeWithDevTools: ReduxDevtoolsExtensionCompose =\n  typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__\n    ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__\n    : extensionComposeStub;\n\nexport const devToolsEnhancer: (options?: EnhancerOptions) => StoreEnhancer =\n  typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__\n    ? window.__REDUX_DEVTOOLS_EXTENSION__\n    : function () {\n        return function (noop) {\n          return noop;\n        };\n      };\n\nexport {\n  composeWithDevTools as composeWithDevToolsDevelopmentOnly,\n  devToolsEnhancer as devToolsEnhancerDevelopmentOnly,\n} from './developmentOnly.js';\nexport {\n  composeWithDevTools as composeWithDevToolsLogOnly,\n  devToolsEnhancer as devToolsEnhancerLogOnly,\n} from './logOnly.js';\nexport {\n  composeWithDevTools as composeWithDevToolsLogOnlyInProduction,\n  devToolsEnhancer as devToolsEnhancerLogOnlyInProduction,\n} from './logOnlyInProduction.js';\n"
  },
  {
    "path": "packages/redux-devtools-extension/src/logOnly.ts",
    "content": "import { compose } from 'redux';\nimport type { Action, Dispatch, Reducer, StoreEnhancer } from 'redux';\nimport type {\n  Config,\n  EnhancerOptions,\n  InferComposedStoreExt,\n} from './index.js';\n\nfunction enhancer(options?: EnhancerOptions): StoreEnhancer {\n  const config: Config = options || {};\n  config.features = { pause: true, export: true, test: true };\n  config.type = 'redux';\n  if (config.autoPause === undefined) config.autoPause = true;\n  if (config.latency === undefined) config.latency = 500;\n\n  return function (createStore) {\n    return function <S, A extends Action<string>, PreloadedState>(\n      reducer: Reducer<S, A, PreloadedState>,\n      preloadedState?: PreloadedState | undefined,\n    ) {\n      const store = createStore(reducer, preloadedState);\n      const origDispatch = store.dispatch;\n\n      const devTools = window.__REDUX_DEVTOOLS_EXTENSION__!.connect(config);\n      devTools.init(store.getState());\n\n      const dispatch: Dispatch<A> = function (action) {\n        const r = origDispatch(action);\n        devTools.send(action, store.getState());\n        return r;\n      };\n\n      return Object.assign(store, { dispatch: dispatch });\n    };\n  };\n}\n\nfunction composeWithEnhancer(config?: EnhancerOptions) {\n  return function (...funcs: StoreEnhancer[]) {\n    return compose(compose(...funcs), enhancer(config));\n  };\n}\n\nexport function composeWithDevTools(\n  config: Config,\n): <StoreEnhancers extends readonly StoreEnhancer[]>(\n  ...funcs: StoreEnhancers\n) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;\nexport function composeWithDevTools<\n  StoreEnhancers extends readonly StoreEnhancer[],\n>(\n  ...funcs: StoreEnhancers\n): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;\nexport function composeWithDevTools(...funcs: [Config] | StoreEnhancer[]) {\n  if (typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__) {\n    if (funcs.length === 0) return enhancer();\n    if (typeof funcs[0] === 'object') return composeWithEnhancer(funcs[0]);\n    return composeWithEnhancer()(...(funcs as StoreEnhancer[]));\n  }\n\n  if (funcs.length === 0) return undefined;\n  if (typeof funcs[0] === 'object') return compose;\n  return compose(...(funcs as StoreEnhancer[]));\n}\n\nexport const devToolsEnhancer: (options?: EnhancerOptions) => StoreEnhancer =\n  typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__\n    ? enhancer\n    : function () {\n        return function (noop) {\n          return noop;\n        };\n      };\n"
  },
  {
    "path": "packages/redux-devtools-extension/src/logOnlyInProduction.ts",
    "content": "import { compose } from 'redux';\nimport type { StoreEnhancer } from 'redux';\nimport * as logOnly from './logOnly.js';\nimport type {\n  Config,\n  EnhancerOptions,\n  InferComposedStoreExt,\n  ReduxDevtoolsExtensionCompose,\n} from './index.js';\n\ndeclare const process: {\n  env: {\n    NODE_ENV: string;\n  };\n};\n\nfunction extensionComposeStub(\n  config: Config,\n): <StoreEnhancers extends readonly StoreEnhancer[]>(\n  ...funcs: StoreEnhancers\n) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;\nfunction extensionComposeStub<StoreEnhancers extends readonly StoreEnhancer[]>(\n  ...funcs: StoreEnhancers\n): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;\nfunction extensionComposeStub(...funcs: [Config] | StoreEnhancer[]) {\n  if (funcs.length === 0) return undefined;\n  if (typeof funcs[0] === 'object') return compose;\n  return compose(...(funcs as StoreEnhancer[]));\n}\n\nexport const composeWithDevTools: ReduxDevtoolsExtensionCompose =\n  process.env.NODE_ENV === 'production'\n    ? logOnly.composeWithDevTools\n    : typeof window !== 'undefined' &&\n        window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__\n      ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__\n      : extensionComposeStub;\n\nexport const devToolsEnhancer: (options?: EnhancerOptions) => StoreEnhancer =\n  process.env.NODE_ENV === 'production'\n    ? logOnly.devToolsEnhancer\n    : typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__\n      ? window.__REDUX_DEVTOOLS_EXTENSION__\n      : function () {\n          return function (noop) {\n            return noop;\n          };\n        };\n"
  },
  {
    "path": "packages/redux-devtools-extension/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/CHANGELOG.md",
    "content": "# Change Log\n\n## 7.0.0\n\n### Major Changes\n\n- 12849a4: Convert monitors to ESM\n\n### Patch Changes\n\n- Updated dependencies [804d6bd]\n  - @redux-devtools/core@5.0.0\n\n## 6.1.2\n\n### Patch Changes\n\n- 20883e5: fix(deps): update all non-major dependencies\n\n## 6.1.1\n\n### Patch Changes\n\n- Updated dependencies [91f21b2]\n  - @redux-devtools/core@4.1.1\n\n## 6.1.0\n\n### Minor Changes\n\n- 6830118: Add React 19 to peer deps\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - react-json-tree@0.20.0\n  - @redux-devtools/core@4.1.0\n\n## 6.0.1\n\n### Patch Changes\n\n- Updated dependencies [bbb1a40]\n  - react-base16-styling@0.10.0\n  - react-json-tree@0.19.0\n\n## 6.0.0\n\n### Major Changes\n\n- 5cfe3e5: Update min required React version to 16.8.4\n\n### Patch Changes\n\n- Updated dependencies [decc035]\n  - @redux-devtools/core@4.0.0\n\n## 5.0.1\n\n### Patch Changes\n\n- 3205269: Add explicit return types\n\n## 5.0.0\n\n### Major Changes\n\n- 158ba2c: Replace jss with Emotion in inspector-monitor. `@emotion/react` is now a required peer dependency.\n\n## 4.1.0\n\n### Minor Changes\n\n- 6fc18ed7: Add new Redux version to peer dependencies\n\n### Patch Changes\n\n- 7f5bddbd: Widen peer dependencies\n\n## 4.0.1\n\n### Patch Changes\n\n- 65205f90: Replace Action<unknown> with Action<string>\n- Updated dependencies [65205f90]\n  - @redux-devtools/core@3.13.2\n\n## 4.0.0\n\n### Major Changes\n\n- 57751ff9: Add react-dom peerDependency and bump react peerDependency to `^16.8.0 || ^17.0.0 || ^18.0.0`\n\n## 3.1.1\n\n### Patch Changes\n\n- fe32709c: Update jsondiffpatch to fix bundling issues.\n\n## 3.1.0\n\n### Minor Changes\n\n- d54adb76: Option to sort State Tree keys alphabetically\n  Option to disable collapsing of object keys\n\n### Patch Changes\n\n- 14a79573: Replace react-dragula with dnd-kit\n- bb9bd907: Move @types/redux-devtools-themes to dependencies\n\n## 3.0.2\n\n### Patch Changes\n\n- Updated dependencies [81926f32]\n  - react-json-tree@0.18.0\n\n## 3.0.1\n\n### Patch Changes\n\n- a55ba302: Fix peer dependencies on @redux-devtools/core\n- Updated dependencies [a55ba302]\n  - @redux-devtools/core@3.13.1\n\n## 3.0.0\n\n### Minor Changes\n\n- 8a7eae4: Add React 18 to peerDependencies range\n\n### Patch Changes\n\n- Updated dependencies [8a7eae4]\n  - react-json-tree@0.17.0\n  - @redux-devtools/core@3.13.0\n\n## 2.1.2\n\n### Patch Changes\n\n- Updated dependencies [4891bf6]\n  - @redux-devtools/core@3.12.0\n\n## 2.1.1\n\n### Patch Changes\n\n- 55cc37e: Fix filter to show state-controlled search value\n\n## 2.0.0\n\n- Adds ESM build (https://github.com/reduxjs/redux-devtools/pull/997) and switches the default export to a named export in order to ensure that the CommonJS output and the ESM output are [interchangeable](https://rollupjs.org/guide/en/#outputexports):\n\n```diff\n- import Inspector from '@redux-devtools/inspector-monitor';\n+ import { InspectorMonitor } from '@redux-devtools/inspector-monitor';\n```\n\n## [1.0.0](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/inspector-monitor@0.15.0...@redux-devtools/inspector-monitor@1.0.0) (2021-06-11)\n\n### Bug Fixes\n\n- **inspector:** fix z-index of tabs ([#723](https://github.com/reduxjs/redux-devtools/issues/723)) ([e747783](https://github.com/reduxjs/redux-devtools/commit/e7477833f05ab0ff8f947a48d97eb3ed87ccb70b))\n- **inspector:** move immutable back to dependencies ([#725](https://github.com/reduxjs/redux-devtools/issues/725)) ([fcd73ab](https://github.com/reduxjs/redux-devtools/commit/fcd73ab043062bd3c191fd814f3d912bea6fc675))\n\n## [0.15.0](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/inspector-monitor@0.14.1...@redux-devtools/inspector-monitor@0.15.0) (2021-03-06)\n\n### Features\n\n- update peer dependencies to allow react@^17 ([#703](https://github.com/reduxjs/redux-devtools/issues/703)) ([2aaa9c1](https://github.com/reduxjs/redux-devtools/commit/2aaa9c10a383e3a7ab20b3ab14639781fd7bb2eb))\n\n## 0.14.1 (2021-03-06)\n\n**Note:** Version bump only for package @redux-devtools/inspector-monitor\n\n## [0.14.0](https://github.com/reduxjs/redux-devtools/compare/redux-devtools-inspector@0.13.1...redux-devtools-inspector@0.14.0) (2020-09-07)\n\n### Features\n\n- **redux-devtools-inspector:** convert to TypeScript ([#623](https://github.com/reduxjs/redux-devtools/issues/623)) ([c7b0c7a](https://github.com/reduxjs/redux-devtools/commit/c7b0c7aa6e09f46a36b382ae3ec8e38bd48aeb28))\n\n## [0.13.1](https://github.com/reduxjs/redux-devtools/compare/redux-devtools-inspector@0.13.0...redux-devtools-inspector@0.13.1) (2020-08-14)\n\n**Note:** Version bump only for package redux-devtools-inspector\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/LICENSE.md",
    "content": "MIT License\n\nCopyright (c) 2015 Alexander Kuznetsov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/README.md",
    "content": "# redux-devtools-inspector-monitor\n\n[![npm version](https://badge.fury.io/js/redux-devtools-inspector.svg)](https://badge.fury.io/js/redux-devtools-inspector)\n\nA state monitor for [Redux DevTools](https://github.com/reduxjs/redux-devtools) that provides a convenient way to inspect \"real world\" app states that could be complicated and deeply nested. Created by [@alexkuz](https://github.com/alexkuz) and merged from [`alexkuz/redux-devtools-inspector`](https://github.com/alexkuz/redux-devtools-inspector) into [`reduxjs/redux-devtools` monorepo](https://github.com/reduxjs/redux-devtools).\n\n![](https://raw.githubusercontent.com/alexkuz/redux-devtools-inspector/master/demo.gif)\n\n### Installation\n\n```\nyarn add @redux-devtools/inspector-monitor\n```\n\n### Usage\n\nYou can use `Inspector` as the only monitor in your app:\n\n##### `containers/DevTools.js`\n\n```js\nimport React from 'react';\nimport { createDevTools } from '@redux-devtools/core';\nimport { InspectorMonitor } from '@redux-devtools/inspector-monitor';\n\nexport default createDevTools(<InspectorMonitor />);\n```\n\nThen you can render `<DevTools>` to any place inside app or even into a separate popup window.\n\nAlternative, you can use it together with [`DockMonitor`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-dock-monitor) to make it dockable.  \nConsult the [`DockMonitor` README](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-dock-monitor) for details of this approach.\n\n[Read how to start using Redux DevTools.](https://github.com/gaearon/redux-devtools)\n\n### Features\n\nThe inspector displays a list of actions and a preview panel which shows the state after the selected action and a diff with the previous state. If no actions are selected, the last state is shown.\n\nYou may pin a certain part of the state to only track its changes.\n\n### Props\n\n| Name                 | Type              | Description                                                                                                                                                       |\n| -------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `theme`              | Object or string  | Contains either [base16](https://github.com/chriskempson/base16) theme name or object, that can be `base16` colors map or object containing classnames or styles. |\n| `invertTheme`        | Boolean           | Inverts theme color luminance, making light theme out of dark theme and vice versa.                                                                               |\n| `supportImmutable`   | Boolean           | Better `Immutable` rendering in `Diff` (can affect performance if state has huge objects/arrays). `false` by default.                                             |\n| `tabs`               | Array or function | Overrides list of tabs (see below)                                                                                                                                |\n| `diffObjectHash`     | Function          | Optional callback for better array handling in diffs (see [jsondiffpatch docs](https://github.com/benjamine/jsondiffpatch/blob/master/docs/arrays.md))            |\n| `diffPropertyFilter` | Function          | Optional callback for ignoring particular props in diff (see [jsondiffpatch docs](https://github.com/benjamine/jsondiffpatch#options))                            |\n\nIf `tabs` is a function, it receives a list of default tabs and should return updated list, for example:\n\n```\ndefaultTabs => [...defaultTabs, { name: 'My Tab', component: MyTab }]\n```\n\nIf `tabs` is an array, only provided tabs are rendered.\n\n`component` is provided with `action` and other props, see [`ActionPreview.jsx`](src/ActionPreview.jsx#L42) for reference.\n\nUsage example: [`redux-devtools-inspector-monitor-test-tab`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-inspector-monitor-test-tab#containersdevtoolsjs).\n\n### License\n\nMIT\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/demo/CHANGELOG.md",
    "content": "# inspector-demo\n\n## 0.1.14\n\n### Patch Changes\n\n- Updated dependencies [12849a4]\n- Updated dependencies [804d6bd]\n  - @redux-devtools/dock-monitor@5.0.0\n  - @redux-devtools/inspector-monitor@7.0.0\n  - @redux-devtools/core@5.0.0\n\n## 0.1.13\n\n### Patch Changes\n\n- Updated dependencies [91f21b2]\n  - @redux-devtools/core@4.1.1\n  - @redux-devtools/dock-monitor@4.1.1\n  - @redux-devtools/inspector-monitor@6.1.1\n\n## 0.1.12\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - @redux-devtools/dock-monitor@5.0.0\n  - @redux-devtools/inspector-monitor@7.0.0\n  - @redux-devtools/core@4.1.0\n\n## 0.1.11\n\n### Patch Changes\n\n- Updated dependencies [bbb1a40]\n  - react-base16-styling@0.10.0\n  - @redux-devtools/inspector-monitor@6.0.1\n  - @redux-devtools/dock-monitor@4.0.1\n\n## 0.1.10\n\n### Patch Changes\n\n- Updated dependencies [5cfe3e5]\n- Updated dependencies [decc035]\n  - @redux-devtools/dock-monitor@4.0.0\n  - @redux-devtools/inspector-monitor@6.0.0\n  - @redux-devtools/core@4.0.0\n\n## 0.1.9\n\n### Patch Changes\n\n- Updated dependencies [158ba2c]\n  - @redux-devtools/inspector-monitor@5.0.0\n\n## 0.1.8\n\n### Patch Changes\n\n- Updated dependencies [57751ff9]\n  - @redux-devtools/inspector-monitor@4.0.0\n\n## 0.1.7\n\n### Patch Changes\n\n- Updated dependencies [8a7eae4]\n  - @redux-devtools/dock-monitor@3.0.0\n  - @redux-devtools/inspector-monitor@3.0.0\n  - @redux-devtools/core@3.13.0\n\n## 0.1.6\n\n### Patch Changes\n\n- Updated dependencies [4891bf6]\n  - @redux-devtools/core@3.12.0\n  - @redux-devtools/dock-monitor@2.1.1\n  - @redux-devtools/inspector-monitor@2.1.2\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/demo/eslint.config.mjs",
    "content": "import eslintJs from '../../../eslint.js.config.base.mjs';\nimport eslintTs from '../../../eslint.ts.react.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTs(import.meta.dirname),\n  ...eslintTs(\n    import.meta.dirname,\n    ['webpack.config.ts'],\n    ['./tsconfig.webpack.json'],\n  ),\n  {\n    ignores: ['dist'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/demo/index.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />\n    <title><%= htmlWebpackPlugin.options.package.name %></title>\n    <meta\n      name=\"description\"\n      content=\"<%= htmlWebpackPlugin.options.package.description %>\"\n    />\n    <link\n      href=\"http://fonts.googleapis.com/css?family=Noto+Sans|Roboto:400,300,500\"\n      rel=\"stylesheet\"\n      type=\"text/css\"\n    />\n    <link\n      href=\"//maxcdn.bootstrapcdn.com/bootswatch/3.3.5/paper/bootstrap.min.css\"\n      rel=\"stylesheet\"\n    />\n  </head>\n  <body>\n    <a href=\"<%= htmlWebpackPlugin.options.package.repository.url %>\"\n      ><img\n        style=\"z-index: 999999999; position: fixed; top: 0; left: 0; border: 0\"\n        src=\"https://camo.githubusercontent.com/121cd7cbdc3e4855075ea8b558508b91ac463ac2/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f6c6566745f677265656e5f3030373230302e706e67\"\n        alt=\"Fork me on GitHub\"\n        data-canonical-src=\"https://s3.amazonaws.com/github/ribbons/forkme_left_green_007200.png\"\n    /></a>\n    <div id=\"root\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/demo/package.json",
    "content": "{\n  \"private\": true,\n  \"name\": \"inspector-demo\",\n  \"version\": \"0.1.14\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"start\": \"cross-env TS_NODE_PROJECT=\\\"tsconfig.webpack.json\\\" webpack serve --open\",\n    \"build\": \"cross-env TS_NODE_PROJECT=\\\"tsconfig.webpack.json\\\" webpack\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\"\n  },\n  \"dependencies\": {\n    \"@emotion/react\": \"^11.14.0\",\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@redux-devtools/dock-monitor\": \"workspace:^\",\n    \"@redux-devtools/inspector-monitor\": \"workspace:^\",\n    \"immutable\": \"^5.1.5\",\n    \"lodash.shuffle\": \"^4.2.0\",\n    \"react\": \"^19.2.4\",\n    \"react-base16-styling\": \"workspace:^\",\n    \"react-bootstrap\": \"^2.10.10\",\n    \"react-dom\": \"^19.2.4\",\n    \"react-redux\": \"^9.2.0\",\n    \"react-router-dom\": \"^7.13.1\",\n    \"redux\": \"^5.0.1\",\n    \"redux-logger\": \"^3.0.6\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.29.0\",\n    \"@babel/preset-env\": \"^7.29.0\",\n    \"@babel/preset-react\": \"^7.28.5\",\n    \"@babel/preset-typescript\": \"^7.28.5\",\n    \"@types/lodash.shuffle\": \"^4.2.9\",\n    \"@types/node\": \"^24.12.0\",\n    \"@types/react\": \"^19.2.14\",\n    \"@types/react-dom\": \"^19.2.3\",\n    \"@types/redux-logger\": \"^3.0.13\",\n    \"@types/webpack-env\": \"^1.18.8\",\n    \"babel-loader\": \"^10.1.1\",\n    \"cross-env\": \"^10.1.0\",\n    \"fork-ts-checker-webpack-plugin\": \"^9.1.0\",\n    \"html-webpack-plugin\": \"^5.6.6\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"~5.9.3\",\n    \"webpack\": \"^5.105.4\",\n    \"webpack-cli\": \"^7.0.0\",\n    \"webpack-dev-server\": \"^5.2.3\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/demo/src/DemoApp.tsx",
    "content": "import React, { CSSProperties, useRef } from 'react';\nimport { connect } from 'react-redux';\nimport pkg from '@redux-devtools/inspector-monitor/package.json';\nimport Button from 'react-bootstrap/Button';\nimport FormGroup from 'react-bootstrap/FormGroup';\nimport FormControl from 'react-bootstrap/FormControl';\nimport FormLabel from 'react-bootstrap/FormLabel';\nimport Form from 'react-bootstrap/Form';\nimport Col from 'react-bootstrap/Col';\nimport InputGroup from 'react-bootstrap/InputGroup';\nimport Row from 'react-bootstrap/Row';\nimport { base16Themes } from 'react-base16-styling';\nimport { inspectorThemes } from '@redux-devtools/inspector-monitor';\nimport { useLocation, useNavigate } from 'react-router-dom';\nimport getOptions, { Options } from './getOptions';\nimport {\n  AddFunctionAction,\n  AddHugeObjectAction,\n  AddImmutableMapAction,\n  AddIteratorAction,\n  AddNativeMapAction,\n  AddRecursiveAction,\n  AddSymbolAction,\n  ChangeImmutableNestedAction,\n  ChangeNestedAction,\n  DemoAppState,\n  HugePayloadAction,\n  IncrementAction,\n  PopAction,\n  PushAction,\n  PushHugeArrayAction,\n  ReplaceAction,\n  ShuffleArrayAction,\n  TimeoutUpdateAction,\n  ToggleTimeoutUpdateAction,\n} from './reducers';\n\nconst styles: {\n  wrapper: CSSProperties;\n  header: CSSProperties;\n  content: CSSProperties;\n  buttons: CSSProperties;\n  muted: CSSProperties;\n  button: CSSProperties;\n  links: CSSProperties;\n  link: CSSProperties;\n  input: CSSProperties;\n} = {\n  wrapper: {\n    height: '100vh',\n    width: '80%',\n    margin: '0 auto',\n    paddingTop: '1px',\n  },\n  header: {},\n  content: {\n    display: 'flex',\n    alignItems: 'center',\n    justifyContent: 'center',\n    height: '50%',\n  },\n  buttons: {\n    display: 'flex',\n    width: '40rem',\n    justifyContent: 'center',\n    flexWrap: 'wrap',\n  },\n  muted: {\n    color: '#CCCCCC',\n  },\n  button: {\n    margin: '0.5rem',\n  },\n  links: {\n    textAlign: 'center',\n  },\n  link: {\n    margin: '0 0.5rem',\n    cursor: 'pointer',\n    display: 'block',\n  },\n  input: {\n    display: 'inline-block',\n    textAlign: 'left',\n    width: '30rem',\n  },\n};\n\nconst themeOptions = [\n  ...Object.keys(inspectorThemes).map((value) => ({\n    value,\n    label: inspectorThemes[value as keyof typeof inspectorThemes].scheme,\n  })),\n  null,\n  ...Object.keys(base16Themes)\n    .map((value) => ({\n      value,\n      label: base16Themes[value as keyof typeof base16Themes].scheme,\n    }))\n    .filter((opt) => opt.label),\n];\n\nconst ROOT =\n  process.env.NODE_ENV === 'production'\n    ? '/redux-devtools-inspector-monitor/'\n    : '/';\n\nfunction buildUrl(options: Options) {\n  return (\n    `${ROOT}?` +\n    [\n      options.useExtension ? 'ext' : '',\n      options.supportImmutable ? 'immutable' : '',\n      options.theme ? 'theme=' + options.theme : '',\n      options.dark ? 'dark' : '',\n    ]\n      .filter((s) => s)\n      .join('&')\n  );\n}\n\ninterface Props extends Omit<\n  DemoAppState,\n  'addFunction' | 'addSymbol' | 'shuffleArray'\n> {\n  toggleTimeoutUpdate: (timeoutUpdateEnabled: boolean) => void;\n  timeoutUpdate: () => void;\n  increment: () => void;\n  push: () => void;\n  pop: () => void;\n  replace: () => void;\n  changeNested: () => void;\n  pushHugeArray: () => void;\n  addIterator: () => void;\n  addHugeObject: () => void;\n  addRecursive: () => void;\n  addNativeMap: () => void;\n  addImmutableMap: () => void;\n  changeImmutableNested: () => void;\n  hugePayload: () => void;\n  addFunction: () => void;\n  addSymbol: () => void;\n  shuffleArray: () => void;\n}\n\nfunction DemoApp(props: Props) {\n  const timeout = useRef<number | undefined>(undefined);\n  const location = useLocation();\n  const navigate = useNavigate();\n\n  const toggleExtension = () => {\n    const options = getOptions(location);\n\n    window.location.href = buildUrl({\n      ...options,\n      useExtension: !options.useExtension,\n    });\n  };\n\n  const toggleImmutableSupport = async () => {\n    const options = getOptions(location);\n\n    await navigate(\n      buildUrl({ ...options, supportImmutable: !options.supportImmutable }),\n    );\n  };\n\n  const toggleTheme = async () => {\n    const options = getOptions(location);\n\n    await navigate(buildUrl({ ...options, dark: !options.dark }));\n  };\n\n  const setTheme = async (options: Options, theme: string) => {\n    await navigate(buildUrl({ ...options, theme }));\n  };\n\n  const toggleTimeoutUpdate = () => {\n    const enabled = !props.timeoutUpdateEnabled;\n    props.toggleTimeoutUpdate(enabled);\n\n    if (enabled) {\n      timeout.current = window.setInterval(props.timeoutUpdate, 1000);\n    } else {\n      clearTimeout(timeout.current);\n    }\n  };\n\n  const options = getOptions(location);\n\n  return (\n    <div style={styles.wrapper}>\n      <h1 style={styles.header}>\n        {pkg.name || <span style={styles.muted}>Package Name</span>}\n      </h1>\n      <h5>\n        {pkg.description || (\n          <span style={styles.muted}>Package Description</span>\n        )}\n      </h5>\n      <div style={styles.links}>\n        <div style={styles.input}>\n          <Form>\n            <FormGroup as={Row}>\n              <Col as={FormLabel} sm={3}>\n                Theme:\n              </Col>\n              <Col sm={9}>\n                <InputGroup>\n                  <FormControl\n                    as=\"select\"\n                    onChange={(event) =>\n                      setTheme(options, event.currentTarget.value)\n                    }\n                  >\n                    {themeOptions.map((theme) => (\n                      <option\n                        key={(theme && theme.label) || 'empty'}\n                        label={(theme && theme.label) || '──────────'}\n                        value={theme ? theme.value : undefined}\n                        disabled={!theme}\n                      />\n                    ))}\n                  </FormControl>\n                  <a onClick={toggleTheme} style={styles.link}>\n                    {options.dark ? 'Light theme' : 'Dark theme'}\n                  </a>\n                </InputGroup>\n              </Col>\n            </FormGroup>\n          </Form>\n        </div>\n      </div>\n      <div style={styles.content}>\n        <div style={styles.buttons}>\n          <Button onClick={props.increment} style={styles.button}>\n            Increment\n          </Button>\n          <Button onClick={props.push} style={styles.button}>\n            Push\n          </Button>\n          <Button onClick={props.pop} style={styles.button}>\n            Pop\n          </Button>\n          <Button onClick={props.replace} style={styles.button}>\n            Replace\n          </Button>\n          <Button onClick={props.changeNested} style={styles.button}>\n            Change Nested\n          </Button>\n          <Button onClick={props.pushHugeArray} style={styles.button}>\n            Push Huge Array\n          </Button>\n          <Button onClick={props.addHugeObject} style={styles.button}>\n            Add Huge Object\n          </Button>\n          <Button onClick={props.addIterator} style={styles.button}>\n            Add Iterator\n          </Button>\n          <Button onClick={props.addRecursive} style={styles.button}>\n            Add Recursive\n          </Button>\n          <Button onClick={props.addNativeMap} style={styles.button}>\n            Add Native Map\n          </Button>\n          <Button onClick={props.addImmutableMap} style={styles.button}>\n            Add Immutable Map\n          </Button>\n          <Button onClick={props.changeImmutableNested} style={styles.button}>\n            Change Immutable Nested\n          </Button>\n          <Button onClick={props.hugePayload} style={styles.button}>\n            Huge Payload\n          </Button>\n          <Button onClick={props.addFunction} style={styles.button}>\n            Add Function\n          </Button>\n          <Button onClick={props.addSymbol} style={styles.button}>\n            Add Symbol\n          </Button>\n          <Button onClick={toggleTimeoutUpdate} style={styles.button}>\n            Timeout Update {props.timeoutUpdateEnabled ? 'On' : 'Off'}\n          </Button>\n          <Button onClick={props.shuffleArray} style={styles.button}>\n            Shuffle Array\n          </Button>\n        </div>\n      </div>\n      <div style={styles.links}>\n        <a onClick={toggleExtension} style={styles.link}>\n          {(options.useExtension ? 'Disable' : 'Enable') +\n            ' Chrome Extension (will reload this page)'}\n        </a>\n        <a onClick={toggleImmutableSupport} style={styles.link}>\n          {(options.supportImmutable ? 'Disable' : 'Enable') +\n            ' Full Immutable Support'}\n        </a>\n      </div>\n    </div>\n  );\n}\n\nexport default connect((state: DemoAppState) => state, {\n  toggleTimeoutUpdate: (\n    timeoutUpdateEnabled: boolean,\n  ): ToggleTimeoutUpdateAction => ({\n    type: 'TOGGLE_TIMEOUT_UPDATE',\n    timeoutUpdateEnabled,\n  }),\n  timeoutUpdate: (): TimeoutUpdateAction => ({ type: 'TIMEOUT_UPDATE' }),\n  increment: (): IncrementAction => ({ type: 'INCREMENT' }),\n  push: (): PushAction => ({ type: 'PUSH' }),\n  pop: (): PopAction => ({ type: 'POP' }),\n  replace: (): ReplaceAction => ({ type: 'REPLACE' }),\n  changeNested: (): ChangeNestedAction => ({ type: 'CHANGE_NESTED' }),\n  pushHugeArray: (): PushHugeArrayAction => ({ type: 'PUSH_HUGE_ARRAY' }),\n  addIterator: (): AddIteratorAction => ({ type: 'ADD_ITERATOR' }),\n  addHugeObject: (): AddHugeObjectAction => ({ type: 'ADD_HUGE_OBJECT' }),\n  addRecursive: (): AddRecursiveAction => ({ type: 'ADD_RECURSIVE' }),\n  addNativeMap: (): AddNativeMapAction => ({ type: 'ADD_NATIVE_MAP' }),\n  addImmutableMap: (): AddImmutableMapAction => ({ type: 'ADD_IMMUTABLE_MAP' }),\n  changeImmutableNested: (): ChangeImmutableNestedAction => ({\n    type: 'CHANGE_IMMUTABLE_NESTED',\n  }),\n  hugePayload: (): HugePayloadAction => ({\n    type: 'HUGE_PAYLOAD',\n    payload: Array.from({ length: 10000 }).map((_, i) => i),\n  }),\n  addFunction: (): AddFunctionAction => ({ type: 'ADD_FUNCTION' }),\n  addSymbol: (): AddSymbolAction => ({ type: 'ADD_SYMBOL' }),\n  shuffleArray: (): ShuffleArrayAction => ({ type: 'SHUFFLE_ARRAY' }),\n})(DemoApp);\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/demo/src/DevTools.tsx",
    "content": "import React from 'react';\nimport { createDevTools } from '@redux-devtools/core';\nimport { DockMonitor } from '@redux-devtools/dock-monitor';\nimport { InspectorMonitor } from '@redux-devtools/inspector-monitor';\nimport type { Base16ThemeName } from '@redux-devtools/inspector-monitor';\nimport { useLocation } from 'react-router-dom';\nimport getOptions from './getOptions';\n\nconst CustomComponent = () => (\n  <div\n    style={{\n      display: 'flex',\n      alignItems: 'center',\n      justifyContent: 'center',\n      width: '100%',\n      height: '100%',\n      minHeight: '20rem',\n    }}\n  >\n    <div>Custom Tab Content</div>\n  </div>\n);\n\nexport const getDevTools = (location: { search: string }) =>\n  createDevTools(\n    <DockMonitor\n      defaultIsVisible\n      toggleVisibilityKey=\"ctrl-h\"\n      changePositionKey=\"ctrl-q\"\n      changeMonitorKey=\"ctrl-m\"\n    >\n      <InspectorMonitor\n        theme={getOptions(location).theme as Base16ThemeName}\n        invertTheme={!getOptions(location).dark}\n        supportImmutable={getOptions(location).supportImmutable}\n        tabs={(defaultTabs) => [\n          {\n            name: 'Custom Tab',\n            component: CustomComponent,\n          },\n          ...defaultTabs,\n        ]}\n      />\n    </DockMonitor>,\n  );\n\nexport function ConnectedDevTools() {\n  const location = useLocation();\n  const DevTools = getDevTools(location);\n  // eslint-disable-next-line react-hooks/static-components\n  return <DevTools />;\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/demo/src/getOptions.ts",
    "content": "export interface Options {\n  useExtension: boolean;\n  supportImmutable: boolean;\n  theme: string;\n  dark: boolean;\n}\n\nexport default function getOptions(location: { search: string }) {\n  return {\n    useExtension: location.search.includes('ext'),\n    supportImmutable: location.search.includes('immutable'),\n    theme: getTheme(location),\n    dark: location.search.includes('dark'),\n  };\n}\n\nfunction getTheme(location: { search: string }) {\n  const match = /theme=([^&]+)/.exec(location.search);\n  return match ? match[1] : 'inspector';\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/demo/src/index.tsx",
    "content": "import React from 'react';\nimport { createRoot } from 'react-dom/client';\nimport { Provider } from 'react-redux';\nimport {\n  createStore,\n  applyMiddleware,\n  compose,\n  StoreEnhancerStoreCreator,\n  StoreEnhancer,\n} from 'redux';\nimport logger from 'redux-logger';\nimport { BrowserRouter, Route, Routes } from 'react-router-dom';\nimport { persistState } from '@redux-devtools/core';\nimport DemoApp from './DemoApp';\nimport { rootReducer } from './reducers';\nimport getOptions from './getOptions';\nimport { ConnectedDevTools, getDevTools } from './DevTools';\n\nfunction getDebugSessionKey() {\n  const matches = /[?&]debug_session=([^&#]+)\\b/.exec(window.location.href);\n  return matches && matches.length > 0 ? matches[1] : null;\n}\n\nconst ROOT =\n  process.env.NODE_ENV === 'production'\n    ? '/redux-devtools-inspector-monitor/'\n    : '/';\n\nconst DevTools = getDevTools(window.location);\n\nconst useDevtoolsExtension =\n  !!(window as unknown as { __REDUX_DEVTOOLS_EXTENSION__: unknown })\n    .__REDUX_DEVTOOLS_EXTENSION__ && getOptions(window.location).useExtension;\n\nconst enhancer: StoreEnhancer = compose(\n  applyMiddleware(logger),\n  (next: StoreEnhancerStoreCreator) => {\n    const instrument = useDevtoolsExtension\n      ? (\n          window as unknown as {\n            __REDUX_DEVTOOLS_EXTENSION__(): StoreEnhancer;\n          }\n        ).__REDUX_DEVTOOLS_EXTENSION__()\n      : DevTools.instrument();\n    return instrument(next);\n  },\n  persistState(getDebugSessionKey()),\n) as any;\n\nconst store = createStore(rootReducer, enhancer);\n\nconst root = createRoot(document.getElementById('root')!);\nroot.render(\n  <Provider store={store}>\n    <BrowserRouter>\n      <Routes>\n        <Route path={ROOT} element={<DemoApp />} />\n      </Routes>\n      {!useDevtoolsExtension && <ConnectedDevTools />}\n    </BrowserRouter>\n  </Provider>,\n);\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/demo/src/reducers.ts",
    "content": "import {\n  fromJS,\n  Map as ImmutableMap,\n  List,\n  Set as ImmutableSet,\n  Stack,\n  Seq,\n} from 'immutable';\nimport shuffle from 'lodash.shuffle';\nimport { combineReducers, Reducer } from 'redux';\n\ntype Nested = { long: { nested: { path: { to: { a: string } } }[] } };\n\nconst NESTED = {\n  long: {\n    nested: [\n      {\n        path: {\n          to: {\n            a: 'key',\n          },\n        },\n      },\n    ],\n  },\n};\n\nconst IMMUTABLE_NESTED = fromJS(NESTED) as ImmutableMap<unknown, unknown>;\n\nconst IMMUTABLE_MAP = ImmutableMap({\n  map: ImmutableMap({ a: 1, b: 2, c: 3 }),\n  list: List(['a', 'b', 'c']),\n  set: ImmutableSet(['a', 'b', 'c']),\n  stack: Stack(['a', 'b', 'c']),\n  seq: Seq([1, 2, 3, 4, 5, 6, 7, 8]),\n});\n\ntype MapValue =\n  | Map<{ first: boolean } | string, number>\n  | WeakMap<{ first: boolean } | { second: number }, number>\n  | Set<{ first: boolean } | string>\n  | WeakSet<{ first: boolean } | { second: number }>;\n\nconst NATIVE_MAP = new window.Map<string, MapValue>([\n  [\n    'map',\n    new window.Map<{ first: boolean } | string, number>([\n      [{ first: true }, 1],\n      ['second', 2],\n    ]),\n  ],\n  [\n    'weakMap',\n    new window.WeakMap<{ first: boolean } | { second: number }, number>([\n      [{ first: true }, 1],\n      [{ second: 1 }, 2],\n    ]),\n  ],\n  ['set', new window.Set([{ first: true }, 'second'])],\n  ['weakSet', new window.WeakSet([{ first: true }, { second: 1 }])],\n]);\n\nconst HUGE_ARRAY = Array.from({ length: 5000 }).map((_, key) => ({\n  str: `key ${key}`,\n}));\n\nconst HUGE_OBJECT = Array.from({ length: 5000 }).reduce(\n  (o: { [key: string]: string }, _, key) => (\n    (o[`key ${key}`] = `item ${key}`),\n    o\n  ),\n  {},\n);\n\nconst FUNC = function (a: number, b: number, c: number) {\n  return a + b + c;\n};\n\nconst RECURSIVE: { obj?: unknown } = {};\nRECURSIVE.obj = RECURSIVE;\n\nfunction createIterator() {\n  const iterable: { [Symbol.iterator](): IterableIterator<string> } = {\n    [Symbol.iterator]: function* iterator() {\n      for (let i = 0; i < 333; i++) {\n        yield `item ${i}`;\n      }\n    },\n  };\n\n  return iterable;\n}\n\nconst DEFAULT_SHUFFLE_ARRAY = [0, 1, null, { id: 1 }, { id: 2 }, 'string'];\n\nexport interface ToggleTimeoutUpdateAction {\n  type: 'TOGGLE_TIMEOUT_UPDATE';\n  timeoutUpdateEnabled: boolean;\n}\nexport interface TimeoutUpdateAction {\n  type: 'TIMEOUT_UPDATE';\n}\nexport interface IncrementAction {\n  type: 'INCREMENT';\n}\nexport interface PushAction {\n  type: 'PUSH';\n}\nexport interface PopAction {\n  type: 'POP';\n}\nexport interface ReplaceAction {\n  type: 'REPLACE';\n}\nexport interface ChangeNestedAction {\n  type: 'CHANGE_NESTED';\n}\nexport interface PushHugeArrayAction {\n  type: 'PUSH_HUGE_ARRAY';\n}\nexport interface AddIteratorAction {\n  type: 'ADD_ITERATOR';\n}\nexport interface AddHugeObjectAction {\n  type: 'ADD_HUGE_OBJECT';\n}\nexport interface AddRecursiveAction {\n  type: 'ADD_RECURSIVE';\n}\nexport interface AddNativeMapAction {\n  type: 'ADD_NATIVE_MAP';\n}\nexport interface AddImmutableMapAction {\n  type: 'ADD_IMMUTABLE_MAP';\n}\nexport interface ChangeImmutableNestedAction {\n  type: 'CHANGE_IMMUTABLE_NESTED';\n}\nexport interface HugePayloadAction {\n  type: 'HUGE_PAYLOAD';\n  payload: number[];\n}\nexport interface AddFunctionAction {\n  type: 'ADD_FUNCTION';\n}\nexport interface AddSymbolAction {\n  type: 'ADD_SYMBOL';\n}\nexport interface ShuffleArrayAction {\n  type: 'SHUFFLE_ARRAY';\n}\ntype DemoAppAction =\n  | ToggleTimeoutUpdateAction\n  | TimeoutUpdateAction\n  | IncrementAction\n  | PushAction\n  | PopAction\n  | ReplaceAction\n  | ChangeNestedAction\n  | PushHugeArrayAction\n  | AddIteratorAction\n  | AddHugeObjectAction\n  | AddRecursiveAction\n  | AddNativeMapAction\n  | AddImmutableMapAction\n  | ChangeImmutableNestedAction\n  | HugePayloadAction\n  | AddFunctionAction\n  | AddSymbolAction\n  | ShuffleArrayAction;\n\nexport interface DemoAppState {\n  timeoutUpdateEnabled: boolean;\n  store: number;\n  undefined: { val: undefined };\n  null: null;\n  func: () => void;\n  array: number[];\n  hugeArrays: { str: string }[];\n  hugeObjects: { [key: string]: string }[];\n  iterators: { [Symbol.iterator](): IterableIterator<string> }[];\n  nested: Nested;\n  recursive: { obj?: unknown }[];\n  immutables: Immutable.Map<string, unknown>[];\n  maps: Map<string, MapValue>[];\n  immutableNested: Immutable.Map<unknown, unknown>;\n  addFunction: { f: (a: number, b: number, c: number) => number } | null;\n  addSymbol: { s: symbol; error: Error } | null;\n  shuffleArray: unknown[];\n}\n\nexport const rootReducer: Reducer<DemoAppState, DemoAppAction> =\n  combineReducers({\n    timeoutUpdateEnabled: (state = false, action: DemoAppAction) =>\n      action.type === 'TOGGLE_TIMEOUT_UPDATE'\n        ? action.timeoutUpdateEnabled\n        : state,\n    store: (state = 0, action: DemoAppAction) =>\n      action.type === 'INCREMENT' ? state + 1 : state,\n    undefined: (state = { val: undefined }) => state,\n    null: (state = null) => state,\n    func: (\n      state = () => {\n        // noop\n      },\n    ) => state,\n    array: (state = [], action: DemoAppAction) =>\n      action.type === 'PUSH'\n        ? [...state, Math.random()]\n        : action.type === 'POP'\n          ? state.slice(0, state.length - 1)\n          : action.type === 'REPLACE'\n            ? [Math.random(), ...state.slice(1)]\n            : state,\n    hugeArrays: (state = [], action: DemoAppAction) =>\n      action.type === 'PUSH_HUGE_ARRAY' ? [...state, ...HUGE_ARRAY] : state,\n    hugeObjects: (state = [], action: DemoAppAction) =>\n      action.type === 'ADD_HUGE_OBJECT' ? [...state, HUGE_OBJECT] : state,\n    iterators: (state = [], action: DemoAppAction) =>\n      action.type === 'ADD_ITERATOR' ? [...state, createIterator()] : state,\n    nested: (state = NESTED, action: DemoAppAction) =>\n      action.type === 'CHANGE_NESTED'\n        ? {\n            ...state,\n            long: {\n              nested: [\n                {\n                  path: {\n                    to: {\n                      a: state.long.nested[0].path.to.a + '!',\n                    },\n                  },\n                },\n              ],\n            },\n          }\n        : state,\n    recursive: (state: { obj?: unknown }[] = [], action: DemoAppAction) =>\n      action.type === 'ADD_RECURSIVE' ? [...state, { ...RECURSIVE }] : state,\n    immutables: (\n      state: Immutable.Map<string, unknown>[] = [],\n      action: DemoAppAction,\n    ) =>\n      action.type === 'ADD_IMMUTABLE_MAP' ? [...state, IMMUTABLE_MAP] : state,\n    maps: (state: Map<string, MapValue>[] = [], action: DemoAppAction) =>\n      action.type === 'ADD_NATIVE_MAP' ? [...state, NATIVE_MAP] : state,\n    immutableNested: (state = IMMUTABLE_NESTED, action: DemoAppAction) =>\n      action.type === 'CHANGE_IMMUTABLE_NESTED'\n        ? state.updateIn(\n            ['long', 'nested', 0, 'path', 'to', 'a'],\n            (str: unknown) => (str as string) + '!',\n          )\n        : state,\n    addFunction: (state = null, action: DemoAppAction) =>\n      action.type === 'ADD_FUNCTION' ? { f: FUNC } : state,\n    addSymbol: (state = null, action: DemoAppAction) =>\n      action.type === 'ADD_SYMBOL'\n        ? { s: window.Symbol('symbol'), error: new Error('TEST') }\n        : state,\n    shuffleArray: (state = DEFAULT_SHUFFLE_ARRAY, action: DemoAppAction) =>\n      action.type === 'SHUFFLE_ARRAY' ? shuffle(state) : state,\n  }) as any;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/demo/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../tsconfig.react.base.json\",\n  \"compilerOptions\": {\n    \"resolveJsonModule\": true,\n    \"types\": [\"webpack-env\"]\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/demo/tsconfig.webpack.json",
    "content": "{\n  \"extends\": \"../../../tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"resolveJsonModule\": true,\n    \"types\": [\"node\", \"webpack-dev-server\"]\n  },\n  \"include\": [\"webpack.config.ts\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/demo/webpack.config.ts",
    "content": "import * as path from 'path';\nimport * as webpack from 'webpack';\nimport HtmlWebpackPlugin from 'html-webpack-plugin';\nimport ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';\nimport pkg from '@redux-devtools/inspector-monitor/package.json';\n\nconst config: webpack.Configuration = {\n  mode: 'development',\n  entry: './src/index.tsx',\n  devtool: 'eval-source-map',\n  devServer: {\n    static: './dist',\n  },\n  plugins: [\n    new HtmlWebpackPlugin({\n      template: './index.html',\n      package: pkg,\n    }),\n    new ForkTsCheckerWebpackPlugin(),\n  ],\n  output: {\n    filename: 'bundle.js',\n    path: path.join(__dirname, 'dist'),\n    clean: true,\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.(js|ts)x?$/,\n        exclude: /node_modules/,\n        use: {\n          loader: 'babel-loader',\n          options: {\n            presets: [\n              ['@babel/preset-env', { targets: 'defaults' }],\n              '@babel/preset-react',\n              '@babel/preset-typescript',\n            ],\n          },\n        },\n      },\n    ],\n  },\n  resolve: {\n    extensions: ['.js', '.jsx', '.ts', '.tsx'],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/eslint.config.mjs",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTsReact from '../../eslint.ts.react.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTsReact(import.meta.dirname),\n  {\n    ignores: ['demo', 'lib'],\n  },\n  {\n    files: ['**/*.ts', '**/*.tsx'],\n    rules: {\n      'react/no-unknown-property': ['error', { ignore: ['css'] }],\n    },\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/package.json",
    "content": "{\n  \"name\": \"@redux-devtools/inspector-monitor\",\n  \"version\": \"7.0.0\",\n  \"description\": \"Redux DevTools Diff Monitor\",\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-inspector-monitor\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Alexander <alexkuz@gmail.com> (http://kuzya.org/)\",\n  \"contributors\": [\n    \"Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)\"\n  ],\n  \"files\": [\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": {\n    \".\": \"./lib/index.js\",\n    \"./package.json\": \"./package.json\"\n  },\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run type-check && pnpm run lint\"\n  },\n  \"dependencies\": {\n    \"@dnd-kit/core\": \"^6.3.1\",\n    \"@dnd-kit/modifiers\": \"^9.0.0\",\n    \"@dnd-kit/sortable\": \"^10.0.0\",\n    \"@dnd-kit/utilities\": \"^3.2.2\",\n    \"@types/lodash\": \"^4.17.24\",\n    \"dateformat\": \"^5.0.3\",\n    \"hex-rgba\": \"^1.0.2\",\n    \"immutable\": \"^5.1.5\",\n    \"javascript-stringify\": \"^2.1.0\",\n    \"jsondiffpatch\": \"^0.7.3\",\n    \"lodash.debounce\": \"^4.0.8\",\n    \"react-base16-styling\": \"workspace:^\",\n    \"react-json-tree\": \"workspace:^\"\n  },\n  \"devDependencies\": {\n    \"@emotion/react\": \"^11.14.0\",\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@types/dateformat\": \"^5.0.3\",\n    \"@types/hex-rgba\": \"^1.0.3\",\n    \"@types/lodash.debounce\": \"^4.0.9\",\n    \"@types/react\": \"^19.2.14\",\n    \"react\": \"^19.2.4\",\n    \"redux\": \"^5.0.1\",\n    \"rimraf\": \"^6.1.3\",\n    \"typescript\": \"~5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"@emotion/react\": \"^11.14.0\",\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@types/react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react\": \"^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"redux\": \"^3.4.0 || ^4.0.0 || ^5.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/ActionList.tsx",
    "content": "import React, { ReactNode, useCallback, useLayoutEffect, useRef } from 'react';\nimport { Action } from 'redux';\nimport { PerformAction } from '@redux-devtools/core';\nimport {\n  closestCenter,\n  DndContext,\n  DragEndEvent,\n  KeyboardSensor,\n  PointerSensor,\n  useSensor,\n  useSensors,\n} from '@dnd-kit/core';\nimport { restrictToFirstScrollableAncestor } from '@dnd-kit/modifiers';\nimport {\n  SortableContext,\n  sortableKeyboardCoordinates,\n  useSortable,\n  verticalListSortingStrategy,\n} from '@dnd-kit/sortable';\nimport { CSS } from '@dnd-kit/utilities';\nimport type { JSX } from '@emotion/react/jsx-runtime';\nimport ActionListRow from './ActionListRow.js';\nimport ActionListHeader from './ActionListHeader.js';\n\nfunction getTimestamps<A extends Action<string>>(\n  actions: { [actionId: number]: PerformAction<A> },\n  actionIds: number[],\n  actionId: number,\n) {\n  const idx = actionIds.indexOf(actionId);\n  const prevActionId = actionIds[idx - 1];\n\n  return {\n    current: actions[actionId].timestamp,\n    previous: idx ? actions[prevActionId].timestamp : 0,\n  };\n}\n\nfunction scrollToBottom(node: HTMLDivElement) {\n  node.scrollTop = node.scrollHeight;\n}\n\ninterface Props<A extends Action<string>> {\n  actions: { [actionId: number]: PerformAction<A> };\n  actionIds: number[];\n  isWideLayout: boolean;\n  searchValue: string | undefined;\n  selectedActionId: number | null;\n  startActionId: number | null;\n  skippedActionIds: number[];\n  draggableActions: boolean;\n  hideMainButtons: boolean | undefined;\n  hideActionButtons: boolean | undefined;\n  onSearch: (value: string) => void;\n  onSelect: (e: React.MouseEvent<HTMLDivElement>, actionId: number) => void;\n  onToggleAction: (actionId: number) => void;\n  onJumpToState: (actionId: number) => void;\n  onCommit: () => void;\n  onSweep: () => void;\n  onReorderAction: (actionId: number, beforeActionId: number) => void;\n  currentActionId: number;\n  lastActionId: number;\n}\n\nexport default function ActionList<A extends Action<string>>({\n  actions,\n  actionIds,\n  isWideLayout,\n  onToggleAction,\n  skippedActionIds,\n  selectedActionId,\n  startActionId,\n  onSelect,\n  onSearch,\n  searchValue,\n  currentActionId,\n  hideMainButtons,\n  hideActionButtons,\n  onCommit,\n  onSweep,\n  onJumpToState,\n  lastActionId,\n  onReorderAction,\n}: Props<A>): JSX.Element {\n  const nodeRef = useRef<HTMLDivElement | null>(null);\n  const prevLastActionId = useRef<number | undefined>(undefined);\n\n  useLayoutEffect(() => {\n    if (nodeRef.current && prevLastActionId.current !== lastActionId) {\n      const { scrollTop, offsetHeight, scrollHeight } = nodeRef.current;\n      if (Math.abs(scrollHeight - (scrollTop + offsetHeight)) < 50) {\n        scrollToBottom(nodeRef.current);\n      }\n    }\n\n    prevLastActionId.current = lastActionId;\n  }, [lastActionId]);\n\n  const setNodeRef = useCallback((node: HTMLDivElement | null) => {\n    if (node && !nodeRef.current) {\n      scrollToBottom(node);\n    }\n\n    nodeRef.current = node;\n  }, []);\n\n  const sensors = useSensors(\n    useSensor(PointerSensor, {\n      activationConstraint: {\n        distance: 8,\n      },\n    }),\n    useSensor(KeyboardSensor, {\n      coordinateGetter: sortableKeyboardCoordinates,\n    }),\n  );\n\n  const handleDragEnd = useCallback(\n    ({ active, over }: DragEndEvent) => {\n      if (over && active.id !== over.id) {\n        const activeIndex = actionIds.indexOf(active.id as number);\n        const overIndex = actionIds.indexOf(over.id as number);\n\n        const beforeActionId =\n          overIndex < activeIndex\n            ? (over.id as number)\n            : overIndex < actionIds.length - 1\n              ? actionIds[overIndex + 1]\n              : actionIds.length;\n\n        onReorderAction(active.id as number, beforeActionId);\n      }\n    },\n    [actionIds, onReorderAction],\n  );\n\n  const lowerSearchValue = searchValue && searchValue.toLowerCase();\n  const filteredActionIds = searchValue\n    ? actionIds.filter((id) =>\n        actions[id].action.type\n          .toLowerCase()\n          .includes(lowerSearchValue as string),\n      )\n    : actionIds;\n\n  return (\n    <div\n      key=\"actionList\"\n      data-testid=\"actionList\"\n      css={[\n        (theme) => ({\n          flexBasis: '40%',\n          flexShrink: 0,\n          overflowX: 'hidden',\n          overflowY: 'auto',\n          borderBottomWidth: '3px',\n          borderBottomStyle: 'double',\n          display: 'flex',\n          flexDirection: 'column',\n\n          backgroundColor: theme.BACKGROUND_COLOR,\n          borderColor: theme.LIST_BORDER_COLOR,\n        }),\n        isWideLayout && {\n          flexBasis: '40%',\n          borderBottom: 'none',\n          borderRightWidth: '3px',\n          borderRightStyle: 'double',\n        },\n      ]}\n    >\n      <ActionListHeader\n        onSearch={onSearch}\n        onCommit={onCommit}\n        onSweep={onSweep}\n        hideMainButtons={hideMainButtons}\n        hasSkippedActions={skippedActionIds.length > 0}\n        hasStagedActions={actionIds.length > 1}\n        searchValue={searchValue}\n      />\n      <div\n        data-testid=\"actionListRows\"\n        css={{ overflow: 'auto' }}\n        ref={setNodeRef}\n      >\n        <DndContext\n          sensors={sensors}\n          collisionDetection={closestCenter}\n          onDragEnd={handleDragEnd}\n          modifiers={[restrictToFirstScrollableAncestor]}\n        >\n          <SortableContext\n            items={filteredActionIds}\n            strategy={verticalListSortingStrategy}\n          >\n            {filteredActionIds.map((actionId) => (\n              <SortableItem key={actionId} actionId={actionId}>\n                <ActionListRow\n                  actionId={actionId}\n                  isInitAction={!actionId}\n                  isSelected={\n                    (startActionId !== null &&\n                      actionId >= startActionId &&\n                      actionId <= (selectedActionId as number)) ||\n                    actionId === selectedActionId\n                  }\n                  isInFuture={\n                    actionIds.indexOf(actionId) >\n                    actionIds.indexOf(currentActionId)\n                  }\n                  onSelect={(e: React.MouseEvent<HTMLDivElement>) =>\n                    onSelect(e, actionId)\n                  }\n                  timestamps={getTimestamps(actions, actionIds, actionId)}\n                  action={actions[actionId].action}\n                  onToggleClick={() => onToggleAction(actionId)}\n                  onJumpClick={() => onJumpToState(actionId)}\n                  onCommitClick={() => onCommit()}\n                  hideActionButtons={hideActionButtons}\n                  isSkipped={skippedActionIds.includes(actionId)}\n                />\n              </SortableItem>\n            ))}\n          </SortableContext>\n        </DndContext>\n      </div>\n    </div>\n  );\n}\n\ninterface SortableItemProps {\n  readonly children: ReactNode;\n  readonly actionId: number;\n}\n\nfunction SortableItem({ children, actionId }: SortableItemProps) {\n  const { attributes, listeners, setNodeRef, transform, transition } =\n    useSortable({ id: actionId });\n\n  const style = {\n    transform: CSS.Transform.toString(transform),\n    transition,\n  };\n\n  return (\n    <div ref={setNodeRef} style={style} {...attributes} {...listeners}>\n      {children}\n    </div>\n  );\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/ActionListHeader.tsx",
    "content": "import React, { FunctionComponent } from 'react';\nimport RightSlider from './RightSlider.js';\nimport {\n  selectorButtonCss,\n  selectorButtonSmallCss,\n} from './utils/selectorButtonStyles.js';\n\nconst getActiveButtons = (hasSkippedActions: boolean): ('Sweep' | 'Commit')[] =>\n  [hasSkippedActions && 'Sweep', 'Commit'].filter(\n    (a): a is 'Sweep' | 'Commit' => !!a,\n  );\n\ninterface Props {\n  onSearch: (value: string) => void;\n  onCommit: () => void;\n  onSweep: () => void;\n  hideMainButtons: boolean | undefined;\n  hasSkippedActions: boolean;\n  hasStagedActions: boolean;\n  searchValue: string | undefined;\n}\n\nconst ActionListHeader: FunctionComponent<Props> = ({\n  onSearch,\n  hasSkippedActions,\n  hasStagedActions,\n  onCommit,\n  onSweep,\n  hideMainButtons,\n  searchValue,\n}) => (\n  <div\n    css={(theme) => ({\n      display: 'flex',\n      flex: '0 0 auto',\n      alignItems: 'center',\n      borderBottomWidth: '1px',\n      borderBottomStyle: 'solid',\n\n      borderColor: theme.LIST_BORDER_COLOR,\n    })}\n  >\n    <input\n      css={(theme) => ({\n        outline: 'none',\n        border: 'none',\n        width: '100%',\n        padding: '5px 10px',\n        fontSize: '1em',\n        fontFamily: 'monaco, Consolas, \"Lucida Console\", monospace',\n\n        backgroundColor: theme.BACKGROUND_COLOR,\n        color: theme.TEXT_COLOR,\n\n        '&::-webkit-input-placeholder': {\n          color: theme.TEXT_PLACEHOLDER_COLOR,\n        },\n\n        '&::-moz-placeholder': {\n          color: theme.TEXT_PLACEHOLDER_COLOR,\n        },\n      })}\n      onChange={(e) => onSearch(e.target.value)}\n      placeholder=\"filter...\"\n      value={searchValue}\n    />\n    {!hideMainButtons && (\n      <div css={{ position: 'relative', height: '20px' }}>\n        <RightSlider shown={hasStagedActions}>\n          <div css={{ display: 'inline-flex', marginRight: '10px' }}>\n            {getActiveButtons(hasSkippedActions).map((btn) => (\n              <div\n                key={btn}\n                onClick={() =>\n                  ({\n                    Commit: onCommit,\n                    Sweep: onSweep,\n                  })[btn]()\n                }\n                css={[selectorButtonCss, selectorButtonSmallCss]}\n              >\n                {btn}\n              </div>\n            ))}\n          </div>\n        </RightSlider>\n      </div>\n    )}\n  </div>\n);\n\nexport default ActionListHeader;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/ActionListRow.tsx",
    "content": "import React, { MouseEvent, MouseEventHandler, PureComponent } from 'react';\nimport dateformat from 'dateformat';\nimport type { DebouncedFunc } from 'lodash';\nimport debounce from 'lodash.debounce';\nimport { Action } from 'redux';\nimport type { Interpolation, Theme } from '@emotion/react';\nimport type { JSX } from '@emotion/react/jsx-runtime';\nimport RightSlider from './RightSlider.js';\nimport {\n  selectorButtonCss,\n  selectorButtonSelectedCss,\n  selectorButtonSmallCss,\n} from './utils/selectorButtonStyles.js';\n\nconst BUTTON_SKIP = 'Skip';\nconst BUTTON_JUMP = 'Jump';\n\ntype Button = typeof BUTTON_SKIP | typeof BUTTON_JUMP;\n\nconst actionListItemTimeCss: Interpolation<Theme> = (theme) => ({\n  display: 'inline',\n  padding: '4px 6px',\n  borderRadius: '3px',\n  fontSize: '0.8em',\n  lineHeight: '1em',\n  flexShrink: 0,\n\n  backgroundColor: theme.ACTION_TIME_BACK_COLOR,\n  color: theme.ACTION_TIME_COLOR,\n});\n\ninterface Props<A extends Action<string>> {\n  actionId: number;\n  isInitAction: boolean;\n  isSelected: boolean;\n  isInFuture: boolean;\n  onSelect: MouseEventHandler<HTMLDivElement>;\n  timestamps: { current: number; previous: number };\n  action: A;\n  onToggleClick: () => void;\n  onJumpClick: () => void;\n  onCommitClick: () => void;\n  hideActionButtons: boolean | undefined;\n  isSkipped: boolean;\n}\n\ninterface State {\n  hover: boolean;\n}\n\nexport default class ActionListRow<\n  A extends Action<string>,\n> extends PureComponent<Props<A>, State> {\n  state: State = { hover: false };\n\n  render(): JSX.Element {\n    const {\n      isSelected,\n      action,\n      actionId,\n      isInitAction,\n      onSelect,\n      timestamps,\n      isSkipped,\n      isInFuture,\n      hideActionButtons,\n    } = this.props;\n    const { hover } = this.state;\n    const timeDelta = timestamps.current - timestamps.previous;\n    const showButtons = (hover && !isInitAction) || isSkipped;\n\n    const isButtonSelected = (btn: Button) => btn === BUTTON_SKIP && isSkipped;\n\n    let actionType = action.type;\n    if (typeof actionType === 'undefined') actionType = '<UNDEFINED>';\n    else if (actionType === null) actionType = '<NULL>';\n    else actionType = actionType.toString() || '<EMPTY>';\n\n    return (\n      <div\n        onClick={onSelect}\n        onMouseEnter={\n          (!hideActionButtons &&\n            this.handleMouseEnter) as MouseEventHandler<HTMLDivElement>\n        }\n        onMouseLeave={\n          (!hideActionButtons &&\n            this.handleMouseLeave) as MouseEventHandler<HTMLDivElement>\n        }\n        onMouseDown={this.handleMouseDown}\n        onMouseUp={this.handleMouseEnter}\n        data-id={actionId}\n        css={[\n          (theme) => ({\n            borderBottomWidth: '1px',\n            borderBottomStyle: 'solid',\n            display: 'flex',\n            justifyContent: 'space-between',\n            padding: '5px 10px',\n            cursor: 'pointer',\n            userSelect: 'none',\n\n            borderBottomColor: theme.BORDER_COLOR,\n          }),\n          isSelected &&\n            ((theme) => ({\n              backgroundColor: theme.SELECTED_BACKGROUND_COLOR,\n            })),\n          isSkipped &&\n            ((theme) => ({\n              backgroundColor: theme.SKIPPED_BACKGROUND_COLOR,\n            })),\n          isInFuture && { opacity: '0.6' },\n        ]}\n      >\n        <div\n          css={[\n            {\n              overflow: 'hidden',\n              textOverflow: 'ellipsis',\n              lineHeight: '20px',\n            },\n            isSkipped && { textDecoration: 'line-through', opacity: 0.3 },\n          ]}\n        >\n          {actionType}\n        </div>\n        {hideActionButtons ? (\n          <RightSlider shown>\n            <div css={actionListItemTimeCss}>\n              {timeDelta === 0\n                ? '+00:00:00'\n                : dateformat(\n                    timeDelta,\n                    timestamps.previous ? '+MM:ss.L' : 'h:MM:ss.L',\n                  )}\n            </div>\n          </RightSlider>\n        ) : (\n          <div css={{ position: 'relative', height: '20px', display: 'flex' }}>\n            <RightSlider shown={!showButtons} rotate>\n              <div css={actionListItemTimeCss}>\n                {timeDelta === 0\n                  ? '+00:00:00'\n                  : dateformat(\n                      timeDelta,\n                      timestamps.previous ? '+MM:ss.L' : 'h:MM:ss.L',\n                    )}\n              </div>\n            </RightSlider>\n            <RightSlider shown={showButtons} rotate>\n              <div css={{ display: 'inline-flex' }}>\n                {([BUTTON_JUMP, BUTTON_SKIP] as const).map(\n                  (btn) =>\n                    (!isInitAction || btn !== BUTTON_SKIP) && (\n                      <div\n                        key={btn}\n                        onClick={(e) => this.handleButtonClick(btn, e)}\n                        css={[\n                          selectorButtonCss,\n                          isButtonSelected(btn) && selectorButtonSelectedCss,\n                          selectorButtonSmallCss,\n                        ]}\n                        data-isselectorbutton={true}\n                      >\n                        {btn}\n                      </div>\n                    ),\n                )}\n              </div>\n            </RightSlider>\n          </div>\n        )}\n      </div>\n    );\n  }\n\n  handleButtonClick(btn: Button, e: MouseEvent<HTMLDivElement>) {\n    e.stopPropagation();\n\n    switch (btn) {\n      case BUTTON_SKIP:\n        this.props.onToggleClick();\n        break;\n      case BUTTON_JUMP:\n        this.props.onJumpClick();\n        break;\n    }\n  }\n\n  handleMouseEnter = (e: MouseEvent<HTMLDivElement>) => {\n    if (this.state.hover) return;\n    this.handleMouseLeave.cancel();\n    this.handleMouseEnterDebounced(e.buttons);\n  };\n\n  handleMouseEnterDebounced: DebouncedFunc<(buttons: number) => void> =\n    debounce((buttons) => {\n      if (buttons) return;\n      this.setState({ hover: true });\n    }, 150);\n\n  handleMouseLeave: DebouncedFunc<() => void> = debounce(() => {\n    this.handleMouseEnterDebounced.cancel();\n    if (this.state.hover) this.setState({ hover: false });\n  }, 100);\n\n  handleMouseDown = (e: MouseEvent<HTMLDivElement>) => {\n    if ((e.target as HTMLElement).dataset.isselectorbutton) return;\n    this.handleMouseLeave();\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/ActionPreview.tsx",
    "content": "import React, { Component } from 'react';\nimport type { Base16Theme } from 'react-base16-styling';\nimport { Action } from 'redux';\nimport type { LabelRenderer } from 'react-json-tree';\nimport { PerformAction } from '@redux-devtools/core';\nimport type { Delta } from 'jsondiffpatch';\nimport type { JSX } from '@emotion/react/jsx-runtime';\nimport { DEFAULT_STATE, DevtoolsInspectorState } from './redux.js';\nimport ActionPreviewHeader from './ActionPreviewHeader.js';\nimport DiffTab from './tabs/DiffTab.js';\nimport StateTab from './tabs/StateTab.js';\nimport ActionTab from './tabs/ActionTab.js';\n\nexport interface TabComponentProps<S, A extends Action<string>> {\n  labelRenderer: LabelRenderer;\n  computedStates: { state: S; error?: string }[];\n  actions: { [actionId: number]: PerformAction<A> };\n  selectedActionId: number | null;\n  startActionId: number | null;\n  base16Theme: Base16Theme;\n  invertTheme: boolean;\n  isWideLayout: boolean;\n  sortStateTreeAlphabetically: boolean;\n  disableStateTreeCollection: boolean;\n  dataTypeKey: string | symbol | undefined;\n  delta: Delta | null | undefined | false;\n  action: A;\n  nextState: S;\n  monitorState: DevtoolsInspectorState;\n  updateMonitorState: (monitorState: Partial<DevtoolsInspectorState>) => void;\n}\n\nexport interface Tab<S, A extends Action<string>> {\n  name: string;\n  component: React.ComponentType<TabComponentProps<S, A>>;\n}\n\nconst DEFAULT_TABS = [\n  {\n    name: 'Action',\n    component: ActionTab,\n  },\n  {\n    name: 'Diff',\n    component: DiffTab,\n  },\n  {\n    name: 'State',\n    component: StateTab,\n  },\n];\n\ninterface Props<S, A extends Action<string>> {\n  base16Theme: Base16Theme;\n  invertTheme: boolean;\n  isWideLayout: boolean;\n  tabs: Tab<S, A>[] | ((tabs: Tab<S, A>[]) => Tab<S, A>[]);\n  tabName: string;\n  delta: Delta | null | undefined | false;\n  error: string | undefined;\n  nextState: S;\n  computedStates: { state: S; error?: string }[];\n  action: A;\n  actions: { [actionId: number]: PerformAction<A> };\n  selectedActionId: number | null;\n  startActionId: number | null;\n  dataTypeKey: string | symbol | undefined;\n  monitorState: DevtoolsInspectorState;\n  updateMonitorState: (monitorState: Partial<DevtoolsInspectorState>) => void;\n  onInspectPath: (path: (string | number)[]) => void;\n  inspectedPath: (string | number)[];\n  onSelectTab: (tabName: string) => void;\n  sortStateTreeAlphabetically: boolean;\n  disableStateTreeCollection: boolean;\n}\n\nclass ActionPreview<S, A extends Action<string>> extends Component<\n  Props<S, A>\n> {\n  static defaultProps = {\n    tabName: DEFAULT_STATE.tabName,\n  };\n\n  render(): JSX.Element {\n    const {\n      delta,\n      error,\n      nextState,\n      onInspectPath,\n      inspectedPath,\n      tabName,\n      isWideLayout,\n      onSelectTab,\n      action,\n      actions,\n      selectedActionId,\n      startActionId,\n      computedStates,\n      base16Theme,\n      invertTheme,\n      tabs,\n      dataTypeKey,\n      monitorState,\n      updateMonitorState,\n      sortStateTreeAlphabetically,\n      disableStateTreeCollection,\n    } = this.props;\n\n    const renderedTabs: Tab<S, A>[] =\n      typeof tabs === 'function'\n        ? tabs(DEFAULT_TABS as Tab<S, A>[])\n        : tabs\n          ? tabs\n          : (DEFAULT_TABS as Tab<S, A>[]);\n\n    const { component: TabComponent } =\n      renderedTabs.find((tab) => tab.name === tabName) ||\n      renderedTabs.find((tab) => tab.name === DEFAULT_STATE.tabName)!;\n\n    return (\n      <div\n        key=\"actionPreview\"\n        css={(theme) => ({\n          flex: 1,\n          display: 'flex',\n          flexDirection: 'column',\n          flexGrow: 1,\n          overflowY: 'hidden',\n\n          '& pre': {\n            border: 'inherit',\n            borderRadius: '3px',\n            lineHeight: 'inherit',\n            color: 'inherit',\n          },\n\n          backgroundColor: theme.BACKGROUND_COLOR,\n        })}\n      >\n        <ActionPreviewHeader\n          tabs={renderedTabs as unknown as Tab<unknown, Action<string>>[]}\n          {...{ inspectedPath, onInspectPath, tabName, onSelectTab }}\n        />\n        {!error && (\n          <div key=\"actionPreviewContent\" css={{ flex: 1, overflowY: 'auto' }}>\n            <TabComponent\n              labelRenderer={this.labelRenderer}\n              {...{\n                computedStates,\n                actions,\n                selectedActionId,\n                startActionId,\n                base16Theme,\n                invertTheme,\n                isWideLayout,\n                sortStateTreeAlphabetically,\n                disableStateTreeCollection,\n                dataTypeKey,\n                delta,\n                action,\n                nextState,\n                monitorState,\n                updateMonitorState,\n              }}\n            />\n          </div>\n        )}\n        {error && (\n          <div\n            css={(theme) => ({\n              padding: '10px',\n              marginLeft: '14px',\n              fontWeight: 'bold',\n\n              color: theme.ERROR_COLOR,\n            })}\n          >\n            {error}\n          </div>\n        )}\n      </div>\n    );\n  }\n\n  labelRenderer: LabelRenderer = ([key, ...rest], nodeType, expanded) => {\n    const { onInspectPath, inspectedPath } = this.props;\n\n    return (\n      <span>\n        <span>{key}</span>\n        <span\n          css={(theme) => ({\n            fontSize: '0.7em',\n            paddingLeft: '5px',\n            cursor: 'pointer',\n            '&:hover': {\n              textDecoration: 'underline',\n            },\n\n            color: theme.PIN_COLOR,\n          })}\n          onClick={() =>\n            onInspectPath([\n              ...inspectedPath.slice(0, inspectedPath.length - 1),\n              ...[key, ...rest].reverse(),\n            ])\n          }\n        >\n          {'(pin)'}\n        </span>\n        {!expanded && ': '}\n      </span>\n    );\n  };\n}\n\nexport default ActionPreview;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/ActionPreviewHeader.tsx",
    "content": "import React, { FunctionComponent } from 'react';\nimport { Action } from 'redux';\nimport { css } from '@emotion/react';\nimport type { Interpolation, Theme } from '@emotion/react';\nimport { Tab } from './ActionPreview.js';\nimport {\n  selectorButtonCss,\n  selectorButtonSelectedCss,\n} from './utils/selectorButtonStyles.js';\n\nconst inspectedPathKeyCss = css({\n  '&:not(:last-child):after': {\n    content: '\" > \"',\n  },\n});\n\nconst inspectedPathKeyLinkCss: Interpolation<Theme> = (theme) => ({\n  cursor: 'pointer',\n  color: theme.LINK_COLOR,\n  '&:hover': {\n    textDecoration: 'underline',\n    color: theme.LINK_HOVER_COLOR,\n  },\n});\n\ninterface Props<S, A extends Action<string>> {\n  tabs: Tab<S, A>[];\n  inspectedPath: (string | number)[];\n  onInspectPath: (path: (string | number)[]) => void;\n  tabName: string;\n  onSelectTab: (tabName: string) => void;\n}\n\nconst ActionPreviewHeader: FunctionComponent<\n  Props<unknown, Action<string>>\n> = ({ inspectedPath, onInspectPath, tabName, onSelectTab, tabs }) => (\n  <div\n    key=\"previewHeader\"\n    css={(theme) => ({\n      flex: '0 0 30px',\n      padding: '5px 10px',\n      alignItems: 'center',\n      borderBottomWidth: '1px',\n      borderBottomStyle: 'solid',\n\n      backgroundColor: theme.HEADER_BACKGROUND_COLOR,\n      borderBottomColor: theme.HEADER_BORDER_COLOR,\n    })}\n  >\n    <div css={{ position: 'relative', display: 'inline-flex', float: 'right' }}>\n      {tabs.map((tab) => (\n        <div\n          onClick={() => onSelectTab(tab.name)}\n          key={tab.name}\n          css={[\n            selectorButtonCss,\n            tab.name === tabName && selectorButtonSelectedCss,\n          ]}\n        >\n          {tab.name}\n        </div>\n      ))}\n    </div>\n    <div css={{ padding: '6px 0' }}>\n      {inspectedPath.length ? (\n        <span css={inspectedPathKeyCss}>\n          <a onClick={() => onInspectPath([])} css={inspectedPathKeyLinkCss}>\n            {tabName}\n          </a>\n        </span>\n      ) : (\n        tabName\n      )}\n      {inspectedPath.map((key, idx) =>\n        idx === inspectedPath.length - 1 ? (\n          <span key={key}>{key}</span>\n        ) : (\n          <span key={key} css={inspectedPathKeyCss}>\n            <a\n              onClick={() => onInspectPath(inspectedPath.slice(0, idx + 1))}\n              css={inspectedPathKeyLinkCss}\n            >\n              {key}\n            </a>\n          </span>\n        ),\n      )}\n    </div>\n  </div>\n);\n\nexport default ActionPreviewHeader;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/DevtoolsInspector.tsx",
    "content": "import React, { PureComponent } from 'react';\nimport type { Base16Theme } from 'react-base16-styling';\nimport {\n  ActionCreators,\n  LiftedAction,\n  LiftedState,\n} from '@redux-devtools/core';\nimport { Action, Dispatch } from 'redux';\nimport type { Delta, DiffContext } from 'jsondiffpatch';\nimport {\n  createInspectorMonitorThemeFromBase16Theme,\n  resolveBase16Theme,\n} from './utils/themes.js';\nimport type { Base16ThemeName } from './utils/themes.js';\nimport ActionList from './ActionList.js';\nimport ActionPreview, { Tab } from './ActionPreview.js';\nimport getInspectedState from './utils/getInspectedState.js';\nimport createDiffPatcher from './createDiffPatcher.js';\nimport {\n  DevtoolsInspectorAction,\n  DevtoolsInspectorState,\n  reducer,\n  updateMonitorState,\n} from './redux.js';\nimport { ThemeProvider } from '@emotion/react';\n\nconst {\n  commit,\n  sweep,\n  toggleAction,\n  jumpToAction,\n  jumpToState,\n  reorderAction,\n} = ActionCreators;\n\nfunction getLastActionId<S, A extends Action<string>>(\n  props: DevtoolsInspectorProps<S, A>,\n) {\n  return props.stagedActionIds[props.stagedActionIds.length - 1];\n}\n\nfunction getCurrentActionId<S, A extends Action<string>>(\n  props: DevtoolsInspectorProps<S, A>,\n  monitorState: DevtoolsInspectorState,\n) {\n  return monitorState.selectedActionId === null\n    ? props.stagedActionIds[props.currentStateIndex]\n    : monitorState.selectedActionId;\n}\n\nfunction getFromState<S>(\n  actionIndex: number,\n  stagedActionIds: number[],\n  computedStates: { state: S; error?: string }[],\n  monitorState: DevtoolsInspectorState,\n) {\n  const { startActionId } = monitorState;\n  if (startActionId === null) {\n    return actionIndex > 0 ? computedStates[actionIndex - 1] : null;\n  }\n  let fromStateIdx = stagedActionIds.indexOf(startActionId - 1);\n  if (fromStateIdx === -1) fromStateIdx = 0;\n  return computedStates[fromStateIdx];\n}\n\nfunction createIntermediateState<S, A extends Action<string>>(\n  props: DevtoolsInspectorProps<S, A>,\n  monitorState: DevtoolsInspectorState,\n) {\n  const {\n    supportImmutable,\n    computedStates,\n    stagedActionIds,\n    actionsById: actions,\n    diffObjectHash,\n    diffPropertyFilter,\n  } = props;\n  const { inspectedStatePath, inspectedActionPath } = monitorState;\n  const currentActionId = getCurrentActionId(props, monitorState);\n  const currentAction =\n    actions[currentActionId] && actions[currentActionId].action;\n\n  const actionIndex = stagedActionIds.indexOf(currentActionId);\n  const fromState = getFromState(\n    actionIndex,\n    stagedActionIds,\n    computedStates,\n    monitorState,\n  );\n  const toState = computedStates[actionIndex];\n  const error = toState && toState.error;\n\n  const fromInspectedState =\n    !error &&\n    fromState &&\n    getInspectedState(fromState.state, inspectedStatePath, supportImmutable);\n  const toInspectedState =\n    !error &&\n    toState &&\n    getInspectedState(toState.state, inspectedStatePath, supportImmutable);\n  const delta =\n    !error &&\n    fromState &&\n    toState &&\n    createDiffPatcher(diffObjectHash, diffPropertyFilter).diff(\n      fromInspectedState,\n      toInspectedState,\n    );\n\n  return {\n    delta,\n    nextState:\n      toState && getInspectedState(toState.state, inspectedStatePath, false),\n    action: getInspectedState(currentAction, inspectedActionPath, false),\n    error,\n  };\n}\n\nexport interface ExternalProps<S, A extends Action<string>> {\n  dispatch: Dispatch<\n    DevtoolsInspectorAction | LiftedAction<S, A, DevtoolsInspectorState>\n  >;\n  preserveScrollTop?: boolean;\n  draggableActions: boolean;\n  select: (state: S) => unknown;\n  theme: Base16ThemeName | Base16Theme;\n  supportImmutable: boolean;\n  diffObjectHash?: (item: unknown, index: number) => string;\n  diffPropertyFilter?: (name: string, context: DiffContext) => boolean;\n  hideMainButtons?: boolean;\n  hideActionButtons?: boolean;\n  invertTheme: boolean;\n  sortStateTreeAlphabetically: boolean;\n  disableStateTreeCollection: boolean;\n  dataTypeKey?: string | symbol;\n  tabs: Tab<S, A>[] | ((tabs: Tab<S, A>[]) => Tab<S, A>[]);\n}\n\ninterface DefaultProps {\n  select: (state: unknown) => unknown;\n  supportImmutable: boolean;\n  draggableActions: boolean;\n  theme: Base16ThemeName;\n  invertTheme: boolean;\n}\n\nexport interface DevtoolsInspectorProps<\n  S,\n  A extends Action<string>,\n> extends LiftedState<S, A, DevtoolsInspectorState> {\n  dispatch: Dispatch<\n    DevtoolsInspectorAction | LiftedAction<S, A, DevtoolsInspectorState>\n  >;\n  preserveScrollTop?: boolean;\n  draggableActions: boolean;\n  select: (state: S) => unknown;\n  theme: Base16ThemeName | Base16Theme;\n  supportImmutable: boolean;\n  diffObjectHash?: (item: unknown, index: number | undefined) => string;\n  diffPropertyFilter?: (name: string, context: DiffContext) => boolean;\n  hideMainButtons?: boolean;\n  hideActionButtons?: boolean;\n  sortStateTreeAlphabetically: boolean;\n  disableStateTreeCollection: boolean;\n  invertTheme: boolean;\n  dataTypeKey?: string | symbol;\n  tabs: Tab<S, A>[] | ((tabs: Tab<S, A>[]) => Tab<S, A>[]);\n}\n\ninterface State<S, A extends Action<string>> {\n  delta: Delta | null | undefined | false;\n  nextState: S;\n  action: A;\n  error: string | undefined;\n  isWideLayout: boolean;\n}\n\nclass DevtoolsInspector<S, A extends Action<string>> extends PureComponent<\n  DevtoolsInspectorProps<S, A>,\n  State<S, A>\n> {\n  state: State<S, A> = {\n    ...createIntermediateState(this.props, this.props.monitorState),\n    isWideLayout: false,\n  };\n\n  static update = reducer;\n\n  static defaultProps = {\n    select: (state: unknown) => state,\n    supportImmutable: false,\n    draggableActions: true,\n    theme: 'inspector',\n    invertTheme: true,\n  };\n\n  updateSizeTimeout?: number;\n  inspectorRef?: HTMLDivElement | null;\n\n  componentDidMount() {\n    this.updateSizeMode();\n    this.updateSizeTimeout = window.setInterval(\n      this.updateSizeMode.bind(this),\n      150,\n    );\n  }\n\n  componentWillUnmount() {\n    clearTimeout(this.updateSizeTimeout);\n  }\n\n  updateMonitorState = (monitorState: Partial<DevtoolsInspectorState>) => {\n    this.props.dispatch(updateMonitorState(monitorState));\n  };\n\n  updateSizeMode() {\n    const isWideLayout = this.inspectorRef!.offsetWidth > 500;\n\n    if (isWideLayout !== this.state.isWideLayout) {\n      this.setState({ isWideLayout });\n    }\n  }\n\n  UNSAFE_componentWillReceiveProps(nextProps: DevtoolsInspectorProps<S, A>) {\n    const nextMonitorState = nextProps.monitorState;\n    const monitorState = this.props.monitorState;\n\n    if (\n      getCurrentActionId(this.props, monitorState) !==\n        getCurrentActionId(nextProps, nextMonitorState) ||\n      monitorState.startActionId !== nextMonitorState.startActionId ||\n      monitorState.inspectedStatePath !== nextMonitorState.inspectedStatePath ||\n      monitorState.inspectedActionPath !==\n        nextMonitorState.inspectedActionPath ||\n      this.props.computedStates !== nextProps.computedStates ||\n      this.props.stagedActionIds !== nextProps.stagedActionIds\n    ) {\n      this.setState(createIntermediateState(nextProps, nextMonitorState));\n    }\n  }\n\n  inspectorCreateRef: React.RefCallback<HTMLDivElement> = (node) => {\n    this.inspectorRef = node;\n  };\n\n  render() {\n    const {\n      stagedActionIds: actionIds,\n      actionsById: actions,\n      computedStates,\n      draggableActions,\n      tabs,\n      theme,\n      invertTheme,\n      skippedActionIds,\n      currentStateIndex,\n      monitorState,\n      dataTypeKey,\n      hideMainButtons,\n      hideActionButtons,\n      sortStateTreeAlphabetically,\n      disableStateTreeCollection,\n    } = this.props;\n    const { selectedActionId, startActionId, searchValue, tabName } =\n      monitorState;\n    const inspectedPathType =\n      tabName === 'Action' ? 'inspectedActionPath' : 'inspectedStatePath';\n    const { isWideLayout, action, nextState, delta, error } = this.state;\n\n    const base16Theme = resolveBase16Theme(theme)!;\n    const inspectorMonitorTheme = createInspectorMonitorThemeFromBase16Theme(\n      base16Theme,\n      invertTheme,\n    );\n    return (\n      <ThemeProvider theme={inspectorMonitorTheme}>\n        <div\n          key=\"inspector\"\n          data-testid=\"inspector\"\n          ref={this.inspectorCreateRef}\n          css={[\n            (theme) => ({\n              display: 'flex',\n              flexDirection: 'column',\n              width: '100%',\n              height: '100%',\n              fontFamily: 'monaco, Consolas, \"Lucida Console\", monospace',\n              fontSize: '12px',\n              WebkitFontSmoothing: 'antialiased',\n              lineHeight: '1.5em',\n\n              backgroundColor: theme.BACKGROUND_COLOR,\n              color: theme.TEXT_COLOR,\n            }),\n            isWideLayout && { flexDirection: 'row' },\n          ]}\n        >\n          <ActionList\n            {...{\n              actions,\n              actionIds,\n              isWideLayout,\n              searchValue,\n              selectedActionId,\n              startActionId,\n              skippedActionIds,\n              draggableActions,\n              hideMainButtons,\n              hideActionButtons,\n            }}\n            onSearch={this.handleSearch}\n            onSelect={this.handleSelectAction}\n            onToggleAction={this.handleToggleAction}\n            onJumpToState={this.handleJumpToState}\n            onCommit={this.handleCommit}\n            onSweep={this.handleSweep}\n            onReorderAction={this.handleReorderAction}\n            currentActionId={actionIds[currentStateIndex]}\n            lastActionId={getLastActionId(this.props)}\n          />\n          <ActionPreview\n            {...{\n              base16Theme,\n              invertTheme,\n              isWideLayout,\n              tabs,\n              tabName,\n              delta,\n              error,\n              nextState,\n              computedStates,\n              action,\n              actions,\n              selectedActionId,\n              startActionId,\n              dataTypeKey,\n              sortStateTreeAlphabetically,\n              disableStateTreeCollection,\n            }}\n            monitorState={this.props.monitorState}\n            updateMonitorState={this.updateMonitorState}\n            onInspectPath={(path: (string | number)[]) =>\n              this.handleInspectPath(inspectedPathType, path)\n            }\n            inspectedPath={monitorState[inspectedPathType]}\n            onSelectTab={this.handleSelectTab}\n          />\n        </div>\n      </ThemeProvider>\n    );\n  }\n\n  handleToggleAction = (actionId: number) => {\n    this.props.dispatch(toggleAction(actionId));\n  };\n\n  handleJumpToState = (actionId: number) => {\n    if (jumpToAction) {\n      this.props.dispatch(jumpToAction(actionId));\n    } else {\n      // Fallback for redux-devtools-instrument < 1.5\n      const index = this.props.stagedActionIds.indexOf(actionId);\n      if (index !== -1) this.props.dispatch(jumpToState(index));\n    }\n  };\n\n  handleReorderAction = (actionId: number, beforeActionId: number) => {\n    if (reorderAction)\n      this.props.dispatch(reorderAction(actionId, beforeActionId));\n  };\n\n  handleCommit = () => {\n    this.props.dispatch(commit());\n  };\n\n  handleSweep = () => {\n    this.props.dispatch(sweep());\n  };\n\n  handleSearch = (val: string) => {\n    this.updateMonitorState({ searchValue: val });\n  };\n\n  handleSelectAction = (\n    e: React.MouseEvent<HTMLDivElement>,\n    actionId: number,\n  ) => {\n    const { monitorState } = this.props;\n    let startActionId;\n    let selectedActionId;\n\n    if (e.shiftKey && monitorState.selectedActionId !== null) {\n      if (monitorState.startActionId !== null) {\n        if (actionId >= monitorState.startActionId) {\n          startActionId = Math.min(\n            monitorState.startActionId,\n            monitorState.selectedActionId,\n          );\n          selectedActionId = actionId;\n        } else {\n          selectedActionId = Math.max(\n            monitorState.startActionId,\n            monitorState.selectedActionId,\n          );\n          startActionId = actionId;\n        }\n      } else {\n        startActionId = Math.min(actionId, monitorState.selectedActionId);\n        selectedActionId = Math.max(actionId, monitorState.selectedActionId);\n      }\n    } else {\n      startActionId = null;\n      if (\n        actionId === monitorState.selectedActionId ||\n        monitorState.startActionId !== null\n      ) {\n        selectedActionId = null;\n      } else {\n        selectedActionId = actionId;\n      }\n    }\n\n    this.updateMonitorState({ startActionId, selectedActionId });\n  };\n\n  handleInspectPath = (\n    pathType: 'inspectedActionPath' | 'inspectedStatePath',\n    path: (string | number)[],\n  ) => {\n    this.updateMonitorState({ [pathType]: path });\n  };\n\n  handleSelectTab = (tabName: string) => {\n    this.updateMonitorState({ tabName });\n  };\n}\n\nexport default DevtoolsInspector as unknown as React.ComponentType<\n  ExternalProps<unknown, Action<string>>\n> & {\n  update(\n    monitorProps: ExternalProps<unknown, Action<string>>,\n    state: DevtoolsInspectorState | undefined,\n    action: DevtoolsInspectorAction,\n  ): DevtoolsInspectorState;\n  defaultProps: DefaultProps;\n};\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/RightSlider.tsx",
    "content": "import React, { FunctionComponent } from 'react';\n\ninterface Props {\n  shown?: boolean;\n  children: React.ReactNode;\n  rotate?: boolean;\n}\n\nconst RightSlider: FunctionComponent<Props> = ({ shown, children, rotate }) => (\n  <div\n    css={[\n      {\n        WebkitFontSmoothing: 'subpixel-antialiased', // http://stackoverflow.com/a/21136111/4218591\n        position: 'absolute',\n        right: 0,\n        transform: 'translateX(150%)',\n        transition: 'transform 0.2s ease-in-out',\n      },\n      shown && {\n        position: 'static',\n        transform: 'translateX(0)',\n      },\n      rotate && {\n        transform: 'rotateX(90deg)',\n        transition: 'transform 0.2s ease-in-out 0.08s',\n      },\n      rotate &&\n        shown && {\n          transform: 'rotateX(0)',\n          transition: 'transform 0.2s ease-in-out 0.18s',\n        },\n    ]}\n  >\n    {children}\n  </div>\n);\n\nexport default RightSlider;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/createDiffPatcher.ts",
    "content": "import { DiffPatcher } from 'jsondiffpatch';\nimport type { DiffContext } from 'jsondiffpatch';\n\nconst defaultObjectHash = (obj: object, idx: number | undefined) => {\n  const o = obj as Record<string, unknown>;\n  return (\n    (o === null && '$$null') ||\n    (o && (o.id || o.id === 0) && `$$id:${JSON.stringify(o.id)}`) ||\n    (o && (o._id || o._id === 0) && `$$_id:${JSON.stringify(o._id)}`) ||\n    `$$index:${idx}`\n  );\n};\n\nconst defaultPropertyFilter = (name: string, context: DiffContext) =>\n  typeof (context.left as Record<string, unknown>)[name] !== 'function' &&\n  typeof (context.right as Record<string, unknown>)[name] !== 'function';\n\nconst defaultDiffPatcher = new DiffPatcher({\n  arrays: { detectMove: false } as {\n    detectMove: boolean;\n    includeValueOnMove: boolean;\n  },\n  objectHash: defaultObjectHash,\n  propertyFilter: defaultPropertyFilter,\n});\n\nexport default function createDiffPatcher(\n  objectHash:\n    | ((item: unknown, index: number | undefined) => string)\n    | undefined,\n  propertyFilter: ((name: string, context: DiffContext) => boolean) | undefined,\n) {\n  if (!objectHash && !propertyFilter) {\n    return defaultDiffPatcher;\n  }\n\n  return new DiffPatcher({\n    arrays: { detectMove: false } as {\n      detectMove: boolean;\n      includeValueOnMove: boolean;\n    },\n    objectHash: objectHash || defaultObjectHash,\n    propertyFilter: propertyFilter || defaultPropertyFilter,\n  });\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/index.ts",
    "content": "export type { LabelRenderer } from 'react-json-tree';\nexport {\n  default as InspectorMonitor,\n  type ExternalProps as DevtoolsInspectorProps,\n} from './DevtoolsInspector.js';\nexport type { Tab, TabComponentProps } from './ActionPreview.js';\nexport type {\n  DevtoolsInspectorAction,\n  DevtoolsInspectorState,\n} from './redux.js';\nexport type { Base16ThemeName } from './utils/themes.js';\nexport * as inspectorThemes from './themes/index.js';\nexport { default as ActionTab } from './tabs/ActionTab.js';\nexport { default as DiffTab } from './tabs/DiffTab.js';\nexport { default as StateTab } from './tabs/StateTab.js';\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/redux.ts",
    "content": "import { Action } from 'redux';\nimport { DevtoolsInspectorProps } from './DevtoolsInspector.js';\n\nconst UPDATE_MONITOR_STATE =\n  '@@redux-devtools-inspector-monitor/UPDATE_MONITOR_STATE';\n\nexport interface UpdateMonitorStateAction {\n  type: typeof UPDATE_MONITOR_STATE;\n  monitorState: Partial<DevtoolsInspectorState>;\n}\nexport function updateMonitorState(\n  monitorState: Partial<DevtoolsInspectorState>,\n): UpdateMonitorStateAction {\n  return { type: UPDATE_MONITOR_STATE, monitorState };\n}\n\nexport type DevtoolsInspectorAction = UpdateMonitorStateAction;\n\nexport interface DevtoolsInspectorState {\n  selectedActionId: number | null;\n  startActionId: number | null;\n  inspectedActionPath: (string | number)[];\n  inspectedStatePath: (string | number)[];\n  tabName: string;\n  searchValue?: string;\n}\n\nexport const DEFAULT_STATE: DevtoolsInspectorState = {\n  selectedActionId: null,\n  startActionId: null,\n  inspectedActionPath: [],\n  inspectedStatePath: [],\n  tabName: 'Diff',\n};\n\nfunction reduceUpdateState(\n  state: DevtoolsInspectorState,\n  action: DevtoolsInspectorAction,\n) {\n  return action.type === UPDATE_MONITOR_STATE\n    ? {\n        ...state,\n        ...action.monitorState,\n      }\n    : state;\n}\n\nexport function reducer<S, A extends Action<string>>(\n  props: DevtoolsInspectorProps<S, A>,\n  state = DEFAULT_STATE,\n  action: DevtoolsInspectorAction,\n) {\n  return {\n    ...reduceUpdateState(state, action),\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/tabs/ActionTab.tsx",
    "content": "import React, { FunctionComponent } from 'react';\nimport { JSONTree } from 'react-json-tree';\nimport { Action } from 'redux';\nimport getItemString from './getItemString.js';\nimport getJsonTreeTheme from './getJsonTreeTheme.js';\nimport { TabComponentProps } from '../ActionPreview.js';\n\nconst ActionTab: FunctionComponent<\n  TabComponentProps<unknown, Action<string>>\n> = ({\n  action,\n  base16Theme,\n  invertTheme,\n  labelRenderer,\n  dataTypeKey,\n  isWideLayout,\n}) => (\n  <JSONTree\n    labelRenderer={labelRenderer}\n    theme={getJsonTreeTheme(base16Theme)}\n    data={action}\n    getItemString={(type, data) =>\n      getItemString(type, data, dataTypeKey, isWideLayout)\n    }\n    invertTheme={invertTheme}\n    hideRoot\n  />\n);\n\nexport default ActionTab;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/tabs/DiffTab.tsx",
    "content": "import React, { FunctionComponent } from 'react';\nimport JSONDiff from './JSONDiff.js';\nimport { TabComponentProps } from '../ActionPreview.js';\nimport { Action } from 'redux';\n\nconst DiffTab: FunctionComponent<\n  TabComponentProps<unknown, Action<string>>\n> = ({\n  delta,\n  base16Theme,\n  invertTheme,\n  labelRenderer,\n  isWideLayout,\n  dataTypeKey,\n}) => (\n  <JSONDiff\n    {...{\n      delta,\n      base16Theme,\n      invertTheme,\n      labelRenderer,\n      isWideLayout,\n      dataTypeKey,\n    }}\n  />\n);\n\nexport default DiffTab;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/tabs/JSONDiff.tsx",
    "content": "import React, { Component } from 'react';\nimport { JSONTree } from 'react-json-tree';\nimport type { LabelRenderer, ShouldExpandNodeInitially } from 'react-json-tree';\nimport { stringify } from 'javascript-stringify';\nimport type { Delta } from 'jsondiffpatch';\nimport type { Base16Theme } from 'react-base16-styling';\nimport { css } from '@emotion/react';\nimport type { Interpolation, Theme } from '@emotion/react';\nimport type { JSX } from '@emotion/react/jsx-runtime';\nimport getItemString from './getItemString.js';\nimport getJsonTreeTheme from './getJsonTreeTheme.js';\n\nfunction stringifyAndShrink(val: any, isWideLayout?: boolean) {\n  if (val === null) {\n    return 'null';\n  }\n\n  const str = stringify(val);\n  if (typeof str === 'undefined') {\n    return 'undefined';\n  }\n\n  if (isWideLayout)\n    return str.length > 42 ? str.substr(0, 30) + '…' + str.substr(-10) : str;\n  return str.length > 22 ? `${str.substr(0, 15)}…${str.substr(-5)}` : str;\n}\n\nconst expandFirstLevel: ShouldExpandNodeInitially = (keyName, data, level) =>\n  level <= 1;\n\nfunction prepareDelta(value: any) {\n  if (value && value._t === 'a') {\n    const res: { [key: string]: any } = {};\n    for (const key in value) {\n      if (key !== '_t') {\n        if (key[0] === '_' && !value[key.substr(1)]) {\n          res[key.substr(1)] = value[key];\n        } else if (value['_' + key]) {\n          res[key] = [value['_' + key][0], value[key][0]];\n        } else if (!value['_' + key] && key[0] !== '_') {\n          res[key] = value[key];\n        }\n      }\n    }\n    return res;\n  }\n\n  return value;\n}\n\nconst diffCss: Interpolation<Theme> = (theme) => ({\n  padding: '2px 3px',\n  borderRadius: '3px',\n  position: 'relative',\n\n  color: theme.TEXT_COLOR,\n});\n\nconst diffWrapCss = css({ position: 'relative', zIndex: 1 });\n\ninterface Props {\n  delta: Delta | null | undefined | false;\n  base16Theme: Base16Theme;\n  invertTheme: boolean;\n  labelRenderer: LabelRenderer;\n  isWideLayout: boolean;\n  dataTypeKey: string | symbol | undefined;\n}\n\ninterface State {\n  data: any;\n}\n\nexport default class JSONDiff extends Component<Props, State> {\n  state: State = { data: {} };\n\n  componentDidMount() {\n    this.updateData();\n  }\n\n  componentDidUpdate(prevProps: Props) {\n    if (prevProps.delta !== this.props.delta) {\n      this.updateData();\n    }\n  }\n\n  updateData() {\n    // this magically fixes weird React error, where it can't find a node in tree\n    // if we set `delta` as JSONTree data right away\n    // https://github.com/alexkuz/redux-devtools-inspector/issues/17\n\n    this.setState({ data: this.props.delta });\n  }\n\n  render(): JSX.Element {\n    const { base16Theme, ...props } = this.props;\n\n    if (!this.state.data) {\n      return (\n        <div\n          css={(theme) => ({\n            padding: '10px',\n            color: theme.TEXT_PLACEHOLDER_COLOR,\n          })}\n        >\n          (states are equal)\n        </div>\n      );\n    }\n\n    return (\n      <JSONTree\n        {...props}\n        theme={getJsonTreeTheme(base16Theme)}\n        data={this.state.data}\n        getItemString={this.getItemString}\n        valueRenderer={this.valueRenderer}\n        postprocessValue={prepareDelta}\n        isCustomNode={Array.isArray}\n        shouldExpandNodeInitially={expandFirstLevel}\n        hideRoot\n      />\n    );\n  }\n\n  getItemString = (type: string, data: any) =>\n    getItemString(\n      type,\n      data,\n      this.props.dataTypeKey,\n      this.props.isWideLayout,\n      true,\n    );\n\n  valueRenderer = (raw: any, value: any) => {\n    const { isWideLayout } = this.props;\n\n    if (Array.isArray(value)) {\n      switch (value.length) {\n        case 1:\n          return (\n            <span css={diffWrapCss}>\n              <span\n                key=\"diffAdd\"\n                css={[\n                  diffCss,\n                  (theme) => ({ backgroundColor: theme.DIFF_ADD_COLOR }),\n                ]}\n              >\n                {stringifyAndShrink(value[0], isWideLayout)}\n              </span>\n            </span>\n          );\n        case 2:\n          return (\n            <span css={diffWrapCss}>\n              <span\n                key=\"diffUpdateFrom\"\n                css={[\n                  diffCss,\n                  (theme) => ({\n                    textDecoration: 'line-through',\n                    backgroundColor: theme.DIFF_REMOVE_COLOR,\n                  }),\n                ]}\n              >\n                {stringifyAndShrink(value[0], isWideLayout)}\n              </span>\n              <span\n                key=\"diffUpdateArrow\"\n                css={[diffCss, (theme) => ({ color: theme.DIFF_ARROW_COLOR })]}\n              >\n                {' => '}\n              </span>\n              <span\n                key=\"diffUpdateTo\"\n                css={[\n                  diffCss,\n                  (theme) => ({ backgroundColor: theme.DIFF_ADD_COLOR }),\n                ]}\n              >\n                {stringifyAndShrink(value[1], isWideLayout)}\n              </span>\n            </span>\n          );\n        case 3:\n          return (\n            <span css={diffWrapCss}>\n              <span\n                key=\"diffRemove\"\n                css={[\n                  diffCss,\n                  (theme) => ({\n                    textDecoration: 'line-through',\n                    backgroundColor: theme.DIFF_REMOVE_COLOR,\n                  }),\n                ]}\n              >\n                {stringifyAndShrink(value[0])}\n              </span>\n            </span>\n          );\n      }\n    }\n\n    return raw;\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/tabs/StateTab.tsx",
    "content": "import React from 'react';\nimport { JSONTree } from 'react-json-tree';\nimport { Action } from 'redux';\nimport getItemString from './getItemString.js';\nimport getJsonTreeTheme from './getJsonTreeTheme.js';\nimport { TabComponentProps } from '../ActionPreview.js';\n\nconst StateTab: React.FunctionComponent<\n  TabComponentProps<any, Action<string>>\n> = ({\n  nextState,\n  base16Theme,\n  invertTheme,\n  labelRenderer,\n  dataTypeKey,\n  isWideLayout,\n  sortStateTreeAlphabetically,\n  disableStateTreeCollection,\n}) => (\n  <JSONTree\n    labelRenderer={labelRenderer}\n    theme={getJsonTreeTheme(base16Theme)}\n    data={nextState}\n    getItemString={(type, data) =>\n      getItemString(type, data, dataTypeKey, isWideLayout)\n    }\n    invertTheme={invertTheme}\n    hideRoot\n    sortObjectKeys={sortStateTreeAlphabetically}\n    {...(disableStateTreeCollection ? { collectionLimit: 0 } : {})}\n  />\n);\n\nexport default StateTab;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/tabs/getItemString.tsx",
    "content": "import React from 'react';\nimport { isCollection, isIndexed, isKeyed } from 'immutable';\nimport type { JSX } from '@emotion/react/jsx-runtime';\nimport isIterable from '../utils/isIterable.js';\n\nconst IS_IMMUTABLE_KEY = '@@__IS_IMMUTABLE__@@';\n\nfunction isImmutable(value: any) {\n  return isKeyed(value) || isIndexed(value) || isCollection(value);\n}\n\nfunction getShortTypeString(val: any, diff: boolean | undefined) {\n  if (diff && Array.isArray(val)) {\n    val = val[val.length === 2 ? 1 : 0];\n  }\n\n  if (isIterable(val) && !isImmutable(val)) {\n    return '(…)';\n  } else if (Array.isArray(val)) {\n    return val.length > 0 ? '[…]' : '[]';\n  } else if (val === null) {\n    return 'null';\n  } else if (val === undefined) {\n    return 'undef';\n  } else if (typeof val === 'object') {\n    return Object.keys(val as object).length > 0 ? '{…}' : '{}';\n  } else if (typeof val === 'function') {\n    return 'fn';\n  } else if (typeof val === 'string') {\n    return `\"${val.substr(0, 10) + (val.length > 10 ? '…' : '')}\"`;\n  } else if (typeof val === 'symbol') {\n    return 'symbol';\n  } else {\n    return val;\n  }\n}\n\nfunction getText(\n  type: string,\n  data: any,\n  isWideLayout: boolean,\n  isDiff: boolean | undefined,\n) {\n  if (type === 'Object') {\n    const keys = Object.keys(data as object);\n    if (!isWideLayout) return keys.length ? '{…}' : '{}';\n\n    const str = keys\n      .slice(0, 3)\n      .map(\n        (key) => `${key}: ${getShortTypeString(data[key], isDiff) as string}`,\n      )\n      .concat(keys.length > 3 ? ['…'] : [])\n      .join(', ');\n\n    return `{ ${str} }`;\n  } else if (type === 'Array') {\n    if (!isWideLayout) return data.length ? '[…]' : '[]';\n\n    const str = data\n      .slice(0, 4)\n      .map((val: any) => getShortTypeString(val, isDiff))\n      .concat(data.length > 4 ? ['…'] : [])\n      .join(', ');\n\n    return `[${str as string}]`;\n  } else {\n    return type;\n  }\n}\n\nconst getItemString = (\n  type: string,\n  data: any,\n  dataTypeKey: string | symbol | undefined,\n  isWideLayout: boolean,\n  isDiff?: boolean,\n): JSX.Element => (\n  <span css={(theme) => ({ color: theme.ITEM_HINT_COLOR })}>\n    {data[IS_IMMUTABLE_KEY] ? 'Immutable' : ''}\n    {dataTypeKey && data[dataTypeKey] ? `${data[dataTypeKey] as string} ` : ''}\n    {getText(type, data, isWideLayout, isDiff)}\n  </span>\n);\n\nexport default getItemString;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/tabs/getJsonTreeTheme.ts",
    "content": "import type { Base16Theme, StylingConfig } from 'react-base16-styling';\n\nexport default function getJsonTreeTheme(\n  base16Theme: Base16Theme,\n): StylingConfig {\n  return {\n    extend: base16Theme,\n    nestedNode: ({ style }, keyPath, nodeType, expanded) => ({\n      style: {\n        ...style,\n        whiteSpace: expanded ? 'inherit' : 'nowrap',\n      },\n    }),\n    nestedNodeItemString: ({ style }, keyPath, nodeType, expanded) => ({\n      style: {\n        ...style,\n        display: expanded ? 'none' : 'inline',\n      },\n    }),\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/themes/index.ts",
    "content": "export { default as inspector } from './inspector.js';\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/themes/inspector.ts",
    "content": "export default {\n  scheme: 'inspector',\n  author: 'Alexander Kuznetsov (alexkuz@gmail.com)',\n  base00: '#181818',\n  base01: '#282828',\n  base02: '#383838',\n  base03: '#585858',\n  base04: '#b8b8b8',\n  base05: '#d8d8d8',\n  base06: '#e8e8e8',\n  base07: '#FFFFFF',\n  base08: '#E92F28',\n  base09: '#dc9656',\n  base0A: '#f7ca88',\n  base0B: '#65AD00',\n  base0C: '#86c1b9',\n  base0D: '#347BD9',\n  base0E: '#EC31C0',\n  base0F: '#a16946',\n};\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/utils/getInspectedState.ts",
    "content": "import { fromJS, isAssociative, Map } from 'immutable';\nimport isIterable from './isIterable.js';\n\nfunction iterateToKey(obj: any, key: string | number) {\n  // maybe there's a better way, dunno\n  let idx = 0;\n  for (const entry of obj) {\n    if (Array.isArray(entry)) {\n      if (entry[0] === (key as string)) return entry[1];\n    } else {\n      if (idx > (key as number)) return;\n      if (idx === (key as number)) return entry;\n    }\n    idx++;\n  }\n}\n\nexport default function getInspectedState<S>(\n  state: S,\n  path: (string | number)[],\n  convertImmutable: boolean,\n): S {\n  state =\n    path && path.length\n      ? ({\n          [path[path.length - 1]]: path.reduce((s: any, key) => {\n            if (!s) {\n              return s;\n            }\n\n            if (isAssociative(s)) {\n              return s.get(key as number);\n            } else if (isIterable(s)) {\n              return iterateToKey(s, key);\n            }\n\n            return s[key];\n          }, state),\n        } as S)\n      : state;\n\n  if (convertImmutable) {\n    try {\n      state = (fromJS(state) as Map<unknown, unknown>).toJS() as unknown as S;\n    } catch (e) {} // eslint-disable-line no-empty\n  }\n\n  return state;\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/utils/isIterable.ts",
    "content": "export default function isIterable(obj: any) {\n  return (\n    obj !== null &&\n    typeof obj === 'object' &&\n    !Array.isArray(obj) &&\n    typeof obj[window.Symbol.iterator] === 'function'\n  );\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/utils/selectorButtonStyles.ts",
    "content": "import { css } from '@emotion/react';\nimport type { Interpolation, Theme } from '@emotion/react';\n\nexport const selectorButtonCss: Interpolation<Theme> = (theme) => ({\n  cursor: 'pointer',\n  position: 'relative',\n  padding: '5px 10px',\n  borderStyle: 'solid',\n  borderWidth: '1px',\n  borderLeftWidth: 0,\n\n  '&:first-of-type': {\n    borderLeftWidth: '1px',\n    borderTopLeftRadius: '3px',\n    borderBottomLeftRadius: '3px',\n  },\n\n  '&:last-of-type': {\n    borderTopRightRadius: '3px',\n    borderBottomRightRadius: '3px',\n  },\n\n  backgroundColor: theme.TAB_BACK_COLOR,\n\n  '&:hover': {\n    backgroundColor: theme.TAB_BACK_HOVER_COLOR,\n  },\n\n  borderColor: theme.TAB_BORDER_COLOR,\n});\n\nexport const selectorButtonSmallCss = css({\n  padding: '0px 8px',\n  fontSize: '0.8em',\n});\n\nexport const selectorButtonSelectedCss: Interpolation<Theme> = (theme) => ({\n  backgroundColor: theme.TAB_BACK_SELECTED_COLOR,\n});\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/src/utils/themes.ts",
    "content": "import rgba from 'hex-rgba';\nimport type { Base16Theme } from 'react-base16-styling';\nimport { base16Themes as reduxThemes } from 'react-base16-styling';\nimport * as inspectorThemes from '../themes/index.js';\nimport { getBase16Theme, invertBase16Theme } from 'react-base16-styling';\n\nconst base16Themes = { ...reduxThemes, ...inspectorThemes };\nexport type Base16ThemeName = keyof typeof base16Themes;\n\nexport function resolveBase16Theme(theme: Base16ThemeName | Base16Theme) {\n  return getBase16Theme(theme, base16Themes);\n}\n\n/**\n * @internal\n */\ndeclare module '@emotion/react' {\n  export interface Theme {\n    TEXT_COLOR: string;\n    TEXT_PLACEHOLDER_COLOR: string;\n    BACKGROUND_COLOR: string;\n    SELECTED_BACKGROUND_COLOR: string;\n    SKIPPED_BACKGROUND_COLOR: string;\n    HEADER_BACKGROUND_COLOR: string;\n    HEADER_BORDER_COLOR: string;\n    BORDER_COLOR: string;\n    LIST_BORDER_COLOR: string;\n    ACTION_TIME_BACK_COLOR: string;\n    ACTION_TIME_COLOR: string;\n    PIN_COLOR: string;\n    ITEM_HINT_COLOR: string;\n    TAB_BACK_SELECTED_COLOR: string;\n    TAB_BACK_COLOR: string;\n    TAB_BACK_HOVER_COLOR: string;\n    TAB_BORDER_COLOR: string;\n    DIFF_ADD_COLOR: string;\n    DIFF_REMOVE_COLOR: string;\n    DIFF_ARROW_COLOR: string;\n    LINK_COLOR: string;\n    LINK_HOVER_COLOR: string;\n    ERROR_COLOR: string;\n  }\n}\n\nconst colorMap = (theme: Base16Theme) => ({\n  TEXT_COLOR: theme.base06,\n  TEXT_PLACEHOLDER_COLOR: rgba(theme.base06, 60),\n  BACKGROUND_COLOR: theme.base00,\n  SELECTED_BACKGROUND_COLOR: rgba(theme.base03, 20),\n  SKIPPED_BACKGROUND_COLOR: rgba(theme.base03, 10),\n  HEADER_BACKGROUND_COLOR: rgba(theme.base03, 30),\n  HEADER_BORDER_COLOR: rgba(theme.base03, 20),\n  BORDER_COLOR: rgba(theme.base03, 50),\n  LIST_BORDER_COLOR: rgba(theme.base03, 50),\n  ACTION_TIME_BACK_COLOR: rgba(theme.base03, 20),\n  ACTION_TIME_COLOR: theme.base04,\n  PIN_COLOR: theme.base04,\n  ITEM_HINT_COLOR: rgba(theme.base0F, 90),\n  TAB_BACK_SELECTED_COLOR: rgba(theme.base03, 20),\n  TAB_BACK_COLOR: rgba(theme.base00, 70),\n  TAB_BACK_HOVER_COLOR: rgba(theme.base03, 40),\n  TAB_BORDER_COLOR: rgba(theme.base03, 50),\n  DIFF_ADD_COLOR: rgba(theme.base0B, 40),\n  DIFF_REMOVE_COLOR: rgba(theme.base08, 40),\n  DIFF_ARROW_COLOR: theme.base0E,\n  LINK_COLOR: rgba(theme.base0E, 90),\n  LINK_HOVER_COLOR: theme.base0E,\n  ERROR_COLOR: theme.base08,\n});\n\nexport function createInspectorMonitorThemeFromBase16Theme(\n  base16Theme: Base16Theme,\n  invertTheme: boolean,\n) {\n  const finalBase16Theme = invertTheme\n    ? invertBase16Theme(base16Theme)\n    : base16Theme;\n  return colorMap(finalBase16Theme);\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\",\n    \"resolveJsonModule\": true,\n    \"jsx\": \"react-jsx\",\n    \"jsxImportSource\": \"@emotion/react\",\n    \"stripInternal\": true\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/CHANGELOG.md",
    "content": "# Change Log\n\n## 6.0.0\n\n### Major Changes\n\n- 12849a4: Convert monitors to ESM\n\n### Patch Changes\n\n- Updated dependencies [d61d31a]\n- Updated dependencies [804e729]\n- Updated dependencies [12849a4]\n  - @redux-devtools/ui@3.0.0\n  - @redux-devtools/inspector-monitor@7.0.0\n\n## 5.0.0\n\n### Major Changes\n\n- 6163276: Replace styled-components with Emotion\n\n### Patch Changes\n\n- Updated dependencies [6163276]\n- Updated dependencies [20883e5]\n  - @redux-devtools/ui@2.0.0\n  - @redux-devtools/inspector-monitor@6.1.2\n\n## 4.1.1\n\n### Patch Changes\n\n- @redux-devtools/inspector-monitor@6.1.1\n\n## 4.1.0\n\n### Minor Changes\n\n- 6830118: Add React 19 to peer deps\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - @redux-devtools/inspector-monitor@7.0.0\n  - @redux-devtools/ui@1.4.0\n\n## 4.0.0\n\n### Major Changes\n\n- 5cfe3e5: Update min required React version to 16.8.4\n\n### Patch Changes\n\n- Updated dependencies [5cfe3e5]\n  - @redux-devtools/inspector-monitor@6.0.0\n\n## 3.0.0\n\n### Major Changes\n\n- 158ba2c: Replace jss with Emotion in inspector-monitor. `@emotion/react` is now a required peer dependency.\n\n### Patch Changes\n\n- Updated dependencies [158ba2c]\n  - @redux-devtools/inspector-monitor@5.0.0\n\n## 2.1.0\n\n### Minor Changes\n\n- 6fc18ed7: Add new Redux version to peer dependencies\n\n### Patch Changes\n\n- 7f5bddbd: Widen peer dependencies\n- Updated dependencies [7f5bddbd]\n  - @redux-devtools/ui@1.3.1\n\n## 2.0.1\n\n### Patch Changes\n\n- 65205f90: Replace Action<unknown> with Action<string>\n- Updated dependencies [65205f90]\n  - @redux-devtools/inspector-monitor@4.0.1\n\n## 2.0.0\n\n### Major Changes\n\n- 57751ff9: Add react-dom peerDependency and bump react peerDependency to `^16.8.0 || ^17.0.0 || ^18.0.0`\n\n### Patch Changes\n\n- Updated dependencies [57751ff9]\n  - @redux-devtools/inspector-monitor@4.0.0\n\n## 1.0.1\n\n### Patch Changes\n\n- Updated dependencies [14a79573]\n- Updated dependencies [d54adb76]\n- Updated dependencies [bb9bd907]\n  - @redux-devtools/inspector-monitor@3.1.0\n\n## 1.0.0\n\n### Minor Changes\n\n- 8a7eae4: Add React 18 to peerDependencies range\n\n### Patch Changes\n\n- Updated dependencies [8a7eae4]\n  - @redux-devtools/inspector-monitor@3.0.0\n  - @redux-devtools/ui@1.3.0\n\n## 0.8.6\n\n### Patch Changes\n\n- @redux-devtools/inspector-monitor@2.1.2\n\n## 0.8.0\n\n- Adds ESM build (https://github.com/reduxjs/redux-devtools/pull/997) and switches the default export to a named export in order to ensure that the CommonJS output and the ESM output are [interchangeable](https://rollupjs.org/guide/en/#outputexports):\n\n```diff\n- import TestGenerator from '@redux-devtools/inspector-monitor-test-tab';\n- import mochaTemplate from '@redux-devtools/inspector-monitor-test-tab/lib/redux/mocha';\n+ import { TestTab, reduxMochaTemplate } from '@redux-devtools/inspector-monitor-test-tab';\n```\n\n## [0.7.2](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/inspector-monitor-test-tab@0.7.1...@redux-devtools/inspector-monitor-test-tab@0.7.2) (2021-06-11)\n\n### Bug Fixes\n\n- **app:** fix dependency version of inspector ([#732](https://github.com/reduxjs/redux-devtools/issues/732)) ([30c6971](https://github.com/reduxjs/redux-devtools/commit/30c6971d379c53ec1343a20240b73705751f7445))\n\n## [0.7.1](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/inspector-monitor-test-tab@0.7.0...@redux-devtools/inspector-monitor-test-tab@0.7.1) (2021-06-11)\n\n### Bug Fixes\n\n- fix peer dependencies on inpsector monitor ([#730](https://github.com/reduxjs/redux-devtools/issues/730)) ([0291f5c](https://github.com/reduxjs/redux-devtools/commit/0291f5c95e4340a3b5e30a3efe76a1a1a2bb7f5e))\n- fix Select types and usages ([#724](https://github.com/reduxjs/redux-devtools/issues/724)) ([07e409d](https://github.com/reduxjs/redux-devtools/commit/07e409de6a1c3d362929d854542df0c1d74ce18e))\n\n## [0.7.0](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/inspector-monitor-test-tab@0.6.3...@redux-devtools/inspector-monitor-test-tab@0.7.0) (2021-03-06)\n\n### Features\n\n- update peer dependencies to allow react@^17 ([#703](https://github.com/reduxjs/redux-devtools/issues/703)) ([2aaa9c1](https://github.com/reduxjs/redux-devtools/commit/2aaa9c10a383e3a7ab20b3ab14639781fd7bb2eb))\n\n## 0.6.3 (2021-03-06)\n\n**Note:** Version bump only for package @redux-devtools/inspector-monitor-test-tab\n\n## [0.6.2](https://github.com/reduxjs/redux-devtools/compare/redux-devtools-test-generator@0.6.1...redux-devtools-test-generator@0.6.2) (2020-09-07)\n\n**Note:** Version bump only for package redux-devtools-test-generator\n\n## [0.6.1](https://github.com/reduxjs/redux-devtools/compare/redux-devtools-test-generator@0.6.0...redux-devtools-test-generator@0.6.1) (2020-08-14)\n\n**Note:** Version bump only for package redux-devtools-test-generator\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 Mihail Diordiev\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/README.md",
    "content": "# Redux DevTools Test Generator\n\n### Installation\n\n```\nyarn add @redux-devtools/inspector-monitor-test-tab\n```\n\n### Usage\n\nIf you use [Redux DevTools Extension](https://github.com/zalmoxisus/redux-devtools-extension), [Remote Redux DevTools](https://github.com/zalmoxisus/remote-redux-devtools) or [RemoteDev](https://github.com/zalmoxisus/remotedev), it's already there, and no additional actions required.\n\nWith [`redux-devtools`](https://github.com/reduxjs/redux-devtools) and [`redux-devtools-inspector-monitor`](https://github.com/reduxjs/redux-devtools/packages/redux-devtools-inspector-monitor):\n\n##### `containers/DevTools.js`\n\n```js\nimport React from 'react';\nimport { createDevTools } from '@redux-devtools/core';\nimport { InspectorMonitor } from '@redux-devtools/inspector-monitor';\nimport { TestTab, reduxMochaTemplate } from '@redux-devtools/inspector-monitor-test-tab'; // If using default tests.\n\nconst testComponent = (props) => (\n  <TestTab\n    expect={reduxMochaTemplate.expect} wrap={reduxMochaTemplate.wrap} useCodemirror\n    {...props}\n  />\n);\n\nexport default createDevTools(\n  <InspectorMonitor\n    tabs: defaultTabs => [...defaultTabs, { name: 'Test', component: testComponent }]\n  />\n);\n```\n\nInstead of `mochaTemplate.expect` and `mochaTemplate.wrap` you can use your function templates.\n\nIf `useCodemirror` specified, include `codemirror/lib/codemirror.css` style and optionally themes from `codemirror/theme/`.\n\n### Props\n\n| Name              | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |\n| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `assertion`       | String template or function with an object argument containing `action`, `prevState`, `curState` keys, which returns a string representing the assertion (see the [function](https://github.com/reduxjs/redux-devtools/blob/master/packages/redux-devtools-inspector-monitor-test-tab/src/redux/mocha/index.ts#L8-L9) or [template](https://github.com/reduxjs/redux-devtools/blob/master/packages/redux-devtools-inspector-monitor-test-tab/src/redux/mocha/template.ts#L5)). |\n| [`wrap`]          | Optional string template or function which gets `assertions` argument and returns a string (see the example [function](https://github.com/reduxjs/redux-devtools/blob/master/packages/redux-devtools-inspector-monitor-test-tab/src/redux/mocha/index.ts#L11-L13) or [template](https://github.com/reduxjs/redux-devtools/blob/master/packages/redux-devtools-inspector-monitor-test-tab/src/redux/mocha/template.ts#L7-L8)).                                                  |\n| [`useCodemirror`] | Boolean. If specified will use codemirror styles.                                                                                                                                                                                                                                                                                                                                                                                                                              |\n| [`theme`]         | String. Name of [the codemirror theme](https://codemirror.net/demo/theme.html).                                                                                                                                                                                                                                                                                                                                                                                                |\n\n### License\n\nMIT\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/demo/CHANGELOG.md",
    "content": "# test-demo\n\n## 0.1.19\n\n### Patch Changes\n\n- Updated dependencies [d61d31a]\n- Updated dependencies [804e729]\n- Updated dependencies [12849a4]\n- Updated dependencies [804d6bd]\n  - @redux-devtools/ui@3.0.0\n  - @redux-devtools/dock-monitor@5.0.0\n  - @redux-devtools/inspector-monitor@7.0.0\n  - @redux-devtools/inspector-monitor-test-tab@6.0.0\n  - @redux-devtools/core@5.0.0\n\n## 0.1.18\n\n### Patch Changes\n\n- Updated dependencies [6163276]\n- Updated dependencies [20883e5]\n  - @redux-devtools/inspector-monitor-test-tab@5.0.0\n  - @redux-devtools/ui@2.0.0\n  - @redux-devtools/inspector-monitor@6.1.2\n\n## 0.1.17\n\n### Patch Changes\n\n- Updated dependencies [91f21b2]\n  - @redux-devtools/core@4.1.1\n  - @redux-devtools/dock-monitor@4.1.1\n  - @redux-devtools/inspector-monitor@6.1.1\n  - @redux-devtools/inspector-monitor-test-tab@4.1.1\n\n## 0.1.16\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - @redux-devtools/dock-monitor@5.0.0\n  - @redux-devtools/inspector-monitor-test-tab@5.0.0\n  - @redux-devtools/inspector-monitor@7.0.0\n  - @redux-devtools/ui@1.4.0\n  - @redux-devtools/core@4.1.0\n\n## 0.1.15\n\n### Patch Changes\n\n- Updated dependencies [5cfe3e5]\n- Updated dependencies [decc035]\n  - @redux-devtools/dock-monitor@4.0.0\n  - @redux-devtools/inspector-monitor-test-tab@4.0.0\n  - @redux-devtools/inspector-monitor@6.0.0\n  - @redux-devtools/core@4.0.0\n\n## 0.1.14\n\n### Patch Changes\n\n- Updated dependencies [158ba2c]\n  - @redux-devtools/inspector-monitor-test-tab@3.0.0\n  - @redux-devtools/inspector-monitor@5.0.0\n\n## 0.1.13\n\n### Patch Changes\n\n- 65205f90: Replace Action<unknown> with Action<string>\n- Updated dependencies [65205f90]\n  - @redux-devtools/dock-monitor@3.0.2\n  - @redux-devtools/inspector-monitor-test-tab@2.0.1\n  - @redux-devtools/inspector-monitor@4.0.1\n  - @redux-devtools/core@3.13.2\n\n## 0.1.12\n\n### Patch Changes\n\n- Updated dependencies [57751ff9]\n  - @redux-devtools/inspector-monitor-test-tab@2.0.0\n  - @redux-devtools/inspector-monitor@4.0.0\n\n## 0.1.11\n\n### Patch Changes\n\n- Updated dependencies [14a79573]\n- Updated dependencies [d54adb76]\n- Updated dependencies [bb9bd907]\n  - @redux-devtools/inspector-monitor@3.1.0\n  - @redux-devtools/inspector-monitor-test-tab@2.0.0\n\n## 0.1.10\n\n### Patch Changes\n\n- Updated dependencies [8a7eae4]\n  - @redux-devtools/dock-monitor@3.0.0\n  - @redux-devtools/inspector-monitor-test-tab@1.0.0\n  - @redux-devtools/inspector-monitor@3.0.0\n  - @redux-devtools/ui@1.3.0\n  - @redux-devtools/core@3.13.0\n\n## 0.1.9\n\n### Patch Changes\n\n- Updated dependencies [4891bf6]\n  - @redux-devtools/core@3.12.0\n  - @redux-devtools/dock-monitor@2.1.1\n  - @redux-devtools/inspector-monitor@2.1.2\n  - @redux-devtools/inspector-monitor-test-tab@0.8.6\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/demo/eslint.config.mjs",
    "content": "import eslintJs from '../../../eslint.js.config.base.mjs';\nimport eslintTs from '../../../eslint.ts.react.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTs(import.meta.dirname),\n  ...eslintTs(\n    import.meta.dirname,\n    ['webpack.config.ts'],\n    ['./tsconfig.webpack.json'],\n  ),\n  {\n    ignores: ['dist'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/demo/index.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />\n    <title><%= htmlWebpackPlugin.options.package.name %></title>\n    <meta\n      name=\"description\"\n      content=\"<%= htmlWebpackPlugin.options.package.description %>\"\n    />\n    <link\n      href=\"//maxcdn.bootstrapcdn.com/bootswatch/3.3.5/paper/bootstrap.min.css\"\n      rel=\"stylesheet\"\n    />\n  </head>\n  <body>\n    <div id=\"root\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/demo/package.json",
    "content": "{\n  \"private\": true,\n  \"name\": \"test-demo\",\n  \"version\": \"0.1.19\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"start\": \"cross-env TS_NODE_PROJECT=\\\"tsconfig.webpack.json\\\" webpack serve --open\",\n    \"build\": \"cross-env TS_NODE_PROJECT=\\\"tsconfig.webpack.json\\\" webpack\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\"\n  },\n  \"dependencies\": {\n    \"@emotion/react\": \"^11.14.0\",\n    \"@emotion/styled\": \"^11.14.1\",\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@redux-devtools/dock-monitor\": \"workspace:^\",\n    \"@redux-devtools/inspector-monitor\": \"workspace:^\",\n    \"@redux-devtools/inspector-monitor-test-tab\": \"workspace:^\",\n    \"@redux-devtools/ui\": \"workspace:^\",\n    \"immutable\": \"^5.1.5\",\n    \"lodash.shuffle\": \"^4.2.0\",\n    \"react\": \"^19.2.4\",\n    \"react-dom\": \"^19.2.4\",\n    \"react-is\": \"^19.2.4\",\n    \"react-redux\": \"^9.2.0\",\n    \"react-router-dom\": \"^7.13.1\",\n    \"redux\": \"^5.0.1\",\n    \"redux-logger\": \"^3.0.6\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.29.0\",\n    \"@babel/preset-env\": \"^7.29.0\",\n    \"@babel/preset-react\": \"^7.28.5\",\n    \"@babel/preset-typescript\": \"^7.28.5\",\n    \"@types/lodash.shuffle\": \"^4.2.9\",\n    \"@types/node\": \"^24.12.0\",\n    \"@types/react\": \"^19.2.14\",\n    \"@types/react-dom\": \"^19.2.3\",\n    \"@types/redux-logger\": \"^3.0.13\",\n    \"@types/webpack-env\": \"^1.18.8\",\n    \"babel-loader\": \"^10.1.1\",\n    \"cross-env\": \"^10.1.0\",\n    \"css-loader\": \"^7.1.4\",\n    \"fork-ts-checker-webpack-plugin\": \"^9.1.0\",\n    \"html-webpack-plugin\": \"^5.6.6\",\n    \"style-loader\": \"^4.0.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"~5.9.3\",\n    \"webpack\": \"^5.105.4\",\n    \"webpack-cli\": \"^7.0.0\",\n    \"webpack-dev-server\": \"^5.2.3\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/demo/src/DemoApp.tsx",
    "content": "import React, { CSSProperties, useRef } from 'react';\nimport { connect } from 'react-redux';\nimport { Button, Toolbar, Spacer } from '@redux-devtools/ui';\nimport pkg from '@redux-devtools/inspector-monitor-test-tab/package.json';\nimport { useLocation } from 'react-router-dom';\nimport getOptions from './getOptions';\nimport { DemoAppState } from './reducers';\nimport {\n  AddFunctionAction,\n  AddHugeObjectAction,\n  AddImmutableMapAction,\n  AddIteratorAction,\n  AddRecursiveAction,\n  AddSymbolAction,\n  ChangeImmutableNestedAction,\n  ChangeNestedAction,\n  HugePayloadAction,\n  IncrementAction,\n  PopAction,\n  PushAction,\n  PushHugeArrayAction,\n  ReplaceAction,\n  ShuffleArrayAction,\n  TimeoutUpdateAction,\n  ToggleTimeoutUpdateAction,\n} from './reducers';\n\nconst styles: {\n  wrapper: CSSProperties;\n  muted: CSSProperties;\n  link: CSSProperties;\n} = {\n  wrapper: {\n    height: '100vh',\n    width: '450px',\n    margin: 'auto',\n    textAlign: 'center',\n  },\n  muted: {\n    color: '#CCCCCC',\n  },\n  link: {\n    margin: '0 0.5rem',\n    cursor: 'pointer',\n    display: 'block',\n  },\n};\n\nconst ROOT = '/'; // process.env.NODE_ENV === 'production' ? '/' : '/';\n\ninterface Props extends Omit<\n  DemoAppState,\n  'addFunction' | 'addSymbol' | 'shuffleArray'\n> {\n  toggleTimeoutUpdate: (timeoutUpdateEnabled: boolean) => void;\n  timeoutUpdate: () => void;\n  increment: () => void;\n  push: () => void;\n  pop: () => void;\n  replace: () => void;\n  changeNested: () => void;\n  pushHugeArray: () => void;\n  addIterator: () => void;\n  addHugeObject: () => void;\n  addRecursive: () => void;\n  addImmutableMap: () => void;\n  changeImmutableNested: () => void;\n  hugePayload: () => void;\n  addFunction: () => void;\n  addSymbol: () => void;\n  shuffleArray: () => void;\n}\n\nfunction DemoApp(props: Props) {\n  const timeout = useRef<number | undefined>(undefined);\n  const location = useLocation();\n\n  const options = getOptions(location);\n\n  const toggleTimeoutUpdate = () => {\n    const enabled = !props.timeoutUpdateEnabled;\n    props.toggleTimeoutUpdate(enabled);\n\n    if (enabled) {\n      timeout.current = window.setInterval(props.timeoutUpdate, 1000);\n    } else {\n      clearTimeout(timeout.current);\n    }\n  };\n\n  return (\n    <div style={styles.wrapper}>\n      <h3>{pkg.name || <span style={styles.muted}>Package Name</span>}</h3>\n      <h5>\n        {pkg.description || (\n          <span style={styles.muted}>Package Description</span>\n        )}\n      </h5>\n      <Toolbar>\n        <Spacer />\n        <Button onClick={props.increment}>Increment</Button>\n        <Button onClick={props.push}>Push</Button>\n        <Button onClick={props.pop}>Pop</Button>\n        <Button onClick={props.replace}>Replace</Button>\n        <Button onClick={props.changeNested}>Change Nested</Button>\n        <Spacer />\n      </Toolbar>\n      <Toolbar>\n        <Spacer />\n        <Button onClick={props.pushHugeArray}>Push Huge Array</Button>\n        <Button onClick={props.addHugeObject}>Add Huge Object</Button>\n        <Button onClick={props.hugePayload}>Huge Payload</Button>\n        <Spacer />\n      </Toolbar>\n      <Toolbar>\n        <Spacer />\n        <Button onClick={props.addIterator}>Add Iterator</Button>\n        <Button onClick={props.addImmutableMap}>Add Immutable Map</Button>\n        <Button onClick={props.changeImmutableNested}>\n          Change Immutable Nested\n        </Button>\n        <Spacer />\n      </Toolbar>\n      <Toolbar>\n        <Spacer />\n        <Button onClick={props.addRecursive}>Add Recursive</Button>\n        <Button onClick={props.addFunction}>Add Function</Button>\n        <Button onClick={props.addSymbol}>Add Symbol</Button>\n        <Spacer />\n      </Toolbar>\n      <Toolbar>\n        <Spacer />\n        <Button onClick={toggleTimeoutUpdate}>\n          Timeout Update {props.timeoutUpdateEnabled ? 'On' : 'Off'}\n        </Button>\n        <Button onClick={props.shuffleArray}>Shuffle Array</Button>\n        <Spacer />\n      </Toolbar>\n      <div>\n        {options.useExtension ? (\n          <a href={`${ROOT}`} style={styles.link}>\n            Disable browser extension\n          </a>\n        ) : (\n          <a href={`${ROOT}?ext`} style={styles.link}>\n            Use browser extension\n          </a>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default connect((state: DemoAppState) => state, {\n  toggleTimeoutUpdate: (\n    timeoutUpdateEnabled: boolean,\n  ): ToggleTimeoutUpdateAction => ({\n    type: 'TOGGLE_TIMEOUT_UPDATE',\n    timeoutUpdateEnabled,\n  }),\n  timeoutUpdate: (): TimeoutUpdateAction => ({ type: 'TIMEOUT_UPDATE' }),\n  increment: (): IncrementAction => ({ type: 'INCREMENT' }),\n  push: (): PushAction => ({ type: 'PUSH' }),\n  pop: (): PopAction => ({ type: 'POP' }),\n  replace: (): ReplaceAction => ({ type: 'REPLACE' }),\n  changeNested: (): ChangeNestedAction => ({ type: 'CHANGE_NESTED' }),\n  pushHugeArray: (): PushHugeArrayAction => ({ type: 'PUSH_HUGE_ARRAY' }),\n  addIterator: (): AddIteratorAction => ({ type: 'ADD_ITERATOR' }),\n  addHugeObject: (): AddHugeObjectAction => ({ type: 'ADD_HUGE_OBJECT' }),\n  addRecursive: (): AddRecursiveAction => ({ type: 'ADD_RECURSIVE' }),\n  addImmutableMap: (): AddImmutableMapAction => ({ type: 'ADD_IMMUTABLE_MAP' }),\n  changeImmutableNested: (): ChangeImmutableNestedAction => ({\n    type: 'CHANGE_IMMUTABLE_NESTED',\n  }),\n  hugePayload: (): HugePayloadAction => ({\n    type: 'HUGE_PAYLOAD',\n    payload: Array.from({ length: 10000 }).map((_, i) => i),\n  }),\n  addFunction: (): AddFunctionAction => ({ type: 'ADD_FUNCTION' }),\n  addSymbol: (): AddSymbolAction => ({ type: 'ADD_SYMBOL' }),\n  shuffleArray: (): ShuffleArrayAction => ({ type: 'SHUFFLE_ARRAY' }),\n})(DemoApp);\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/demo/src/DevTools.tsx",
    "content": "import React from 'react';\nimport { createDevTools } from '@redux-devtools/core';\nimport { InspectorMonitor, Tab } from '@redux-devtools/inspector-monitor';\nimport type { Base16ThemeName } from '@redux-devtools/inspector-monitor';\nimport { DockMonitor } from '@redux-devtools/dock-monitor';\nimport { useLocation } from 'react-router-dom';\nimport getOptions from './getOptions';\nimport { TestTab } from '@redux-devtools/inspector-monitor-test-tab';\nimport { Action } from 'redux';\n\nexport const getDevTools = (location: { search: string }) =>\n  createDevTools(\n    <DockMonitor\n      defaultIsVisible\n      toggleVisibilityKey=\"ctrl-h\"\n      changePositionKey=\"ctrl-q\"\n      changeMonitorKey=\"ctrl-m\"\n    >\n      <InspectorMonitor\n        theme={getOptions(location).theme as Base16ThemeName}\n        invertTheme={!getOptions(location).dark}\n        supportImmutable={getOptions(location).supportImmutable}\n        tabs={(defaultTabs) =>\n          [\n            {\n              name: 'Test',\n              component: TestTab,\n            },\n            ...defaultTabs,\n          ] as Tab<unknown, Action<string>>[]\n        }\n      />\n    </DockMonitor>,\n  );\n\nexport function ConnectedDevTools() {\n  const location = useLocation();\n  const DevTools = getDevTools(location);\n  // eslint-disable-next-line react-hooks/static-components\n  return <DevTools />;\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/demo/src/getOptions.ts",
    "content": "export interface Options {\n  useExtension: boolean;\n  supportImmutable: boolean;\n  theme: string;\n  dark: boolean;\n}\n\nexport default function getOptions(location: { search: string }) {\n  return {\n    useExtension: location.search.includes('ext'),\n    supportImmutable: location.search.includes('immutable'),\n    theme: getTheme(location),\n    dark: location.search.includes('dark'),\n  };\n}\n\nfunction getTheme(location: { search: string }) {\n  const match = /theme=([^&]+)/.exec(location.search);\n  return match ? match[1] : 'inspector';\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/demo/src/index.tsx",
    "content": "import React from 'react';\nimport { createRoot } from 'react-dom/client';\nimport { Container } from '@redux-devtools/ui';\nimport { Provider } from 'react-redux';\nimport {\n  createStore,\n  applyMiddleware,\n  compose,\n  StoreEnhancer,\n  StoreEnhancerStoreCreator,\n} from 'redux';\nimport logger from 'redux-logger';\nimport { BrowserRouter, Route, Routes } from 'react-router-dom';\nimport { persistState } from '@redux-devtools/core';\nimport DemoApp from './DemoApp';\nimport { rootReducer } from './reducers';\nimport getOptions from './getOptions';\nimport { ConnectedDevTools, getDevTools } from './DevTools';\n\nfunction getDebugSessionKey() {\n  const matches = /[?&]debug_session=([^&#]+)\\b/.exec(window.location.href);\n  return matches && matches.length > 0 ? matches[1] : null;\n}\n\nconst ROOT =\n  process.env.NODE_ENV === 'production'\n    ? '/redux-devtools-inspector-monitor-test-tab/'\n    : '/';\n\nconst DevTools = getDevTools(window.location);\n\nconst useDevtoolsExtension =\n  !!(window as unknown as { __REDUX_DEVTOOLS_EXTENSION__: unknown }) &&\n  getOptions(window.location).useExtension;\n\nconst enhancer: StoreEnhancer = compose(\n  applyMiddleware(logger),\n  ((next) => {\n    const instrument = useDevtoolsExtension\n      ? (\n          window as unknown as {\n            __REDUX_DEVTOOLS_EXTENSION__(): StoreEnhancer;\n          }\n        ).__REDUX_DEVTOOLS_EXTENSION__()\n      : DevTools.instrument();\n    return instrument(next);\n  }) as StoreEnhancer,\n  persistState(getDebugSessionKey()),\n) as any;\n\nconst store = createStore(rootReducer, enhancer);\n\nconst root = createRoot(document.getElementById('root')!);\nroot.render(\n  <Provider store={store}>\n    <BrowserRouter>\n      <Container\n        themeData={{\n          theme: 'default',\n          scheme: 'default',\n          colorPreference: 'auto',\n        }}\n      >\n        <Routes>\n          <Route path={ROOT} element={<DemoApp />} />\n        </Routes>\n        {!useDevtoolsExtension && <ConnectedDevTools />}\n      </Container>\n    </BrowserRouter>\n  </Provider>,\n);\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/demo/src/reducers.ts",
    "content": "import {\n  fromJS,\n  Map as ImmutableMap,\n  List,\n  Set as ImmutableSet,\n  Stack,\n  Seq,\n} from 'immutable';\nimport shuffle from 'lodash.shuffle';\nimport { combineReducers, Reducer } from 'redux';\n\ntype Nested = { long: { nested: { path: { to: { a: string } } }[] } };\n\nconst NESTED = {\n  long: {\n    nested: [\n      {\n        path: {\n          to: {\n            a: 'key',\n          },\n        },\n      },\n    ],\n  },\n};\n\nconst IMMUTABLE_NESTED = fromJS(NESTED) as ImmutableMap<unknown, unknown>;\n\nconst IMMUTABLE_MAP = ImmutableMap({\n  map: ImmutableMap({ a: 1, b: 2, c: 3 }),\n  list: List(['a', 'b', 'c']),\n  set: ImmutableSet(['a', 'b', 'c']),\n  stack: Stack(['a', 'b', 'c']),\n  seq: Seq([1, 2, 3, 4, 5, 6, 7, 8]),\n});\n\nconst HUGE_ARRAY = Array.from({ length: 5000 }).map((_, key) => ({\n  str: `key ${key}`,\n}));\n\nconst HUGE_OBJECT = Array.from({ length: 5000 }).reduce(\n  (o: { [key: string]: string }, _, key) => (\n    (o[`key ${key}`] = `item ${key}`),\n    o\n  ),\n  {},\n);\n\nconst FUNC = function (a: number, b: number, c: number) {\n  return a + b + c;\n};\n\nconst RECURSIVE: { obj?: unknown } = {};\nRECURSIVE.obj = RECURSIVE;\n\nfunction createIterator() {\n  const iterable: { [Symbol.iterator](): IterableIterator<string> } = {\n    [Symbol.iterator]: function* iterator() {\n      for (let i = 0; i < 333; i++) {\n        yield `item ${i}`;\n      }\n    },\n  };\n\n  return iterable;\n}\n\nconst DEFAULT_SHUFFLE_ARRAY = [0, 1, null, { id: 1 }, { id: 2 }, 'string'];\n\nexport interface ToggleTimeoutUpdateAction {\n  type: 'TOGGLE_TIMEOUT_UPDATE';\n  timeoutUpdateEnabled: boolean;\n}\nexport interface TimeoutUpdateAction {\n  type: 'TIMEOUT_UPDATE';\n}\nexport interface IncrementAction {\n  type: 'INCREMENT';\n}\nexport interface PushAction {\n  type: 'PUSH';\n}\nexport interface PopAction {\n  type: 'POP';\n}\nexport interface ReplaceAction {\n  type: 'REPLACE';\n}\nexport interface ChangeNestedAction {\n  type: 'CHANGE_NESTED';\n}\nexport interface PushHugeArrayAction {\n  type: 'PUSH_HUGE_ARRAY';\n}\nexport interface AddIteratorAction {\n  type: 'ADD_ITERATOR';\n}\nexport interface AddHugeObjectAction {\n  type: 'ADD_HUGE_OBJECT';\n}\nexport interface AddRecursiveAction {\n  type: 'ADD_RECURSIVE';\n}\nexport interface AddImmutableMapAction {\n  type: 'ADD_IMMUTABLE_MAP';\n}\nexport interface ChangeImmutableNestedAction {\n  type: 'CHANGE_IMMUTABLE_NESTED';\n}\nexport interface HugePayloadAction {\n  type: 'HUGE_PAYLOAD';\n  payload: number[];\n}\nexport interface AddFunctionAction {\n  type: 'ADD_FUNCTION';\n}\nexport interface AddSymbolAction {\n  type: 'ADD_SYMBOL';\n}\nexport interface ShuffleArrayAction {\n  type: 'SHUFFLE_ARRAY';\n}\ntype DemoAppAction =\n  | ToggleTimeoutUpdateAction\n  | TimeoutUpdateAction\n  | IncrementAction\n  | PushAction\n  | PopAction\n  | ReplaceAction\n  | ChangeNestedAction\n  | PushHugeArrayAction\n  | AddIteratorAction\n  | AddHugeObjectAction\n  | AddRecursiveAction\n  | AddImmutableMapAction\n  | ChangeImmutableNestedAction\n  | HugePayloadAction\n  | AddFunctionAction\n  | AddSymbolAction\n  | ShuffleArrayAction;\n\nexport interface DemoAppState {\n  timeoutUpdateEnabled: boolean;\n  store: number;\n  undefined: { val: undefined };\n  null: null;\n  func: () => void;\n  array: number[];\n  hugeArrays: { str: string }[];\n  hugeObjects: { [key: string]: string }[];\n  iterators: { [Symbol.iterator](): IterableIterator<string> }[];\n  nested: Nested;\n  recursive: { obj?: unknown }[];\n  immutables: Immutable.Map<string, unknown>[];\n  immutableNested: Immutable.Map<unknown, unknown>;\n  addFunction: { f: (a: number, b: number, c: number) => number } | null;\n  addSymbol: { s: symbol; error: Error } | null;\n  shuffleArray: unknown[];\n}\n\nexport const rootReducer: Reducer<DemoAppState, DemoAppAction> =\n  combineReducers({\n    timeoutUpdateEnabled: (state = false, action: DemoAppAction) =>\n      action.type === 'TOGGLE_TIMEOUT_UPDATE'\n        ? action.timeoutUpdateEnabled\n        : state,\n    store: (state = 0, action: DemoAppAction) =>\n      action.type === 'INCREMENT' ? state + 1 : state,\n    undefined: (state = { val: undefined }) => state,\n    null: (state = null) => state,\n    func: (\n      state = () => {\n        // noop\n      },\n    ) => state,\n    array: (state = [], action: DemoAppAction) =>\n      action.type === 'PUSH'\n        ? [...state, Math.random()]\n        : action.type === 'POP'\n          ? state.slice(0, state.length - 1)\n          : action.type === 'REPLACE'\n            ? [Math.random(), ...state.slice(1)]\n            : state,\n    hugeArrays: (state = [], action: DemoAppAction) =>\n      action.type === 'PUSH_HUGE_ARRAY' ? [...state, ...HUGE_ARRAY] : state,\n    hugeObjects: (state = [], action: DemoAppAction) =>\n      action.type === 'ADD_HUGE_OBJECT' ? [...state, HUGE_OBJECT] : state,\n    iterators: (state = [], action: DemoAppAction) =>\n      action.type === 'ADD_ITERATOR' ? [...state, createIterator()] : state,\n    nested: (state = NESTED, action: DemoAppAction) =>\n      action.type === 'CHANGE_NESTED'\n        ? {\n            ...state,\n            long: {\n              nested: [\n                {\n                  path: {\n                    to: {\n                      a: state.long.nested[0].path.to.a + '!',\n                    },\n                  },\n                },\n              ],\n            },\n          }\n        : state,\n    recursive: (state = [], action: DemoAppAction) =>\n      action.type === 'ADD_RECURSIVE' ? [...state, { ...RECURSIVE }] : state,\n    immutables: (state = [], action: DemoAppAction) =>\n      action.type === 'ADD_IMMUTABLE_MAP' ? [...state, IMMUTABLE_MAP] : state,\n    immutableNested: (state = IMMUTABLE_NESTED, action: DemoAppAction) =>\n      action.type === 'CHANGE_IMMUTABLE_NESTED'\n        ? state.updateIn(\n            ['long', 'nested', 0, 'path', 'to', 'a'],\n            (str: unknown) => (str as string) + '!',\n          )\n        : state,\n    addFunction: (state = null, action: DemoAppAction) =>\n      action.type === 'ADD_FUNCTION' ? { f: FUNC } : state,\n    addSymbol: (state = null, action: DemoAppAction) =>\n      action.type === 'ADD_SYMBOL'\n        ? { s: window.Symbol('symbol'), error: new Error('TEST') }\n        : state,\n    shuffleArray: (state = DEFAULT_SHUFFLE_ARRAY, action: DemoAppAction) =>\n      action.type === 'SHUFFLE_ARRAY' ? shuffle(state) : state,\n  }) as any;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/demo/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../tsconfig.react.base.json\",\n  \"compilerOptions\": {\n    \"resolveJsonModule\": true,\n    \"types\": [\"webpack-env\"]\n  },\n  \"include\": [\"../src\", \"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/demo/tsconfig.webpack.json",
    "content": "{\n  \"extends\": \"../../../tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"resolveJsonModule\": true,\n    \"types\": [\"node\", \"webpack-dev-server\"]\n  },\n  \"include\": [\"webpack.config.ts\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/demo/webpack.config.ts",
    "content": "import * as path from 'path';\nimport * as webpack from 'webpack';\nimport HtmlWebpackPlugin from 'html-webpack-plugin';\nimport ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';\nimport pkg from '@redux-devtools/inspector-monitor-test-tab/package.json';\n\nconst config: webpack.Configuration = {\n  mode: 'development',\n  entry: './src/index.tsx',\n  devtool: 'eval-source-map',\n  devServer: {\n    static: './dist',\n  },\n  plugins: [\n    new HtmlWebpackPlugin({\n      template: './index.html',\n      package: pkg,\n    }),\n    new ForkTsCheckerWebpackPlugin(),\n  ],\n  output: {\n    filename: 'bundle.js',\n    path: path.join(__dirname, 'dist'),\n    clean: true,\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.(js|ts)x?$/,\n        exclude: /node_modules/,\n        use: {\n          loader: 'babel-loader',\n          options: {\n            presets: [\n              ['@babel/preset-env', { targets: 'defaults' }],\n              '@babel/preset-react',\n              '@babel/preset-typescript',\n            ],\n          },\n        },\n      },\n      {\n        test: /\\.css$/i,\n        use: ['style-loader', 'css-loader'],\n      },\n    ],\n  },\n  resolve: {\n    extensions: ['.js', '.jsx', '.ts', '.tsx'],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/eslint.config.mjs",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTsReact from '../../eslint.ts.react.config.base.mjs';\nimport eslintTsReactJest from '../../eslint.ts.react.jest.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTsReact(import.meta.dirname),\n  ...eslintTsReactJest(import.meta.dirname),\n  {\n    ignores: ['demo', 'jest.config.ts', 'lib'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/jest.config.ts",
    "content": "import { createDefaultEsmPreset, type JestConfigWithTsJest } from 'ts-jest';\n\nconst presetConfig = createDefaultEsmPreset({\n  tsconfig: 'tsconfig.test.json',\n});\n\nconst jestConfig: JestConfigWithTsJest = {\n  ...presetConfig,\n  testEnvironment: 'jsdom',\n  moduleNameMapper: {\n    '^(\\\\.{1,2}/.*)\\\\.js$': '$1',\n    '\\\\.css$': '<rootDir>/test/__mocks__/styleMock.ts',\n  },\n};\n\nexport default jestConfig;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/package.json",
    "content": "{\n  \"name\": \"@redux-devtools/inspector-monitor-test-tab\",\n  \"version\": \"6.0.0\",\n  \"description\": \"Generate tests for redux devtools.\",\n  \"keywords\": [\n    \"redux\",\n    \"devtools\",\n    \"test\",\n    \"flux\",\n    \"react\",\n    \"hot reloading\",\n    \"time travel\",\n    \"live edit\"\n  ],\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-inspector-monitor-test-tab\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)\",\n  \"files\": [\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": {\n    \".\": \"./lib/index.js\",\n    \"./package.json\": \"./package.json\"\n  },\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"test\": \"node --experimental-vm-modules node_modules/jest/bin/jest.js\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run type-check && pnpm run lint && pnpm run test\"\n  },\n  \"dependencies\": {\n    \"@redux-devtools/ui\": \"workspace:^\",\n    \"es6template\": \"^1.0.5\",\n    \"javascript-stringify\": \"^2.1.0\",\n    \"jsan\": \"^3.1.14\",\n    \"object-path\": \"^0.11.8\",\n    \"react-icons\": \"^5.6.0\",\n    \"simple-diff\": \"^1.7.3\"\n  },\n  \"devDependencies\": {\n    \"@emotion/react\": \"^11.14.0\",\n    \"@emotion/styled\": \"^11.14.1\",\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@redux-devtools/inspector-monitor\": \"workspace:^\",\n    \"@testing-library/dom\": \"^10.4.1\",\n    \"@testing-library/react\": \"^16.3.2\",\n    \"@types/es6template\": \"^1.0.5\",\n    \"@types/jest\": \"^30.0.0\",\n    \"@types/jsan\": \"^3.1.5\",\n    \"@types/object-path\": \"^0.11.4\",\n    \"@types/react\": \"^19.2.14\",\n    \"jest\": \"^30.3.0\",\n    \"jest-environment-jsdom\": \"^30.3.0\",\n    \"react\": \"^19.2.4\",\n    \"react-dom\": \"^19.2.4\",\n    \"redux\": \"^5.0.1\",\n    \"rimraf\": \"^6.1.3\",\n    \"ts-jest\": \"^29.4.6\",\n    \"typescript\": \"~5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"@emotion/react\": \"^11.14.0\",\n    \"@emotion/styled\": \"^11.14.1\",\n    \"@redux-devtools/inspector-monitor\": \"workspace:^\",\n    \"@types/react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react\": \"^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"redux\": \"^3.4.0 || ^4.0.0 || ^5.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/TestGenerator.tsx",
    "content": "import React, { PureComponent, Component, ReactNode } from 'react';\nimport { stringify } from 'javascript-stringify';\nimport objectPath from 'object-path';\nimport jsan from 'jsan';\nimport diff, { DiffEvent } from 'simple-diff';\nimport es6template from 'es6template';\nimport { Editor } from '@redux-devtools/ui';\nimport { TabComponentProps } from '@redux-devtools/inspector-monitor';\nimport { Action } from 'redux';\nimport { AssertionLocals, DispatcherLocals, WrapLocals } from './types.js';\n\nexport const fromPath = (path: (string | number)[]) =>\n  path.map((a) => (typeof a === 'string' ? `.${a}` : `[${a}]`)).join('');\n\nfunction getState<S>(\n  s: { state: S; error?: string } | undefined,\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  defaultValue?: {},\n) {\n  if (!s) return defaultValue;\n  return JSON.parse(jsan.stringify(s.state));\n}\n\nexport function compare<S>(\n  s1: { state: S; error?: string } | undefined,\n  s2: { state: S; error?: string },\n  cb: (value: { path: string; curState: number | string | undefined }) => void,\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  defaultValue?: {},\n) {\n  const paths: string[] = []; // Already processed\n  function generate(\n    event: DiffEvent | { type: 'move-item'; newPath: (string | number)[] },\n  ) {\n    let curState: number | string | undefined;\n    let path = fromPath(event.newPath);\n\n    if (event.type === 'remove-item' || event.type === 'move-item') {\n      if (paths.length && paths.includes(path)) return;\n      paths.push(path);\n      const v = objectPath.get(s2.state as unknown as object, event.newPath);\n      curState = v.length;\n      path += '.length';\n    } else if (event.type === 'add-item') {\n      generate({ type: 'move-item', newPath: event.newPath });\n      path += `[${event.newIndex!}]`;\n      curState = stringify(event.newValue);\n    } else {\n      curState = stringify(event.newValue);\n    }\n\n    // console.log(`expect(store${path}).toEqual(${curState});`);\n    cb({ path, curState });\n  }\n\n  diff(\n    getState(s1, defaultValue),\n    getState(s2, defaultValue) /* , { idProp: '*' } */,\n  ).forEach(generate);\n}\n\ninterface Props<S, A extends Action<string>> extends Omit<\n  TabComponentProps<S, A>,\n  'monitorState' | 'updateMonitorState'\n> {\n  name?: string;\n  isVanilla?: boolean;\n  wrap?: string | ((locals: WrapLocals) => string);\n  dispatcher?: string | ((locals: DispatcherLocals) => string);\n  assertion?: string | ((locals: AssertionLocals) => string);\n  useCodemirror: boolean;\n  indentation?: number;\n  header?: ReactNode;\n}\n\nexport default class TestGenerator<\n  S,\n  A extends Action<string>,\n> extends (PureComponent || Component)<Props<S, A>> {\n  getMethod(action: A) {\n    let type = action.type;\n    if (type[0] === '┗') type = type.substr(1).trim();\n    const args = (action as unknown as { arguments: unknown[] }).arguments\n      ? (action as unknown as { arguments: unknown[] }).arguments\n          .map((arg) => stringify(arg))\n          .join(',')\n      : '';\n    return `${type}(${args})`;\n  }\n\n  getAction(action: A) {\n    if (action.type === '@@INIT') return '{}';\n    return stringify(action);\n  }\n\n  generateTest() {\n    const {\n      computedStates,\n      actions,\n      selectedActionId,\n      startActionId,\n      isVanilla,\n      name,\n    } = this.props;\n\n    if (!actions || !computedStates || computedStates.length < 1) return '';\n\n    let { wrap, assertion, dispatcher, indentation } = this.props;\n    if (typeof assertion === 'string')\n      assertion = es6template.compile(assertion);\n    if (typeof wrap === 'string') {\n      const ident = /\\n.+\\$\\{assertions}/.exec(wrap);\n      if (ident) indentation = ident[0].length - 13;\n      wrap = es6template.compile(wrap);\n    }\n    if (typeof dispatcher === 'string')\n      dispatcher = es6template.compile(dispatcher);\n\n    let space = '';\n    if (indentation) space = Array(indentation).join(' ');\n\n    let r = '';\n    let isFirst = true;\n    let i;\n    if (startActionId !== null) i = startActionId;\n    else if (selectedActionId !== null) i = selectedActionId;\n    else i = computedStates.length - 1;\n    const startIdx = i > 0 ? i : 1;\n\n    const addAssertions = ({\n      path,\n      curState,\n    }: {\n      path: string;\n      curState: number | string | undefined;\n    }) => {\n      r += `${space}${(assertion as (locals: AssertionLocals) => string)({\n        path,\n        curState,\n      })}\\n`;\n    };\n\n    while (actions[i]) {\n      if (\n        !isVanilla ||\n        /* eslint-disable-next-line no-useless-escape */\n        /^┗?\\s?[a-zA-Z0-9_@.\\[\\]-]+?$/.test(actions[i].action.type)\n      ) {\n        if (isFirst) isFirst = false;\n        else r += space;\n        if (!isVanilla || actions[i].action.type[0] !== '@') {\n          r +=\n            (dispatcher as (locals: DispatcherLocals) => string)({\n              action: !isVanilla\n                ? this.getAction(actions[i].action)\n                : this.getMethod(actions[i].action),\n              prevState:\n                i > 0 ? stringify(computedStates[i - 1].state) : undefined,\n            }) + '\\n';\n        }\n        if (!isVanilla) {\n          addAssertions({\n            path: '',\n            curState: stringify(computedStates[i].state),\n          });\n        } else {\n          compare(\n            computedStates[i - 1],\n            computedStates[i],\n            addAssertions,\n            isVanilla && {},\n          );\n        }\n      }\n      i++;\n      if (i > selectedActionId!) break;\n    }\n\n    r = r.trim();\n    if (wrap) {\n      if (!isVanilla) r = wrap({ name, assertions: r });\n      else {\n        r = wrap({\n          name: /^[a-zA-Z0-9_-]+?$/.test(name as string) ? name : 'Store',\n          actionName:\n            (selectedActionId === null || selectedActionId > 0) &&\n            actions[startIdx]\n              ? actions[startIdx].action.type.replace(/[^a-zA-Z0-9_-]+/, '')\n              : 'should return the initial state',\n          initialState: stringify(computedStates[startIdx - 1].state),\n          assertions: r,\n        });\n      }\n    }\n    return r;\n  }\n\n  render() {\n    const code = this.generateTest();\n\n    if (!this.props.useCodemirror) {\n      return (\n        <textarea\n          style={{ padding: '10px', width: '100%', height: '100%' }}\n          defaultValue={code}\n        />\n      );\n    }\n\n    return <Editor value={code} />;\n  }\n\n  static defaultProps = {\n    useCodemirror: true,\n    selectedActionId: null,\n    startActionId: null,\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/index.tsx",
    "content": "import React, { Component } from 'react';\nimport {\n  Toolbar,\n  Container,\n  Button,\n  Select,\n  Notification,\n  Dialog,\n} from '@redux-devtools/ui';\nimport { MdAdd } from 'react-icons/md';\nimport { MdEdit } from 'react-icons/md';\nimport { Action } from 'redux';\nimport {\n  DevtoolsInspectorState,\n  TabComponentProps,\n} from '@redux-devtools/inspector-monitor';\nimport { formSchema, uiSchema, defaultFormData } from './templateForm.js';\nimport TestGenerator from './TestGenerator.js';\nimport jestTemplate from './redux/jest/template.js';\nimport mochaTemplate from './redux/mocha/template.js';\nimport tapeTemplate from './redux/tape/template.js';\nimport avaTemplate from './redux/ava/template.js';\nimport { Template } from './types.js';\n\nexport const getDefaultTemplates = (/* lib */): Template[] =>\n  /*\n   if (lib === 'redux') {\n   return [mochaTemplate, tapeTemplate, avaTemplate];\n   }\n   return [mochaVTemplate, tapeVTemplate, avaVTemplate];\n   */\n  [jestTemplate, mochaTemplate, tapeTemplate, avaTemplate];\n\ninterface TestGeneratorMonitorState {\n  hideTip?: boolean;\n  selected?: number;\n  templates?: Template[];\n}\n\ninterface State {\n  dialogStatus: 'Add' | 'Edit' | null;\n}\n\nexport class TestTab<S, A extends Action<string>> extends Component<\n  TabComponentProps<S, A>,\n  State\n> {\n  state: State = { dialogStatus: null };\n\n  getPersistedState = (): TestGeneratorMonitorState =>\n    (this.props.monitorState as { testGenerator?: TestGeneratorMonitorState })\n      .testGenerator || {};\n\n  handleSelectTemplate = (selectedTemplate: Template | null | undefined) => {\n    const { templates = getDefaultTemplates() } = this.getPersistedState();\n    this.updateState({ selected: templates.indexOf(selectedTemplate!) });\n  };\n\n  handleCloseTip = () => {\n    this.updateState({ hideTip: true });\n  };\n\n  handleCloseDialog = () => {\n    this.setState({ dialogStatus: null });\n  };\n\n  handleSubmit = ({ formData: template }: { formData?: Template }) => {\n    const { templates = getDefaultTemplates(), selected = 0 } =\n      this.getPersistedState();\n    if (this.state.dialogStatus === 'Add') {\n      this.updateState({\n        selected: templates.length,\n        templates: [...templates, template!],\n      });\n    } else {\n      const editedTemplates = [...templates];\n      editedTemplates[selected] = template!;\n      this.updateState({\n        templates: editedTemplates,\n      });\n    }\n    this.handleCloseDialog();\n  };\n\n  handleRemove = () => {\n    const { templates = getDefaultTemplates(), selected = 0 } =\n      this.getPersistedState();\n    this.updateState({\n      selected: 0,\n      templates:\n        templates.length === 1\n          ? undefined\n          : [...templates.slice(0, selected), ...templates.slice(selected + 1)],\n    });\n    this.handleCloseDialog();\n  };\n\n  addTemplate = () => {\n    this.setState({ dialogStatus: 'Add' });\n  };\n\n  editTemplate = () => {\n    this.setState({ dialogStatus: 'Edit' });\n  };\n\n  updateState = (newState: TestGeneratorMonitorState) => {\n    this.props.updateMonitorState({\n      testGenerator: {\n        ...(\n          this.props.monitorState as {\n            testGenerator?: TestGeneratorMonitorState;\n          }\n        ).testGenerator,\n        ...newState,\n      },\n    } as Partial<DevtoolsInspectorState>);\n  };\n\n  render() {\n    const { monitorState, updateMonitorState, ...rest } = this.props; // eslint-disable-line no-unused-vars, max-len\n    const { dialogStatus } = this.state;\n    const persistedState = this.getPersistedState();\n    const { selected = 0, templates = getDefaultTemplates() } = persistedState;\n    const template = templates[selected];\n    const { name, assertion, dispatcher, wrap } = template;\n\n    return (\n      <Container>\n        <Toolbar>\n          <div style={{ flexGrow: 1 }}>\n            <Select\n              options={templates}\n              getOptionValue={(template: Template) => template.name!}\n              getOptionLabel={(template: Template) => template.name!}\n              value={templates.find((template) => template.name === name)}\n              onChange={this.handleSelectTemplate}\n            />\n          </div>\n          <Button onClick={this.editTemplate}>\n            <MdEdit />\n          </Button>\n          <Button onClick={this.addTemplate}>\n            <MdAdd />\n          </Button>\n        </Toolbar>\n        {!assertion ? (\n          <Notification>No template for tests specified.</Notification>\n        ) : (\n          <TestGenerator<S, A>\n            isVanilla={false}\n            assertion={assertion}\n            dispatcher={dispatcher}\n            wrap={wrap}\n            {...rest}\n          />\n        )}\n        {!persistedState.hideTip &&\n          assertion &&\n          rest.startActionId === null && (\n            <Notification onClose={this.handleCloseTip}>\n              Hold <b>SHIFT</b> key to select more actions.\n            </Notification>\n          )}\n        {dialogStatus && (\n          <Dialog<Template>\n            open\n            title={`${dialogStatus} test template`}\n            onDismiss={this.handleCloseDialog}\n            onSubmit={this.handleSubmit}\n            actions={[\n              <Button key=\"cancel\" onClick={this.handleCloseDialog}>\n                Cancel\n              </Button>,\n              <Button key=\"remove\" onClick={this.handleRemove}>\n                Remove\n              </Button>,\n            ]}\n            submitText={dialogStatus}\n            schema={formSchema}\n            uiSchema={uiSchema}\n            formData={dialogStatus === 'Edit' ? template : defaultFormData}\n          />\n        )}\n      </Container>\n    );\n  }\n}\n\nexport { default as reduxAvaTemplate } from './redux/ava/index.js';\nexport { default as reduxJestTemplate } from './redux/jest/index.js';\nexport { default as reduxMochaTemplate } from './redux/mocha/index.js';\nexport { default as reduxTapeTemplate } from './redux/tape/index.js';\nexport { default as vanillaAvaTemplate } from './vanilla/ava/index.js';\nexport { default as vanillaJestTemplate } from './vanilla/jest/index.js';\nexport { default as vanillaMochaTemplate } from './vanilla/mocha/index.js';\nexport { default as vanillaTapeTemplate } from './vanilla/tape/index.js';\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/redux/ava/index.ts",
    "content": "import { AssertionLocals, DispatcherLocals, WrapLocals } from '../../types.js';\n\nexport const name = 'Ava template';\n\nexport const dispatcher = ({ action, prevState }: DispatcherLocals) =>\n  `state = reducers(${prevState!}, ${action!});`;\n\nexport const assertion = ({ curState }: AssertionLocals) =>\n  `t.deepEqual(state, ${curState!});`;\n\nexport const wrap = ({ assertions }: WrapLocals) =>\n  `import test from 'ava';\nimport reducers from '../../reducers';\n\ntest('reducers', (t) => {\n  let state;\n  ${assertions}\n});\n`;\n\nexport default { name, assertion, dispatcher, wrap };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/redux/ava/template.ts",
    "content": "export const name = 'Ava template';\n\nexport const dispatcher = 'state = reducers(${prevState}, ${action});';\n\nexport const assertion = 't.deepEqual(state, ${curState});';\n\nexport const wrap = `import test from 'ava';\nimport reducers from '../../reducers';\n\ntest('reducers', (t) => {\n  let state;\n  \\${assertions}\n});\n`;\n\nexport default { name, assertion, dispatcher, wrap };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/redux/jest/index.ts",
    "content": "import { AssertionLocals, DispatcherLocals, WrapLocals } from '../../types.js';\n\nexport const name = 'Jest template';\n\nexport const dispatcher = ({ action, prevState }: DispatcherLocals) =>\n  `state = reducers(${prevState!}, ${action!});`;\n\nexport const assertion = ({ curState }: AssertionLocals) =>\n  `expect(state).toEqual(${curState!});`;\n\nexport const wrap = ({ assertions }: WrapLocals) =>\n  `import reducers from '../../reducers';\n\ntest('reducers', () => {\n  let state;\n  ${assertions}\n});\n`;\n\nexport default { name, assertion, dispatcher, wrap };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/redux/jest/template.ts",
    "content": "export const name = 'Jest template';\n\nexport const dispatcher = 'state = reducers(${prevState}, ${action});';\n\nexport const assertion = 'expect(state).toEqual(${curState});';\n\nexport const wrap = `import reducers from '../../reducers';\n\ntest('reducers', () => {\n  let state;\n  \\${assertions}\n});\n`;\n\nexport default { name, assertion, dispatcher, wrap };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/redux/mocha/index.ts",
    "content": "import { AssertionLocals, DispatcherLocals, WrapLocals } from '../../types.js';\n\nexport const name = 'Mocha template';\n\nexport const dispatcher = ({ action, prevState }: DispatcherLocals) =>\n  `state = reducers(${prevState!}, ${action!});`;\n\nexport const assertion = ({ curState }: AssertionLocals) =>\n  `expect(state).toEqual(${curState!});`;\n\nexport const wrap = ({ assertions }: WrapLocals) =>\n  `import expect from 'expect';\nimport reducers from '../../reducers';\n\ndescribe('reducers', () => {\n  it('should handle actions', () => {\n    let state;\n    ${assertions}\n  });\n});\n`;\n\nexport default { name, assertion, dispatcher, wrap };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/redux/mocha/template.ts",
    "content": "export const name = 'Mocha template';\n\nexport const dispatcher = 'state = reducers(${prevState}, ${action});';\n\nexport const assertion = 'expect(state).toEqual(${curState});';\n\nexport const wrap = `import expect from 'expect';\nimport reducers from '../../reducers';\n\ndescribe('reducers', () => {\n  it('should handle actions', () => {\n    let state;\n    \\${assertions}\n  });\n});\n`;\n\nexport default { name, assertion, dispatcher, wrap };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/redux/tape/index.ts",
    "content": "import { AssertionLocals, DispatcherLocals, WrapLocals } from '../../types.js';\n\nexport const name = 'Tape template';\n\nexport const dispatcher = ({ action, prevState }: DispatcherLocals) =>\n  `state = reducers(${prevState!}, ${action!});`;\n\nexport const assertion = ({ curState }: AssertionLocals) =>\n  `t.deepEqual(state, ${curState!});`;\n\nexport const wrap = ({ assertions }: WrapLocals) =>\n  `import test from 'tape';\nimport reducers from '../../reducers';\n\ntest('reducers', (t) => {\n  let state;\n  ${assertions}\n  t.end();\n});\n`;\n\nexport default { name, assertion, dispatcher, wrap };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/redux/tape/template.ts",
    "content": "export const name = 'Tape template';\n\nexport const dispatcher = 'state = reducers(${prevState}, ${action});';\n\nexport const assertion = 't.deepEqual(state, ${curState});';\n\nexport const wrap = `import test from 'tape';\nimport reducers from '../../reducers';\n\ntest('reducers', (t) => {\n  let state;\n  \\${assertions}\n  t.end();\n});\n`;\n\nexport default { name, assertion, dispatcher, wrap };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/templateForm.ts",
    "content": "import { Template } from './types.js';\n\nexport const formSchema = {\n  type: 'object' as const,\n  required: ['name'],\n  properties: {\n    name: {\n      type: 'string' as const,\n      title: 'Template name',\n    },\n    dispatcher: {\n      type: 'string' as const,\n      title: 'Dispatcher: ({ action, prevState }) => (`<template>`)',\n    },\n    assertion: {\n      type: 'string' as const,\n      title: 'Assertion: ({ curState }) => (`<template>`)',\n    },\n    wrap: {\n      type: 'string' as const,\n      title:\n        'Wrap code: ({ name, initialState, assertions }) => (`<template>`)',\n    },\n  },\n};\n\nexport const uiSchema = {\n  dispatcher: {\n    'ui:widget': 'textarea',\n  },\n  assertion: {\n    'ui:widget': 'textarea',\n  },\n  wrap: {\n    'ui:widget': 'textarea',\n  },\n};\n\nexport const defaultFormData: Template = {\n  dispatcher: 'state = reducers(${prevState}, ${action});',\n  assertion: 't.deepEqual(state, ${curState});',\n  wrap: `test('reducers', (t) => {\n  \\${assertions}\n});`,\n};\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/types.ts",
    "content": "export interface DispatcherLocals {\n  action: string | undefined;\n  prevState: string | undefined;\n}\n\nexport interface AssertionLocals {\n  path: string;\n  curState: number | string | undefined;\n}\n\nexport interface WrapLocals {\n  name: string | undefined;\n  assertions: string;\n  actionName?: string;\n  initialState?: string | undefined;\n}\n\nexport interface Template {\n  name?: string;\n  dispatcher: string;\n  assertion: string;\n  wrap: string;\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/vanilla/ava/index.ts",
    "content": "import { AssertionLocals, DispatcherLocals, WrapLocals } from '../../types.js';\n\nexport const name = 'Ava template';\n\nexport const dispatcher = ({ action }: DispatcherLocals) => `${action!};`;\n\nexport const assertion = ({ path, curState }: AssertionLocals) =>\n  `t.deepEqual(state${path}, ${curState!});`;\n\nexport const wrap = ({ name, initialState, assertions }: WrapLocals) =>\n  `import test from 'ava';\nimport ${name!} from '../../stores/${name!}';\n\ntest('${name!}', (t) => {\n  const store = new ${name!}(${initialState!});\n  ${assertions}\n});\n`;\n\nexport default { name, assertion, dispatcher, wrap };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/vanilla/ava/template.ts",
    "content": "export const name = 'Ava template';\n\nexport const dispatcher = '${action};';\n\nexport const assertion = 't.deepEqual(state${path}, ${curState});';\n\nexport const wrap = `import test from 'ava';\nimport \\${name} from '../../stores/\\${name}';\n\ntest('\\${name}', (t) => {\n  const store = new \\${name}(\\${initialState});\n  \\${assertions}\n});\n`;\n\nexport default { name, assertion, dispatcher, wrap };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/vanilla/jest/index.ts",
    "content": "import { AssertionLocals, DispatcherLocals, WrapLocals } from '../../types.js';\n\nexport const name = 'Mocha template';\n\nexport const dispatcher = ({ action }: DispatcherLocals) => `${action!};`;\n\nexport const assertion = ({ path, curState }: AssertionLocals) =>\n  `expect(store${path}).toEqual(${curState!});`;\n\nexport const wrap = ({ name, initialState, assertions }: WrapLocals) =>\n  `import expect from 'expect';\nimport ${name!} from '../../stores/${name!}';\n\ntest('${name!}', (t) => {\n  const store = new ${name!}(${initialState!});\n  ${assertions}\n});\n`;\n\nexport default { name, assertion, dispatcher, wrap };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/vanilla/jest/template.ts",
    "content": "export const name = 'Mocha template';\n\nexport const dispatcher = '${action};';\n\nexport const assertion = 'expect(store${path}).toEqual(${curState});';\n\nexport const wrap = `import expect from 'expect';\nimport \\${name} from '../../stores/\\${name}';\n\ntest('\\${name}', (t) => {\n  const store = new \\${name}(\\${initialState});\n  \\${assertions}\n});\n`;\n\nexport default { name, assertion, dispatcher, wrap };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/vanilla/mocha/index.ts",
    "content": "import { AssertionLocals, DispatcherLocals, WrapLocals } from '../../types.js';\n\nexport const name = 'Mocha template';\n\nexport const dispatcher = ({ action }: DispatcherLocals) => `${action!};`;\n\nexport const assertion = ({ path, curState }: AssertionLocals) =>\n  `expect(store${path}).toEqual(${curState!});`;\n\nexport const wrap = ({\n  name,\n  actionName,\n  initialState,\n  assertions,\n}: WrapLocals) =>\n  `import expect from 'expect';\nimport ${name!} from '../../stores/${name!}';\n\ndescribe('${name!}', () => {\n  it('${actionName!}', () => {\n    const store = new ${name!}(${initialState!});\n    ${assertions}\n  });\n});\n`;\n\nexport default { name, assertion, dispatcher, wrap };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/vanilla/mocha/template.ts",
    "content": "export const name = 'Mocha template';\n\nexport const dispatcher = '${action};';\n\nexport const assertion = 'expect(store${path}).toEqual(${curState});';\n\nexport const wrap = `import expect from 'expect';\nimport \\${name} from '../../stores/\\${name}';\n\ndescribe('\\${name}', () => {\n  it('\\${actionName}', () => {\n    const store = new \\${name}(\\${initialState});\n    \\${assertions}\n  });\n});\n`;\n\nexport default { name, assertion, dispatcher, wrap };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/vanilla/tape/index.ts",
    "content": "import { AssertionLocals, DispatcherLocals, WrapLocals } from '../../types.js';\n\nexport const name = 'Tape template';\n\nexport const dispatcher = ({ action }: DispatcherLocals) => `${action!};`;\n\nexport const assertion = ({ path, curState }: AssertionLocals) =>\n  `t.deepEqual(state${path}, ${curState!});`;\n\nexport const wrap = ({ name, initialState, assertions }: WrapLocals) =>\n  `import test from 'tape';\nimport ${name!} from '../../stores/${name!}';\n\ntest('${name!}', (t) => {\n  const store = new ${name!}(${initialState!});\n  ${assertions}\n  t.end();\n});\n`;\n\nexport default { name, assertion, dispatcher, wrap };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/src/vanilla/tape/template.ts",
    "content": "export const name = 'Tape template';\n\nexport const dispatcher = '${action};';\n\nexport const assertion = 't.deepEqual(state${path}, ${curState});';\n\nexport const wrap = `import test from 'tape';\nimport \\${name} from '../../stores/\\${name}';\n\ntest('\\${name}', (t) => {\n  const store = new \\${name}(\\${initialState});\n  \\${assertions}\n  t.end();\n});\n`;\n\nexport default { name, assertion, dispatcher, wrap };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/test/TestGenerator.spec.tsx",
    "content": "import React from 'react';\nimport { render } from '@testing-library/react';\nimport { PerformAction } from '@redux-devtools/core';\nimport { Action } from 'redux';\nimport TestGenerator from '../src/TestGenerator.js';\nimport fnTemplate from '../src/redux/mocha/index.js';\nimport strTemplate from '../src/redux/mocha/template.js';\nimport fnVanillaTemplate from '../src/vanilla/mocha/index.js';\nimport strVanillaTemplate from '../src/vanilla/mocha/template.js';\n\nconst actions: { [actionId: number]: PerformAction<Action<string>> } = {\n  0: {\n    type: 'PERFORM_ACTION',\n    action: { type: '@@INIT' },\n    timestamp: 0,\n    stack: undefined,\n  },\n  1: {\n    type: 'PERFORM_ACTION',\n    action: { type: 'INCREMENT_COUNTER' },\n    timestamp: 0,\n    stack: undefined,\n  },\n};\n\nconst computedStates = [{ state: { counter: 0 } }, { state: { counter: 1 } }];\n\nconst TestGeneratorAsAny = TestGenerator as any;\n\ndescribe('TestGenerator component', () => {\n  it('should show warning message when no params provided', () => {\n    const { container } = render(<TestGeneratorAsAny useCodemirror={false} />);\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('should be empty when no actions provided', () => {\n    const { container } = render(\n      <TestGeneratorAsAny\n        assertion={fnTemplate.assertion}\n        dispatcher={fnTemplate.dispatcher}\n        wrap={fnTemplate.wrap}\n        useCodemirror={false}\n      />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it(\"should match function template's test for first action\", () => {\n    const { container } = render(\n      <TestGeneratorAsAny\n        assertion={fnTemplate.assertion}\n        dispatcher={fnTemplate.dispatcher}\n        wrap={fnTemplate.wrap}\n        actions={actions}\n        computedStates={computedStates}\n        selectedActionId={1}\n        useCodemirror={false}\n      />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it(\"should match string template's test for first action\", () => {\n    const { container } = render(\n      <TestGeneratorAsAny\n        assertion={strTemplate.assertion}\n        dispatcher={strTemplate.dispatcher}\n        wrap={strTemplate.wrap}\n        useCodemirror={false}\n        actions={actions}\n        computedStates={computedStates}\n        selectedActionId={1}\n      />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('should generate test for the last action when selectedActionId not specified', () => {\n    const { container } = render(\n      <TestGeneratorAsAny\n        assertion={fnTemplate.assertion}\n        dispatcher={fnTemplate.dispatcher}\n        wrap={fnTemplate.wrap}\n        actions={actions}\n        computedStates={computedStates}\n        useCodemirror={false}\n      />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('should generate test for vanilla js class', () => {\n    const { container } = render(\n      <TestGeneratorAsAny\n        assertion={fnVanillaTemplate.assertion}\n        dispatcher={fnVanillaTemplate.dispatcher}\n        wrap={fnVanillaTemplate.wrap}\n        actions={actions}\n        computedStates={computedStates}\n        selectedActionId={1}\n        isVanilla\n        name=\"SomeStore\"\n        useCodemirror={false}\n      />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('should generate test for vanilla js class with string template', () => {\n    const { container } = render(\n      <TestGeneratorAsAny\n        assertion={strVanillaTemplate.assertion}\n        dispatcher={strVanillaTemplate.dispatcher}\n        wrap={strVanillaTemplate.wrap}\n        actions={actions}\n        computedStates={computedStates}\n        selectedActionId={1}\n        isVanilla\n        name=\"SomeStore\"\n        useCodemirror={false}\n      />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/test/__mocks__/styleMock.ts",
    "content": "export default {};\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/test/__snapshots__/TestGenerator.spec.tsx.snap",
    "content": "// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing\n\nexports[`TestGenerator component should be empty when no actions provided 1`] = `\n<textarea\n  style=\"padding: 10px; width: 100%; height: 100%;\"\n/>\n`;\n\nexports[`TestGenerator component should generate test for the last action when selectedActionId not specified 1`] = `\n<textarea\n  style=\"padding: 10px; width: 100%; height: 100%;\"\n>\n  import expect from 'expect';\nimport reducers from '../../reducers';\n\ndescribe('reducers', () =&gt; {\n  it('should handle actions', () =&gt; {\n    let state;\n    state = reducers({counter:0}, {type:'INCREMENT_COUNTER'});\nexpect(state).toEqual({counter:1});\n  });\n});\n\n</textarea>\n`;\n\nexports[`TestGenerator component should generate test for vanilla js class 1`] = `\n<textarea\n  style=\"padding: 10px; width: 100%; height: 100%;\"\n>\n  import expect from 'expect';\nimport SomeStore from '../../stores/SomeStore';\n\ndescribe('SomeStore', () =&gt; {\n  it('INCREMENT_COUNTER', () =&gt; {\n    const store = new SomeStore({counter:0});\n    INCREMENT_COUNTER();\nexpect(store.counter).toEqual(1);\n  });\n});\n\n</textarea>\n`;\n\nexports[`TestGenerator component should generate test for vanilla js class with string template 1`] = `\n<textarea\n  style=\"padding: 10px; width: 100%; height: 100%;\"\n>\n  import expect from 'expect';\nimport SomeStore from '../../stores/SomeStore';\n\ndescribe('SomeStore', () =&gt; {\n  it('INCREMENT_COUNTER', () =&gt; {\n    const store = new SomeStore({counter:0});\n    INCREMENT_COUNTER();\n    expect(store.counter).toEqual(1);\n  });\n});\n\n</textarea>\n`;\n\nexports[`TestGenerator component should match function template's test for first action 1`] = `\n<textarea\n  style=\"padding: 10px; width: 100%; height: 100%;\"\n>\n  import expect from 'expect';\nimport reducers from '../../reducers';\n\ndescribe('reducers', () =&gt; {\n  it('should handle actions', () =&gt; {\n    let state;\n    state = reducers({counter:0}, {type:'INCREMENT_COUNTER'});\nexpect(state).toEqual({counter:1});\n  });\n});\n\n</textarea>\n`;\n\nexports[`TestGenerator component should match string template's test for first action 1`] = `\n<textarea\n  style=\"padding: 10px; width: 100%; height: 100%;\"\n>\n  import expect from 'expect';\nimport reducers from '../../reducers';\n\ndescribe('reducers', () =&gt; {\n  it('should handle actions', () =&gt; {\n    let state;\n    state = reducers({counter:0}, {type:'INCREMENT_COUNTER'});\n    expect(state).toEqual({counter:1});\n  });\n});\n\n</textarea>\n`;\n\nexports[`TestGenerator component should show warning message when no params provided 1`] = `\n<textarea\n  style=\"padding: 10px; width: 100%; height: 100%;\"\n/>\n`;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/test/assertions.spec.ts",
    "content": "import { assertion } from '../src/vanilla/mocha/index.js';\nimport { compare } from '../src/TestGenerator.js';\n\nconst computedStates = [\n  { state: { o1: 0 } },\n  { state: { o1: 0, o2: 1 } },\n  { state: { o1: 0, o2: 'a' } },\n  { state: { o1: [{ t: 1 }], o3: { t: 2 } } },\n  { state: { o1: [{ t: 3 }], o3: { t: 2 } } },\n  { state: [0, 1, 2, 3, 4] },\n  { state: [0, 3] },\n  { state: [0, 2, 3, 4] },\n];\n\nconst runTest = (s1: { state: unknown } | undefined, s2: { state: unknown }) =>\n  compare(s1, s2, ({ path, curState }) =>\n    expect(\n      `expect(store${path}).toEqual(${curState as number | string});`,\n    ).toBe(assertion({ path, curState })),\n  );\n\ndescribe('Assertions', () => {\n  it('should return initial state', () => {\n    runTest(undefined, computedStates[0]);\n  });\n\n  it('should add element', () => {\n    runTest(computedStates[0], computedStates[1]);\n  });\n\n  it('should remove element', () => {\n    runTest(computedStates[1], computedStates[0]);\n  });\n\n  it('should change element', () => {\n    runTest(computedStates[1], computedStates[2]);\n  });\n\n  it('should add, change and remove elements', () => {\n    runTest(computedStates[2], computedStates[3]);\n  });\n\n  it('should change in array', () => {\n    runTest(computedStates[3], computedStates[4]);\n  });\n\n  it('should remove elements in array', () => {\n    runTest(computedStates[5], computedStates[6]);\n  });\n\n  it('should add elements in array', () => {\n    runTest(computedStates[6], computedStates[5]);\n  });\n\n  it('should add and change elements in array', () => {\n    runTest(computedStates[5], computedStates[7]);\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\",\n    \"resolveJsonModule\": true\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-test-tab/tsconfig.test.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"jest\"]\n  },\n  \"include\": [\"src\", \"test\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/CHANGELOG.md",
    "content": "# Change Log\n\n## 5.0.0\n\n### Major Changes\n\n- 12849a4: Convert monitors to ESM\n\n### Patch Changes\n\n- Updated dependencies [12849a4]\n  - @redux-devtools/inspector-monitor@7.0.0\n\n## 4.1.1\n\n### Patch Changes\n\n- @redux-devtools/inspector-monitor@6.1.1\n\n## 4.1.0\n\n### Minor Changes\n\n- 6830118: Add React 19 to peer deps\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - @redux-devtools/inspector-monitor@7.0.0\n\n## 4.0.1\n\n### Patch Changes\n\n- Updated dependencies [bbb1a40]\n  - react-base16-styling@0.10.0\n\n## 4.0.0\n\n### Major Changes\n\n- 5cfe3e5: Update min required React version to 16.8.4\n\n### Patch Changes\n\n- Updated dependencies [5cfe3e5]\n  - @redux-devtools/inspector-monitor@6.0.0\n\n## 3.0.0\n\n### Major Changes\n\n- 158ba2c: Replace jss with Emotion in inspector-monitor. `@emotion/react` is now a required peer dependency.\n\n### Patch Changes\n\n- Updated dependencies [158ba2c]\n  - @redux-devtools/inspector-monitor@5.0.0\n\n## 2.1.0\n\n### Minor Changes\n\n- 6fc18ed7: Add new Redux version to peer dependencies\n\n### Patch Changes\n\n- 7f5bddbd: Widen peer dependencies\n\n## 2.0.1\n\n### Patch Changes\n\n- 65205f90: Replace Action<unknown> with Action<string>\n- Updated dependencies [65205f90]\n  - @redux-devtools/inspector-monitor@4.0.1\n\n## 2.0.0\n\n### Major Changes\n\n- 57751ff9: Add react-dom peerDependency and bump react peerDependency to `^16.8.0 || ^17.0.0 || ^18.0.0`\n\n### Patch Changes\n\n- Updated dependencies [57751ff9]\n  - @redux-devtools/inspector-monitor@4.0.0\n\n## 1.0.1\n\n### Patch Changes\n\n- Updated dependencies [14a79573]\n- Updated dependencies [d54adb76]\n- Updated dependencies [bb9bd907]\n  - @redux-devtools/inspector-monitor@3.1.0\n\n## 1.0.0\n\n### Minor Changes\n\n- 8a7eae4: Add React 18 to peerDependencies range\n\n### Patch Changes\n\n- Updated dependencies [8a7eae4]\n  - @redux-devtools/inspector-monitor@3.0.0\n\n## 0.3.4\n\n### Patch Changes\n\n- @redux-devtools/inspector-monitor@3.0.0\n\n## 0.3.0\n\n- Adds ESM build (https://github.com/reduxjs/redux-devtools/pull/997) and switches the default export to a named export in order to ensure that the CommonJS output and the ESM output are [interchangeable](https://rollupjs.org/guide/en/#outputexports):\n\n```diff\n- import TraceTab from '@redux-devtools/inspector-monitor-trace-tab';\n+ import { TraceTab } from '@redux-devtools/inspector-monitor-trace-tab';\n```\n\n## [0.2.2](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/inspector-monitor-trace-tab@0.2.1...@redux-devtools/inspector-monitor-trace-tab@0.2.2) (2021-06-11)\n\n### Bug Fixes\n\n- **app:** fix dependency version of inspector ([#732](https://github.com/reduxjs/redux-devtools/issues/732)) ([30c6971](https://github.com/reduxjs/redux-devtools/commit/30c6971d379c53ec1343a20240b73705751f7445))\n\n## [0.2.1](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/inspector-monitor-trace-tab@0.2.0...@redux-devtools/inspector-monitor-trace-tab@0.2.1) (2021-06-11)\n\n### Bug Fixes\n\n- fix peer dependencies on inpsector monitor ([#730](https://github.com/reduxjs/redux-devtools/issues/730)) ([0291f5c](https://github.com/reduxjs/redux-devtools/commit/0291f5c95e4340a3b5e30a3efe76a1a1a2bb7f5e))\n\n## [0.2.0](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/inspector-monitor-trace-tab@0.1.4...@redux-devtools/inspector-monitor-trace-tab@0.2.0) (2021-03-06)\n\n### Features\n\n- update peer dependencies to allow react@^17 ([#703](https://github.com/reduxjs/redux-devtools/issues/703)) ([2aaa9c1](https://github.com/reduxjs/redux-devtools/commit/2aaa9c10a383e3a7ab20b3ab14639781fd7bb2eb))\n\n## 0.1.4 (2021-03-06)\n\n**Note:** Version bump only for package @redux-devtools/inspector-monitor-trace-tab\n\n## [0.1.3](https://github.com/reduxjs/redux-devtools/compare/redux-devtools-trace-monitor@0.1.2...redux-devtools-trace-monitor@0.1.3) (2020-09-07)\n\n**Note:** Version bump only for package redux-devtools-trace-monitor\n\n## 0.1.2 (2020-08-14)\n\n### Bug Fixes\n\n- **redux-devtools-trace-monitor:** consolidate packages ([#540](https://github.com/reduxjs/redux-devtools/issues/540)) ([370134d](https://github.com/reduxjs/redux-devtools/commit/370134d5a2bb7337f72134a9396398ab9f66fe30))\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/LICENSE.md",
    "content": "The MIT License (MIT)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/README.md",
    "content": "# Redux DevTools Stack Trace Monitor\n\nSubmonitor for Redux DevTools inspector to show stack traces. Based on [`react-error-overlay`](https://github.com/facebook/create-react-app/tree/master/packages/react-error-overlay) and the contribution of [Mark Erikson](https://github.com/markerikson) in [the PR from `remotedev-app`](https://github.com/zalmoxisus/remotedev-app/pull/43/).\n\nIt's integrated in Redux DevTools browser extension. To use it separately with [`redux-devtools`](https://github.com/reduxjs/redux-devtools/packages/redux-devtools) and [`redux-devtools-inspector-monitor`](https://github.com/reduxjs/redux-devtools/packages/redux-devtools-inspector-monitor) according to [Walkthrough](https://github.com/reduxjs/redux-devtools/blob/master/docs/Walkthrough.md):\n\n##### `containers/DevTools.js`\n\n```js\nimport React from 'react';\nimport { createDevTools } from '@redux-devtools/core';\nimport { InspectorMonitor } from '@redux-devtools/inspector-monitor';\nimport { TraceTab } from '@redux-devtools/inspector-monitor-trace-tab';\n\nexport default createDevTools(\n  <InspectorMonitor\n    tabs: defaultTabs => [...defaultTabs, { name: 'Trace', component: TraceTab }]\n  />\n);\n```\n\n##### `store/configureStore.js`\n\n```js\n// ...\nconst enhancer = compose(\n  // ...\n  DevTools.instrument({ trace: true }),\n);\n// ...\n```\n\n### License\n\nMIT\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/eslint.config.mjs",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTsReact from '../../eslint.ts.react.config.base.mjs';\nimport eslintTsReactJest from '../../eslint.ts.react.jest.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTsReact(import.meta.dirname),\n  ...eslintTsReactJest(import.meta.dirname),\n  {\n    ignores: ['jest.config.ts', 'lib'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/jest.config.ts",
    "content": "import { createDefaultEsmPreset, type JestConfigWithTsJest } from 'ts-jest';\n\nconst presetConfig = createDefaultEsmPreset({\n  tsconfig: 'tsconfig.test.json',\n});\n\nconst jestConfig: JestConfigWithTsJest = {\n  ...presetConfig,\n  testEnvironment: 'jsdom',\n  moduleNameMapper: {\n    '^(\\\\.{1,2}/.*)\\\\.js$': '$1',\n  },\n};\n\nexport default jestConfig;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/package.json",
    "content": "{\n  \"name\": \"@redux-devtools/inspector-monitor-trace-tab\",\n  \"version\": \"5.0.0\",\n  \"description\": \"Submonitor for Redux DevTools inspector to show stack traces.\",\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-inspector-monitor-trace-tab\",\n  \"license\": \"MIT\",\n  \"author\": \"Mark Erikson <mark@isquaredsoftware.com>\",\n  \"contributors\": [\n    \"Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)\"\n  ],\n  \"files\": [\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": \"./lib/StackTraceTab.js\",\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": \"https://github.com/reduxjs/redux-devtools\",\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"test\": \"node --experimental-vm-modules node_modules/jest/bin/jest.js\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run type-check && pnpm run lint && pnpm run test\"\n  },\n  \"dependencies\": {\n    \"@babel/code-frame\": \"^8.0.0-rc.2\",\n    \"@types/chrome\": \"^0.1.37\",\n    \"anser\": \"^2.3.5\",\n    \"html-entities\": \"^2.6.0\",\n    \"path-browserify\": \"^1.0.1\",\n    \"react-base16-styling\": \"workspace:^\",\n    \"source-map\": \"^0.5.7\"\n  },\n  \"devDependencies\": {\n    \"@emotion/react\": \"^11.14.0\",\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@redux-devtools/inspector-monitor\": \"workspace:^\",\n    \"@testing-library/dom\": \"^10.4.1\",\n    \"@testing-library/react\": \"^16.3.2\",\n    \"@types/babel__code-frame\": \"^7.27.0\",\n    \"@types/jest\": \"^30.0.0\",\n    \"@types/node\": \"^24.12.0\",\n    \"@types/path-browserify\": \"^1.0.3\",\n    \"@types/react\": \"^19.2.14\",\n    \"@types/source-map\": \"0.5.2\",\n    \"jest\": \"^30.3.0\",\n    \"jest-environment-jsdom\": \"^30.3.0\",\n    \"react\": \"^19.2.4\",\n    \"react-dom\": \"^19.2.4\",\n    \"redux\": \"^5.0.1\",\n    \"rimraf\": \"^6.1.3\",\n    \"ts-jest\": \"^29.4.6\",\n    \"typescript\": \"~5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"@emotion/react\": \"^11.14.0\",\n    \"@redux-devtools/inspector-monitor\": \"workspace:^\",\n    \"@types/react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react\": \"^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"redux\": \"^3.4.0 || ^4.0.0 || ^5.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/StackTraceTab.tsx",
    "content": "import React, { Component } from 'react';\n\nimport { getStackFrames } from './react-error-overlay/utils/getStackFrames.js';\nimport StackTrace from './react-error-overlay/containers/StackTrace.js';\nimport openFile from './openFile.js';\nimport { Action } from 'redux';\nimport { TabComponentProps } from '@redux-devtools/inspector-monitor';\nimport StackFrame from './react-error-overlay/utils/stack-frame.js';\nimport { ErrorLocation } from './react-error-overlay/utils/parseCompileError.js';\n\nconst rootStyle = { padding: '5px 10px' };\n\ninterface Props<S, A extends Action<string>> extends TabComponentProps<S, A> {\n  openFile: (\n    fileName: string,\n    lineNumber: number,\n    stackFrame: StackFrame,\n  ) => void;\n}\n\ninterface State {\n  stackFrames: StackFrame[];\n  currentError?: Error;\n  showDocsLink?: boolean;\n}\n\nexport class TraceTab<S, A extends Action<string>> extends Component<\n  Props<S, A>,\n  State\n> {\n  static defaultProps = {\n    openFile,\n  };\n\n  state: State = {\n    stackFrames: [],\n  };\n\n  componentDidMount() {\n    // console.log(\"StackTraceTab mounted\");\n    this.checkForStackTrace();\n  }\n\n  componentDidUpdate(prevProps: Props<S, A>) {\n    const { action, actions } = prevProps;\n\n    if (action !== this.props.action || actions !== this.props.actions) {\n      this.checkForStackTrace();\n    }\n  }\n\n  checkForStackTrace() {\n    const { action, actions: liftedActionsById } = this.props;\n\n    if (!action) {\n      return;\n    }\n\n    const liftedActions = Object.values(liftedActionsById);\n    const liftedAction = liftedActions.find(\n      (liftedAction) => liftedAction.action === action,\n    );\n\n    if (liftedAction && typeof liftedAction.stack === 'string') {\n      const deserializedError = Object.assign(new Error(), {\n        stack: liftedAction.stack,\n      });\n\n      getStackFrames(deserializedError)\n        .then((stackFrames) => {\n          this.setState({\n            stackFrames: stackFrames!,\n            currentError: deserializedError,\n          });\n        })\n        .catch(() => {\n          // noop\n        });\n    } else {\n      this.setState({\n        stackFrames: [],\n        showDocsLink:\n          !!liftedAction!.action &&\n          !!liftedAction!.action.type &&\n          liftedAction!.action.type !== '@@INIT',\n      });\n    }\n  }\n\n  onStackLocationClicked = (fileLocation: Partial<ErrorLocation> = {}) => {\n    // console.log(\"Stack location args: \", ...args);\n\n    const { fileName, lineNumber } = fileLocation;\n\n    if (fileName && lineNumber) {\n      const matchingStackFrame = this.state.stackFrames.find((stackFrame) => {\n        const matches =\n          (stackFrame._originalFileName === fileName &&\n            stackFrame._originalLineNumber === lineNumber) ||\n          (stackFrame.fileName === fileName &&\n            stackFrame.lineNumber === lineNumber);\n        return matches;\n      });\n\n      // console.log(\"Matching stack frame: \", matchingStackFrame);\n\n      if (matchingStackFrame) {\n        /*\n        const frameIndex = this.state.stackFrames.indexOf(matchingStackFrame);\n        const originalStackFrame = parsedFramesNoSourcemaps[frameIndex];\n        console.log(\"Original stack frame: \", originalStackFrame);\n        */\n        this.props.openFile(fileName, lineNumber, matchingStackFrame);\n      }\n    }\n  };\n\n  openDocs: React.MouseEventHandler<HTMLAnchorElement> = (e) => {\n    e.stopPropagation();\n    window.open(\n      'https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/Features/Trace.md',\n    );\n  };\n\n  render() {\n    const { stackFrames, showDocsLink } = this.state;\n\n    if (showDocsLink) {\n      return (\n        <div style={rootStyle}>\n          To enable tracing action calls, you should set `trace` option to\n          `true` for Redux DevTools enhancer. Refer to{' '}\n          <a href=\"#\" onClick={this.openDocs}>\n            this page\n          </a>{' '}\n          for more details.\n        </div>\n      );\n    }\n\n    return (\n      <div style={rootStyle}>\n        <StackTrace\n          stackFrames={stackFrames}\n          errorName=\"N/A\"\n          contextSize={3}\n          editorHandler={this.onStackLocationClicked}\n        />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/openFile.ts",
    "content": "import StackFrame from './react-error-overlay/utils/stack-frame.js';\n\nconst isFF = navigator.userAgent.includes('Firefox');\n\nfunction openResource(\n  fileName: string,\n  lineNumber: number,\n  stackFrame: StackFrame,\n) {\n  const adjustedLineNumber = Math.max(lineNumber - 1, 0);\n  chrome.devtools.panels.openResource(fileName, adjustedLineNumber, ((result: {\n    isError?: boolean;\n  }) => {\n    //console.log(\"openResource callback args: \", callbackArgs);\n    if (result.isError) {\n      const { fileName: finalFileName, lineNumber: finalLineNumber } =\n        stackFrame;\n      const adjustedLineNumber = Math.max(finalLineNumber! - 1, 0);\n      chrome.devtools.panels.openResource(\n        finalFileName!,\n        adjustedLineNumber,\n        (/* result */) => {\n          // console.log(\"openResource result: \", result);\n        },\n      );\n    }\n  }) as () => void);\n}\n\nfunction openAndCloseTab(url: string) {\n  chrome.tabs.create({ url }, (tab) => {\n    const removeTab = () => {\n      chrome.windows.onFocusChanged.removeListener(removeTab);\n      if (tab && tab.id) {\n        chrome.tabs.remove(tab.id, () => {\n          if (chrome.runtime.lastError) console.log(chrome.runtime.lastError);\n          else if (chrome.devtools && chrome.devtools.inspectedWindow) {\n            void chrome.tabs.update(chrome.devtools.inspectedWindow.tabId, {\n              active: true,\n            });\n          }\n        });\n      }\n    };\n    if (chrome.windows) chrome.windows.onFocusChanged.addListener(removeTab);\n  });\n}\n\nfunction openInIframe(url: string) {\n  const iframe = document.createElement('iframe');\n  iframe.src = url;\n  iframe.style.display = 'none';\n  document.body.appendChild(iframe);\n  setTimeout(() => iframe.parentNode!.removeChild(iframe), 3000);\n}\n\nfunction openInEditor(editor: string, path: string, stackFrame: StackFrame) {\n  const projectPath = path.replace(/\\/$/, '');\n  const file =\n    stackFrame._originalFileName ||\n    (stackFrame as unknown as { finalFileName: string }).finalFileName ||\n    stackFrame.fileName ||\n    '';\n  let filePath = /^https?:\\/\\//.test(file)\n    ? file.replace(/^https?:\\/\\/[^/]*/, '')\n    : file.replace(/^\\w+:\\/\\//, '');\n  filePath = filePath.replace(/^\\/~\\//, '/node_modules/');\n  const line = stackFrame._originalLineNumber || stackFrame.lineNumber || '0';\n  const column =\n    stackFrame._originalColumnNumber || stackFrame.columnNumber || '0';\n  let url;\n\n  switch (editor) {\n    case 'vscode':\n    case 'code':\n      url = `vscode://file/${projectPath}${filePath}:${line}:${column}`;\n      break;\n    case 'atom':\n      url = `atom://core/open/file?filename=${projectPath}${filePath}&line=${line}&column=${column}`;\n      break;\n    case 'webstorm':\n    case 'phpstorm':\n    case 'idea':\n      url = `${editor}://open?file=${projectPath}${filePath}&line=${line}&column=${column}`;\n      break;\n    default:\n      // sublime, emacs, macvim, textmate + custom like https://github.com/eclemens/atom-url-handler\n      url = `${editor}://open/?url=file://${projectPath}${filePath}&line=${line}&column=${column}`;\n  }\n  if (chrome.devtools && !isFF) {\n    if (chrome.tabs) openAndCloseTab(url);\n    else window.open(url);\n  } else {\n    openInIframe(url);\n  }\n}\n\nexport default function openFile(\n  fileName: string,\n  lineNumber: number,\n  stackFrame: StackFrame,\n) {\n  if (!chrome || !chrome.storage) return; // TODO: Pass editor settings for using outside of browser extension\n  const storage = isFF\n    ? chrome.storage.local\n    : chrome.storage.sync || chrome.storage.local;\n  storage.get(\n    ['useEditor', 'editor', 'projectPath'],\n    function ({ useEditor, editor, projectPath }) {\n      if (\n        useEditor &&\n        projectPath &&\n        typeof editor === 'string' &&\n        /^\\w{1,30}$/.test(editor)\n      ) {\n        openInEditor(editor.toLowerCase(), projectPath as string, stackFrame);\n      } else {\n        if (\n          chrome.devtools &&\n          chrome.devtools.panels &&\n          !!chrome.devtools.panels.openResource\n        ) {\n          openResource(fileName, lineNumber, stackFrame);\n        } else if (chrome.runtime && (chrome.runtime.openOptionsPage || isFF)) {\n          if (chrome.devtools && isFF) {\n            chrome.devtools.inspectedWindow.eval(\n              'confirm(\"Set the editor to open the file in?\")',\n              (result) => {\n                if (!result) return;\n                void chrome.runtime.sendMessage({ type: 'OPEN_OPTIONS' });\n              },\n            );\n          } else if (confirm('Set the editor to open the file in?')) {\n            void chrome.runtime.openOptionsPage();\n          }\n        }\n      }\n    },\n  );\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/presets.ts",
    "content": "export const toExclude = /chrome-extension:\\/\\/|moz-extension:\\/\\//;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/components/CodeBlock.tsx",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport React, { CSSProperties } from 'react';\n\nconst preStyle: CSSProperties = {\n  position: 'relative',\n  display: 'block',\n  backgroundColor: '#000',\n  padding: '0.5em',\n  marginTop: '0.5em',\n  marginBottom: '0.5em',\n  overflowX: 'auto',\n  whiteSpace: 'pre-wrap',\n  borderRadius: '0.25rem',\n};\n\nconst codeStyle = {\n  fontFamily: 'Consolas, Menlo, monospace',\n};\n\ninterface CodeBlockPropsType {\n  main: boolean;\n  codeHTML: string;\n}\n\nfunction CodeBlock(props: CodeBlockPropsType) {\n  const codeBlock = { __html: props.codeHTML };\n\n  return (\n    <pre style={preStyle}>\n      <code style={codeStyle} dangerouslySetInnerHTML={codeBlock} />\n    </pre>\n  );\n}\n\nexport default CodeBlock;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/components/Collapsible.tsx",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport React, { Component, CSSProperties, ReactNode } from 'react';\nimport { base16Themes } from 'react-base16-styling';\n\nconst theme = base16Themes.nicinabox;\n\nconst _collapsibleStyle: CSSProperties = {\n  color: theme.base06,\n  backgroundColor: theme.base01,\n  cursor: 'pointer',\n  border: 'none',\n  display: 'block',\n  width: '100%',\n  textAlign: 'left',\n  fontSize: '1em',\n  padding: '0px 5px',\n  lineHeight: '1.5',\n};\n\nconst collapsibleCollapsedStyle: CSSProperties = {\n  ..._collapsibleStyle,\n  marginBottom: '1.5em',\n};\n\nconst collapsibleExpandedStyle: CSSProperties = {\n  ..._collapsibleStyle,\n  marginBottom: '0.6em',\n};\n\ninterface Props {\n  collapsedByDefault?: boolean;\n  children: ReactNode[];\n}\n\ninterface State {\n  collapsed: boolean | undefined;\n}\n\nclass Collapsible extends Component<Props, State> {\n  state: State = {\n    collapsed: undefined,\n  };\n\n  toggleCollapsed = () => {\n    this.setState((state) => ({\n      collapsed: !this.isCollapsed(state),\n    }));\n  };\n\n  isCollapsed = (state: State) =>\n    state.collapsed === undefined\n      ? this.props.collapsedByDefault\n      : state.collapsed;\n\n  render() {\n    const count = this.props.children.length;\n    const collapsed = this.isCollapsed(this.state);\n    return (\n      <div>\n        <button\n          onClick={this.toggleCollapsed}\n          style={\n            collapsed ? collapsibleCollapsedStyle : collapsibleExpandedStyle\n          }\n        >\n          {(collapsed ? '▶' : '▼') +\n            ` ${count} stack frames were ` +\n            (collapsed ? 'collapsed.' : 'expanded.')}\n        </button>\n        <div style={{ display: collapsed ? 'none' : 'block' }}>\n          {this.props.children}\n          <button\n            onClick={this.toggleCollapsed}\n            style={collapsibleExpandedStyle}\n          >\n            {`▲ ${count} stack frames were expanded.`}\n          </button>\n        </div>\n      </div>\n    );\n  }\n}\n\nexport default Collapsible;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackFrame.tsx",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport React, { Component, CSSProperties } from 'react';\nimport CodeBlock from './StackFrameCodeBlock.js';\nimport { getPrettyURL } from '../utils/getPrettyURL.js';\nimport { base16Themes } from 'react-base16-styling';\n\nimport type { StackFrame as StackFrameType } from '../utils/stack-frame.js';\nimport type { ErrorLocation } from '../utils/parseCompileError.js';\n\nconst theme = base16Themes.nicinabox;\n\nconst linkStyle: CSSProperties = {\n  fontSize: '0.9em',\n  marginBottom: '0.9em',\n};\n\nconst anchorStyle: CSSProperties = {\n  textDecoration: 'none',\n  color: theme.base05,\n  cursor: 'pointer',\n};\n\nconst codeAnchorStyle: CSSProperties = {\n  cursor: 'pointer',\n};\n\nconst toggleStyle: CSSProperties = {\n  marginBottom: '1.5em',\n  color: theme.base05,\n  cursor: 'pointer',\n  border: 'none',\n  display: 'block',\n  width: '100%',\n  textAlign: 'left',\n  background: 'transparent',\n  fontFamily: 'Consolas, Menlo, monospace',\n  fontSize: '1em',\n  padding: '0px',\n  lineHeight: '1.5',\n};\n\ninterface Props {\n  frame: StackFrameType;\n  contextSize: number;\n  critical: boolean;\n  showCode: boolean;\n  editorHandler: (errorLoc: ErrorLocation) => void;\n}\n\ninterface State {\n  compiled: boolean;\n}\n\nclass StackFrame extends Component<Props, State> {\n  state: State = {\n    compiled: false,\n  };\n\n  toggleCompiled = () => {\n    this.setState((state) => ({\n      compiled: !state.compiled,\n    }));\n  };\n\n  getErrorLocation(): ErrorLocation | null {\n    const { _originalFileName: fileName, _originalLineNumber: lineNumber } =\n      this.props.frame;\n    // Unknown file\n    if (!fileName) {\n      return null;\n    }\n    // e.g. \"/path-to-my-app/webpack/bootstrap eaddeb46b67d75e4dfc1\"\n    const isInternalWebpackBootstrapCode = fileName.trim().includes(' ');\n    if (isInternalWebpackBootstrapCode) {\n      return null;\n    }\n    // Code is in a real file\n    return { fileName, lineNumber: lineNumber || 1 };\n  }\n\n  editorHandler = () => {\n    const errorLoc = this.getErrorLocation();\n    if (!errorLoc) {\n      return;\n    }\n    this.props.editorHandler(errorLoc);\n  };\n\n  onKeyDown: React.KeyboardEventHandler<HTMLSpanElement> = (\n    e /* : SyntheticKeyboardEvent<> */,\n  ) => {\n    if (e.key === 'Enter') {\n      this.editorHandler();\n    }\n  };\n\n  render() {\n    const { frame, contextSize, critical, showCode } = this.props;\n    const {\n      fileName,\n      lineNumber,\n      columnNumber,\n      _scriptCode: scriptLines,\n      _originalFileName: sourceFileName,\n      _originalLineNumber: sourceLineNumber,\n      _originalColumnNumber: sourceColumnNumber,\n      _originalScriptCode: sourceLines,\n    } = frame;\n    const functionName = frame.getFunctionName();\n\n    const compiled = this.state.compiled;\n    const url = getPrettyURL(\n      sourceFileName,\n      sourceLineNumber,\n      sourceColumnNumber,\n      fileName,\n      lineNumber,\n      columnNumber,\n      compiled,\n    );\n\n    let codeBlockProps = null;\n    if (showCode) {\n      if (\n        compiled &&\n        scriptLines &&\n        scriptLines.length !== 0 &&\n        lineNumber != null\n      ) {\n        codeBlockProps = {\n          lines: scriptLines,\n          lineNum: lineNumber,\n          columnNum: columnNumber,\n          contextSize,\n          main: critical,\n        };\n      } else if (\n        !compiled &&\n        sourceLines &&\n        sourceLines.length !== 0 &&\n        sourceLineNumber != null\n      ) {\n        codeBlockProps = {\n          lines: sourceLines,\n          lineNum: sourceLineNumber,\n          columnNum: sourceColumnNumber,\n          contextSize,\n          main: critical,\n        };\n      }\n    }\n\n    const canOpenInEditor =\n      this.getErrorLocation() !== null && this.props.editorHandler !== null;\n    return (\n      <div>\n        <div>{functionName}</div>\n        <div style={linkStyle}>\n          <span\n            style={canOpenInEditor ? anchorStyle : undefined}\n            onClick={canOpenInEditor ? this.editorHandler : undefined}\n            onKeyDown={canOpenInEditor ? this.onKeyDown : undefined}\n            tabIndex={canOpenInEditor ? 0 : undefined}\n          >\n            {url}\n          </span>\n        </div>\n        {codeBlockProps && (\n          <span>\n            <span\n              onClick={canOpenInEditor ? this.editorHandler : undefined}\n              style={canOpenInEditor ? codeAnchorStyle : undefined}\n            >\n              <CodeBlock {...codeBlockProps} />\n            </span>\n            <button style={toggleStyle} onClick={this.toggleCompiled}>\n              {'View ' + (compiled ? 'source' : 'compiled')}\n            </button>\n          </span>\n        )}\n      </div>\n    );\n  }\n}\n\nexport default StackFrame;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackFrameCodeBlock.tsx",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport React from 'react';\nimport CodeBlock from '../components/CodeBlock.js';\nimport { applyStyles } from '../utils/dom/css.js';\nimport { absolutifyCaret } from '../utils/dom/absolutifyCaret.js';\nimport { ScriptLine } from '../utils/stack-frame.js';\nimport generateAnsiHTML from '../utils/generateAnsiHTML.js';\n\nimport { codeFrameColumns } from '@babel/code-frame';\nimport { base16Themes } from 'react-base16-styling';\n\nconst theme = base16Themes.nicinabox;\n\ninterface StackFrameCodeBlockPropsType {\n  lines: ScriptLine[];\n  lineNum: number;\n  columnNum: number | null | undefined;\n  contextSize: number;\n  main: boolean;\n}\n\nfunction StackFrameCodeBlock(props: StackFrameCodeBlockPropsType) {\n  const { lines, lineNum, columnNum, contextSize, main } = props;\n  const sourceCode: string[] = [];\n  let whiteSpace = Infinity;\n  lines.forEach(function (e) {\n    const { content: text } = e;\n    const m = /^\\s*/.exec(text);\n    if (text === '') {\n      return;\n    }\n    if (m && m[0]) {\n      whiteSpace = Math.min(whiteSpace, m[0].length);\n    } else {\n      whiteSpace = 0;\n    }\n  });\n  lines.forEach(function (e) {\n    let { content: text } = e;\n    const { lineNumber: line } = e;\n\n    if (isFinite(whiteSpace)) {\n      text = text.substring(whiteSpace);\n    }\n    sourceCode[line - 1] = text;\n  });\n  const ansiHighlight = codeFrameColumns(\n    sourceCode.join('\\n'),\n    {\n      start: {\n        line: lineNum,\n        column:\n          columnNum == null\n            ? 0\n            : columnNum - (isFinite(whiteSpace) ? whiteSpace : 0),\n      },\n    },\n    {\n      forceColor: true,\n      linesAbove: contextSize,\n      linesBelow: contextSize,\n    },\n  );\n  const htmlHighlight = generateAnsiHTML(ansiHighlight);\n  const code = document.createElement('code');\n  code.innerHTML = htmlHighlight;\n  absolutifyCaret(code);\n\n  const ccn = code.childNodes;\n  // eslint-disable-next-line\n  oLoop: for (let index = 0; index < ccn.length; ++index) {\n    const node = ccn[index];\n    const ccn2 = node.childNodes;\n    for (let index2 = 0; index2 < ccn2.length; ++index2) {\n      const lineNode = ccn2[index2];\n      const text = (lineNode as HTMLElement).innerText;\n      if (text == null) {\n        continue;\n      }\n      if (!text.includes(` ${lineNum} |`)) {\n        continue;\n      }\n      // $FlowFixMe\n      applyStyles(node as HTMLElement, {\n        backgroundColor: main ? theme.base02 : theme.base01,\n      });\n      // eslint-disable-next-line\n      break oLoop;\n    }\n  }\n\n  return <CodeBlock main={main} codeHTML={code.innerHTML} />;\n}\n\nexport default StackFrameCodeBlock;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackTrace.tsx",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport React, { Component, ReactElement } from 'react';\nimport StackFrame from './StackFrame.js';\nimport Collapsible from '../components/Collapsible.js';\nimport { isInternalFile } from '../utils/isInternalFile.js';\nimport { isBultinErrorName } from '../utils/isBultinErrorName.js';\n\nimport type { StackFrame as StackFrameType } from '../utils/stack-frame.js';\nimport type { ErrorLocation } from '../utils/parseCompileError.js';\n\nconst traceStyle = {\n  fontSize: '1em',\n  flex: '0 1 auto',\n  minHeight: '0px',\n  overflow: 'auto',\n};\n\ninterface Props {\n  stackFrames: StackFrameType[];\n  errorName: string;\n  contextSize: number;\n  editorHandler: (errorLoc: ErrorLocation) => void;\n}\n\nclass StackTrace extends Component<Props> {\n  renderFrames() {\n    const { stackFrames, errorName, contextSize, editorHandler } = this.props;\n    const renderedFrames: ReactElement[] = [];\n    let hasReachedAppCode = false,\n      currentBundle: ReactElement[] = [],\n      bundleCount = 0,\n      anyNodeExpanded = false;\n\n    stackFrames.forEach((frame, index) => {\n      const { fileName, _originalFileName: sourceFileName } = frame;\n      const isInternalUrl = isInternalFile(sourceFileName, fileName);\n      const isThrownIntentionally = !isBultinErrorName(errorName);\n      const shouldCollapse =\n        isInternalUrl && (isThrownIntentionally || hasReachedAppCode);\n\n      if (!shouldCollapse) {\n        anyNodeExpanded = true;\n      }\n\n      if (!isInternalUrl) {\n        hasReachedAppCode = true;\n      }\n\n      const frameEle = (\n        <StackFrame\n          key={`frame-${index}`}\n          frame={frame}\n          contextSize={contextSize}\n          critical={index === 0}\n          showCode={!shouldCollapse}\n          editorHandler={editorHandler}\n        />\n      );\n      const lastElement = index === stackFrames.length - 1;\n\n      if (shouldCollapse) {\n        currentBundle.push(frameEle);\n      }\n\n      if (!shouldCollapse || lastElement) {\n        if (currentBundle.length === 1) {\n          renderedFrames.push(currentBundle[0]);\n        } else if (currentBundle.length > 1) {\n          bundleCount++;\n          renderedFrames.push(\n            <Collapsible\n              collapsedByDefault={anyNodeExpanded}\n              key={`bundle-${bundleCount}`}\n            >\n              {currentBundle}\n            </Collapsible>,\n          );\n        }\n        currentBundle = [];\n      }\n\n      if (!shouldCollapse) {\n        renderedFrames.push(frameEle);\n      }\n    });\n\n    return renderedFrames;\n  }\n\n  render() {\n    return (\n      <div data-testid=\"stack-trace\" style={traceStyle}>\n        {this.renderFrames()}\n      </div>\n    );\n  }\n}\n\nexport default StackTrace;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/dom/absolutifyCaret.ts",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nfunction removeNextBr(parent: Node, component: Element | null | undefined) {\n  while (component != null && component.tagName.toLowerCase() !== 'br') {\n    component = component.nextElementSibling;\n  }\n  if (component != null) {\n    parent.removeChild(component);\n  }\n}\n\nfunction absolutifyCaret(component: Node) {\n  const ccn = component.childNodes;\n  for (let index = 0; index < ccn.length; ++index) {\n    const c = ccn[index] as HTMLElement;\n    // $FlowFixMe\n    if (c.tagName.toLowerCase() !== 'span') {\n      continue;\n    }\n    const _text = c.innerText;\n    if (_text == null) {\n      continue;\n    }\n    const text = _text.replace(/\\s/g, '');\n    if (text !== '|^') {\n      continue;\n    }\n    // $FlowFixMe\n    c.style.position = 'absolute';\n    c.style.marginTop = '-7px';\n    // $FlowFixMe\n    removeNextBr(component, c);\n  }\n}\n\nexport { absolutifyCaret };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/dom/css.ts",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nlet injectedCount = 0;\nconst injectedCache: { [key: number]: HTMLStyleElement } = {};\n\nfunction getHead(document: Document) {\n  return document.head || document.getElementsByTagName('head')[0];\n}\n\nfunction injectCss(document: Document, css: string): number {\n  const head = getHead(document);\n  const style = document.createElement('style');\n  style.type = 'text/css';\n  style.appendChild(document.createTextNode(css));\n  head.appendChild(style);\n\n  injectedCache[++injectedCount] = style;\n  return injectedCount;\n}\n\nfunction removeCss(document: Document, ref: number) {\n  if (injectedCache[ref] == null) {\n    return;\n  }\n  const head = getHead(document);\n  head.removeChild(injectedCache[ref]);\n  delete injectedCache[ref];\n}\n\nfunction applyStyles(\n  element: HTMLElement,\n  styles: Partial<CSSStyleDeclaration>,\n) {\n  element.setAttribute('style', '');\n  for (const key in styles) {\n    if (!Object.prototype.hasOwnProperty.call(styles, key)) {\n      continue;\n    }\n    // $FlowFixMe\n    element.style[key] = styles[key]!;\n  }\n}\n\nexport { getHead, injectCss, removeCss, applyStyles };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/generateAnsiHTML.ts",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport Anser from 'anser';\nimport { base16Themes } from 'react-base16-styling';\nimport { encode } from 'html-entities';\n\nconst theme = base16Themes.nicinabox;\n\nconst anserMap = {\n  'ansi-bright-black': theme.base03,\n  'ansi-bright-yellow': theme.base0A,\n  'ansi-yellow': theme.base0B,\n  'ansi-bright-green': theme.base0B,\n  'ansi-green': theme.base0F,\n  'ansi-bright-cyan': theme.base0D,\n  'ansi-cyan': theme.base0C,\n  'ansi-bright-red': theme.base09,\n  'ansi-red': theme.base0E,\n  'ansi-bright-magenta': theme.base0F,\n  'ansi-magenta': theme.base0E,\n  'ansi-white': theme.base00,\n};\n\nfunction generateAnsiHTML(txt: string): string {\n  const arr = new Anser().ansiToJson(encode(txt), {\n    use_classes: true,\n  });\n\n  let result = '';\n  let open = false;\n  for (let index = 0; index < arr.length; ++index) {\n    const c = arr[index];\n    const content = c.content,\n      fg = c.fg;\n\n    const contentParts = content.split('\\n');\n    for (let _index = 0; _index < contentParts.length; ++_index) {\n      if (!open) {\n        result += '<span data-ansi-line=\"true\">';\n        open = true;\n      }\n      const part = contentParts[_index].replace('\\r', '');\n      const color = anserMap[fg as keyof typeof anserMap];\n      if (color != null) {\n        result += '<span style=\"color: ' + color + ';\">' + part + '</span>';\n      } else {\n        if (fg != null) {\n          console.log('Missing color mapping:', fg); // eslint-disable-line no-console\n        }\n        result += '<span>' + part + '</span>';\n      }\n      if (_index < contentParts.length - 1) {\n        result += '</span>';\n        open = false;\n        result += '<br/>';\n      }\n    }\n  }\n  if (open) {\n    result += '</span>';\n    open = false;\n  }\n  return result;\n}\n\nexport default generateAnsiHTML;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/getLinesAround.ts",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { ScriptLine } from './stack-frame.js';\n\n/**\n *\n * @param {number} line The line number to provide context around.\n * @param {number} count The number of lines you'd like for context.\n * @param {string[] | string} lines The source code.\n */\nfunction getLinesAround(\n  line: number,\n  count: number,\n  lines: string[] | string,\n): ScriptLine[] {\n  if (typeof lines === 'string') {\n    lines = lines.split('\\n');\n  }\n  const result = [];\n  for (\n    let index = Math.max(0, line - 1 - count);\n    index <= Math.min(lines.length - 1, line - 1 + count);\n    ++index\n  ) {\n    result.push(new ScriptLine(index + 1, lines[index], index === line - 1));\n  }\n  return result;\n}\n\nexport { getLinesAround };\nexport default getLinesAround;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/getPrettyURL.ts",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nfunction getPrettyURL(\n  sourceFileName: string | null | undefined,\n  sourceLineNumber: number | null | undefined,\n  sourceColumnNumber: number | null | undefined,\n  fileName: string | null | undefined,\n  lineNumber: number | null | undefined,\n  columnNumber: number | null | undefined,\n  compiled: boolean,\n): string {\n  let prettyURL;\n  if (!compiled && sourceFileName && typeof sourceLineNumber === 'number') {\n    // Remove everything up to the first /src/ or /node_modules/\n    const trimMatch = /^[/|\\\\].*?[/|\\\\]((src|node_modules)[/|\\\\].*)/.exec(\n      sourceFileName,\n    );\n    if (trimMatch && trimMatch[1]) {\n      prettyURL = trimMatch[1];\n    } else {\n      prettyURL = sourceFileName;\n    }\n    prettyURL += `:${sourceLineNumber}`;\n    // Note: we intentionally skip 0's because they're produced by cheap Webpack maps\n    if (sourceColumnNumber) {\n      prettyURL += `:${sourceColumnNumber}`;\n    }\n  } else if (fileName && typeof lineNumber === 'number') {\n    prettyURL = `${fileName}:${lineNumber}`;\n    // Note: we intentionally skip 0's because they're produced by cheap Webpack maps\n    if (columnNumber) {\n      prettyURL += `:${columnNumber}`;\n    }\n  } else {\n    prettyURL = 'unknown';\n  }\n  return prettyURL.replace('webpack://', '.');\n}\n\nexport { getPrettyURL };\nexport default getPrettyURL;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/getSourceMap.ts",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { RawSourceMap, SourceMapConsumer } from 'source-map';\n\n/**\n * A wrapped instance of a <code>{@link https://github.com/mozilla/source-map SourceMapConsumer}</code>.\n *\n * This exposes methods which will be indifferent to changes made in <code>{@link https://github.com/mozilla/source-map source-map}</code>.\n */\nexport class SourceMap {\n  __source_map: SourceMapConsumer;\n\n  constructor(sourceMap: SourceMapConsumer) {\n    this.__source_map = sourceMap;\n  }\n\n  /**\n   * Returns the original code position for a generated code position.\n   * @param {number} line The line of the generated code position.\n   * @param {number} column The column of the generated code position.\n   */\n  getOriginalPosition(\n    line: number,\n    column: number,\n  ): { source: string | null; line: number | null; column: number | null } {\n    const {\n      line: l,\n      column: c,\n      source: s,\n    } = this.__source_map.originalPositionFor({\n      line,\n      column,\n    });\n    return { line: l, column: c, source: s };\n  }\n\n  /**\n   * Returns the generated code position for an original position.\n   * @param {string} source The source file of the original code position.\n   * @param {number} line The line of the original code position.\n   * @param {number} column The column of the original code position.\n   */\n  getGeneratedPosition(\n    source: string,\n    line: number,\n    column: number,\n  ): { line: number | null; column: number | null } {\n    const { line: l, column: c } = this.__source_map.generatedPositionFor({\n      source,\n      line,\n      column,\n    });\n    return {\n      line: l,\n      column: c,\n    };\n  }\n\n  /**\n   * Returns the code for a given source file name.\n   * @param {string} sourceName The name of the source file.\n   */\n  getSource(sourceName: string): string | null {\n    return this.__source_map.sourceContentFor(sourceName);\n  }\n\n  getSources(): string[] {\n    return (this.__source_map as unknown as { sources: string[] }).sources;\n  }\n}\n\nexport function extractSourceMapUrl(\n  fileUri: string,\n  fileContents: string,\n): Promise<string> {\n  const regex = /\\/\\/[#@] ?sourceMappingURL=([^\\s'\"]+)\\s*$/gm;\n  let match = null;\n  for (;;) {\n    const next = regex.exec(fileContents);\n    if (next == null) {\n      break;\n    }\n    match = next;\n  }\n  if (!(match && match[1])) {\n    return Promise.reject(\n      new Error(`Cannot find a source map directive for ${fileUri}.`),\n    );\n  }\n  return Promise.resolve(match[1].toString());\n}\n\n/**\n * Returns an instance of <code>{@link SourceMap}</code> for a given fileUri and fileContents.\n * @param {string} fileUri The URI of the source file.\n * @param {string} fileContents The contents of the source file.\n */\nexport async function getSourceMap(\n  //function getSourceMap(\n  fileUri: string,\n  fileContents: string,\n): Promise<SourceMap> {\n  let sm = await extractSourceMapUrl(fileUri, fileContents);\n  if (sm.indexOf('data:') === 0) {\n    const base64 = /^data:application\\/json;([\\w=:\"-]+;)*base64,/;\n    const match2 = base64.exec(sm);\n    if (!match2) {\n      throw new Error(\n        'Sorry, non-base64 inline source-map encoding is not supported.',\n      );\n    }\n    sm = sm.substring(match2[0].length);\n    sm = window.atob(sm);\n    sm = JSON.parse(sm);\n    return new SourceMap(new SourceMapConsumer(sm as unknown as RawSourceMap));\n  } else {\n    const index = fileUri.lastIndexOf('/');\n    const url = fileUri.substring(0, index + 1) + sm;\n    const obj = await fetch(url).then((res) => res.json());\n    return new SourceMap(new SourceMapConsumer(obj as RawSourceMap));\n  }\n\n  /*\n  return extractSourceMapUrl(fileUri, fileContents)\n      .then(sm => {\n          if (sm.indexOf('data:') === 0) {\n              const base64 = /^data:application\\/json;([\\w=:\"-]+;)*base64,/;\n              const match2 = sm.match(base64);\n              if (!match2) {\n                  throw new Error(\n                      'Sorry, non-base64 inline source-map encoding is not supported.'\n                  );\n              }\n              sm = sm.substring(match2[0].length);\n              sm = window.atob(sm);\n              sm = JSON.parse(sm);\n              return new SourceMap(new SourceMapConsumer(sm));\n          } else {\n              const index = fileUri.lastIndexOf('/');\n              const url = fileUri.substring(0, index + 1) + sm;\n\n              return fetch(url).then(res => res.json())\n                  .then(obj => {\n                    return new SourceMap(new SourceMapConsumer(obj))\n                  })\n              //const obj = await fetch(url).then(res => res.json());\n              //return new SourceMap(new SourceMapConsumer(obj));\n          }\n      });\n      */\n}\n\nexport default getSourceMap;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/getStackFrames.ts",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport type { StackFrame } from './stack-frame.js';\nimport { parse } from './parser.js';\nimport { map } from './mapper.js';\nimport { unmap } from './unmapper.js';\nimport { toExclude } from '../../presets.js';\n\nfunction getStackFrames(\n  error: Error,\n  unhandledRejection = false, // eslint-disable-line no-unused-vars\n  contextSize = 3,\n): Promise<StackFrame[] | null> {\n  const parsedFrames = parse(error);\n  let enhancedFramesPromise;\n  if (\n    (\n      error as unknown as {\n        __unmap_source: string | { uri: string; contents: string };\n      }\n    ).__unmap_source\n  ) {\n    enhancedFramesPromise = unmap(\n      // $FlowFixMe\n      (\n        error as unknown as {\n          __unmap_source: string | { uri: string; contents: string };\n        }\n      ).__unmap_source,\n      parsedFrames,\n      contextSize,\n    );\n  } else {\n    enhancedFramesPromise = map(parsedFrames, contextSize);\n  }\n  return enhancedFramesPromise.then((enhancedFrames) => {\n    /*\n    if (\n      enhancedFrames\n        .map(f => f._originalFileName)\n        .filter(f => f != null && f.indexOf('node_modules') === -1).length === 0\n    ) {\n      return null;\n    }\n    */\n    return enhancedFrames.filter(\n      ({ functionName, fileName }) =>\n        (functionName == null ||\n          !functionName.includes('__stack_frame_overlay_proxy_console__')) &&\n        !toExclude.test(fileName!),\n    );\n  });\n}\n\nexport default getStackFrames;\nexport { getStackFrames };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/isBultinErrorName.ts",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nfunction isBultinErrorName(errorName: string | null | undefined) {\n  switch (errorName) {\n    case 'EvalError':\n    case 'InternalError':\n    case 'RangeError':\n    case 'ReferenceError':\n    case 'SyntaxError':\n    case 'TypeError':\n    case 'URIError':\n      return true;\n    default:\n      return false;\n  }\n}\n\nexport { isBultinErrorName };\nexport default isBultinErrorName;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/isInternalFile.ts",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nfunction isInternalFile(\n  sourceFileName: string | null | undefined,\n  fileName: string | null | undefined,\n) {\n  return (\n    sourceFileName == null ||\n    sourceFileName === '' ||\n    sourceFileName.includes('/~/') ||\n    sourceFileName.includes('/node_modules/') ||\n    sourceFileName.trim().includes(' ') ||\n    fileName == null ||\n    fileName === ''\n  );\n}\n\nexport { isInternalFile };\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/mapper.ts",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport StackFrame from './stack-frame.js';\nimport { getSourceMap, SourceMap } from './getSourceMap.js';\nimport { getLinesAround } from './getLinesAround.js';\n\n/**\n * Enhances a set of <code>StackFrame</code>s with their original positions and code (when available).\n * @param {StackFrame[]} frames A set of <code>StackFrame</code>s which contain (generated) code positions.\n * @param {number} [contextLines=3] The number of lines to provide before and after the line specified in the <code>StackFrame</code>.\n */\nasync function map(\n  frames: StackFrame[],\n  contextLines = 3,\n): Promise<StackFrame[]> {\n  const cache: {\n    [fileName: string]: {\n      readonly fileSource: string;\n      readonly map: SourceMap;\n    };\n  } = {};\n  const files: string[] = [];\n  frames.forEach((frame) => {\n    const { fileName } = frame;\n    if (fileName == null) {\n      return;\n    }\n    if (files.includes(fileName)) {\n      return;\n    }\n    files.push(fileName);\n  });\n  await Promise.allSettled(\n    files.map(async (fileName) => {\n      const fileSource = await fetch(fileName).then((r) => r.text());\n      const map = await getSourceMap(fileName, fileSource);\n      cache[fileName] = { fileSource, map };\n    }),\n  );\n  return frames.map((frame) => {\n    const { functionName, fileName, lineNumber, columnNumber } = frame;\n    const { map, fileSource } = cache[fileName!] || {};\n    if (map == null || lineNumber == null) {\n      return frame;\n    }\n    const { source, line, column } = map.getOriginalPosition(\n      lineNumber,\n      columnNumber!,\n    );\n    const originalSource = source == null ? [] : map.getSource(source) || [];\n    return new StackFrame(\n      functionName,\n      fileName,\n      lineNumber,\n      columnNumber,\n      getLinesAround(lineNumber, contextLines, fileSource),\n      functionName,\n      source,\n      line,\n      column,\n      getLinesAround(line!, contextLines, originalSource),\n    );\n  });\n}\n\nexport { map };\nexport default map;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/parseCompileError.ts",
    "content": "import Anser from 'anser';\n\nexport interface ErrorLocation {\n  fileName: string;\n  lineNumber: number;\n  colNumber?: number;\n}\n\nconst filePathRegex = /^\\.(\\/[^/\\n ]+)+\\.[^/\\n ]+$/;\n\nconst lineNumberRegexes = [\n  // Babel syntax errors\n  // Based on syntax error formating of babylon parser\n  // https://github.com/babel/babylon/blob/v7.0.0-beta.22/src/parser/location.js#L19\n  /^.*\\((\\d+):(\\d+)\\)$/,\n\n  // ESLint errors\n  // Based on eslintFormatter in react-dev-utils\n  /^Line (\\d+):.+$/,\n];\n\n// Based on error formatting of webpack\n// https://github.com/webpack/webpack/blob/v3.5.5/lib/Stats.js#L183-L217\nfunction parseCompileError(message: string): ErrorLocation | null | undefined {\n  const lines: string[] = message.split('\\n');\n  let fileName = '';\n  let lineNumber = 0;\n  let colNumber = 0;\n\n  for (let i = 0; i < lines.length; i++) {\n    const line: string = Anser.ansiToText(lines[i]).trim();\n    if (!line) {\n      continue;\n    }\n\n    if (!fileName && filePathRegex.exec(line)) {\n      fileName = line;\n    }\n\n    let k = 0;\n    while (k < lineNumberRegexes.length) {\n      const match: string[] | null | undefined =\n        lineNumberRegexes[k].exec(line);\n      if (match) {\n        lineNumber = parseInt(match[1], 10);\n        // colNumber starts with 0 and hence add 1\n        colNumber = parseInt(match[2], 10) + 1 || 1;\n        break;\n      }\n      k++;\n    }\n\n    if (fileName && lineNumber) {\n      break;\n    }\n  }\n\n  return fileName && lineNumber ? { fileName, lineNumber, colNumber } : null;\n}\n\nexport default parseCompileError;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/parser.ts",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport StackFrame from './stack-frame.js';\n\nconst regexExtractLocation = /\\(?(.+?)(?::(\\d+))?(?::(\\d+))?\\)?$/;\n\nfunction extractLocation(token: string): [string, number, number] {\n  return regexExtractLocation\n    .exec(token)!\n    .slice(1)\n    .map((v) => {\n      const p = Number(v);\n      if (!isNaN(p)) {\n        return p;\n      }\n      return v;\n    }) as [string, number, number];\n}\n\nconst regexValidFrame_Chrome = /^\\s*(at|in)\\s.+(:\\d+)/;\nconst regexValidFrame_FireFox =\n  /(^|@)\\S+:\\d+|.+line\\s+\\d+\\s+>\\s+(eval|Function).+/;\n\nfunction parseStack(stack: string[]): StackFrame[] {\n  const frames = stack\n    .filter(\n      (e) => regexValidFrame_Chrome.test(e) || regexValidFrame_FireFox.test(e),\n    )\n    .map((e) => {\n      if (regexValidFrame_FireFox.test(e)) {\n        // Strip eval, we don't care about it\n        let isEval = false;\n        if (/ > (eval|Function)/.test(e)) {\n          e = e.replace(\n            / line (\\d+)(?: > eval line \\d+)* > (eval|Function):\\d+:\\d+/g,\n            ':$1',\n          );\n          isEval = true;\n        }\n        const data = e.split(/[@]/g);\n        const last = data.pop();\n        return new StackFrame(\n          data.join('@') || (isEval ? 'eval' : null),\n          ...extractLocation(last!),\n        );\n      } else {\n        // Strip eval, we don't care about it\n        if (e.includes('(eval ')) {\n          e = e.replace(/(\\(eval at [^()]*)|(\\),.*$)/g, '');\n        }\n        if (e.includes('(at ')) {\n          e = e.replace(/\\(at /, '(');\n        }\n        const data = e.trim().split(/\\s+/g).slice(1);\n        const last = data.pop();\n        return new StackFrame(\n          data.join(' ') || null,\n          ...extractLocation(last!),\n        );\n      }\n    });\n  return frames;\n}\n\n/**\n * Turns an <code>Error</code>, or similar object, into a set of <code>StackFrame</code>s.\n * @alias parse\n */\nfunction parseError(error: Error | string | string[]): StackFrame[] {\n  if (error == null) {\n    throw new Error('You cannot pass a null object.');\n  }\n  if (typeof error === 'string') {\n    return parseStack(error.split('\\n'));\n  }\n  if (Array.isArray(error)) {\n    return parseStack(error);\n  }\n  if (typeof error.stack === 'string') {\n    return parseStack(error.stack.split('\\n'));\n  }\n  throw new Error('The error you provided does not contain a stack trace.');\n}\n\nexport { parseError as parse };\nexport default parseError;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/stack-frame.ts",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n/** A container holding a script line. */\nclass ScriptLine {\n  /** The line number of this line of source. */\n  lineNumber: number;\n  /** The content (or value) of this line of source. */\n  content: string;\n  /** Whether or not this line should be highlighted. Particularly useful for error reporting with context. */\n  highlight: boolean;\n\n  constructor(lineNumber: number, content: string, highlight = false) {\n    this.lineNumber = lineNumber;\n    this.content = content;\n    this.highlight = highlight;\n  }\n}\n\n/**\n * A representation of a stack frame.\n */\nclass StackFrame {\n  functionName: string | null;\n  fileName: string | null;\n  lineNumber: number | null;\n  columnNumber: number | null;\n\n  _originalFunctionName: string | null;\n  _originalFileName: string | null;\n  _originalLineNumber: number | null;\n  _originalColumnNumber: number | null;\n\n  _scriptCode: ScriptLine[] | null;\n  _originalScriptCode: ScriptLine[] | null;\n\n  constructor(\n    functionName: string | null = null,\n    fileName: string | null = null,\n    lineNumber: number | null = null,\n    columnNumber: number | null = null,\n    scriptCode: ScriptLine[] | null = null,\n    sourceFunctionName: string | null = null,\n    sourceFileName: string | null = null,\n    sourceLineNumber: number | null = null,\n    sourceColumnNumber: number | null = null,\n    sourceScriptCode: ScriptLine[] | null = null,\n  ) {\n    if (functionName && functionName.indexOf('Object.') === 0) {\n      functionName = functionName.slice('Object.'.length);\n    }\n    if (\n      // Chrome has a bug with inferring function.name:\n      // https://github.com/facebook/create-react-app/issues/2097\n      // Let's ignore a meaningless name we get for top-level modules.\n      functionName === 'friendlySyntaxErrorLabel' ||\n      functionName === 'exports.__esModule' ||\n      functionName === '<anonymous>' ||\n      !functionName\n    ) {\n      functionName = null;\n    }\n    this.functionName = functionName;\n\n    this.fileName = fileName;\n    this.lineNumber = lineNumber;\n    this.columnNumber = columnNumber;\n\n    this._originalFunctionName = sourceFunctionName;\n    this._originalFileName = sourceFileName;\n    this._originalLineNumber = sourceLineNumber;\n    this._originalColumnNumber = sourceColumnNumber;\n\n    this._scriptCode = scriptCode;\n    this._originalScriptCode = sourceScriptCode;\n  }\n\n  /**\n   * Returns the name of this function.\n   */\n  getFunctionName(): string {\n    return this.functionName || '(anonymous function)';\n  }\n\n  /**\n   * Returns the source of the frame.\n   * This contains the file name, line number, and column number when available.\n   */\n  getSource(): string {\n    let str = '';\n    if (this.fileName != null) {\n      str += this.fileName + ':';\n    }\n    if (this.lineNumber != null) {\n      str += `${this.lineNumber}:`;\n    }\n    if (this.columnNumber != null) {\n      str += `${this.columnNumber}:`;\n    }\n    return str.slice(0, -1);\n  }\n\n  /**\n   * Returns a pretty version of this stack frame.\n   */\n  toString(): string {\n    const functionName = this.getFunctionName();\n    const source = this.getSource();\n    return `${functionName}${source ? ` (${source})` : ''}`;\n  }\n}\n\nexport { StackFrame, ScriptLine };\nexport default StackFrame;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/utils/unmapper.ts",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport path from 'path-browserify';\nimport StackFrame from './stack-frame.js';\nimport { getSourceMap } from './getSourceMap.js';\nimport { getLinesAround } from './getLinesAround.js';\n\nfunction count(search: string, string: string): number {\n  // Count starts at -1 becuse a do-while loop always runs at least once\n  let count = -1,\n    index = -1;\n  do {\n    // First call or the while case evaluated true, meaning we have to make\n    // count 0 or we found a character\n    ++count;\n    // Find the index of our search string, starting after the previous index\n    index = string.indexOf(search, index + 1);\n  } while (index !== -1);\n  return count;\n}\n\n/**\n * Turns a set of mapped <code>StackFrame</code>s back into their generated code position and enhances them with code.\n * @param {string} fileUri The URI of the <code>bundle.js</code> file.\n * @param {StackFrame[]} frames A set of <code>StackFrame</code>s which are already mapped and missing their generated positions.\n * @param {number} [fileContents=3] The number of lines to provide before and after the line specified in the <code>StackFrame</code>.\n */\nasync function unmap(\n  _fileUri: string | { uri: string; contents: string },\n  frames: StackFrame[],\n  contextLines = 3,\n): Promise<StackFrame[]> {\n  let fileContents = typeof _fileUri === 'object' ? _fileUri.contents : null;\n  const fileUri = typeof _fileUri === 'object' ? _fileUri.uri : _fileUri;\n  if (fileContents == null) {\n    fileContents = await fetch(fileUri).then((res) => res.text());\n  }\n  const map = await getSourceMap(fileUri, fileContents!);\n  return frames.map((frame) => {\n    const { functionName, lineNumber, columnNumber, _originalLineNumber } =\n      frame;\n    if (_originalLineNumber != null) {\n      return frame;\n    }\n    let { fileName } = frame;\n    if (fileName) {\n      // The web version of this module only provides POSIX support, so Windows\n      // paths like C:\\foo\\\\baz\\..\\\\bar\\ cannot be normalized.\n      // A simple solution to this is to replace all `\\` with `/`, then\n      // normalize afterwards.\n      fileName = path.normalize(fileName.replace(/[\\\\]+/g, '/'));\n    }\n    if (fileName == null) {\n      return frame;\n    }\n    const fN: string = fileName;\n    const source = map\n      .getSources()\n      // Prepare path for normalization; see comment above for reasoning.\n      .map((s) => s.replace(/[\\\\]+/g, '/'))\n      .filter((p) => {\n        p = path.normalize(p);\n        const i = p.lastIndexOf(fN);\n        return i !== -1 && i === p.length - fN.length;\n      })\n      .map((p) => ({\n        token: p,\n        seps: count(path.sep, path.normalize(p)),\n        penalties: count('node_modules', p) + count('~', p),\n      }))\n      .sort((a, b) => {\n        const s = Math.sign(a.seps - b.seps);\n        if (s !== 0) {\n          return s;\n        }\n        return Math.sign(a.penalties - b.penalties);\n      });\n    if (source.length < 1 || lineNumber == null) {\n      return new StackFrame(\n        null,\n        null,\n        null,\n        null,\n        null,\n        functionName,\n        fN,\n        lineNumber,\n        columnNumber,\n        null,\n      );\n    }\n    const sourceT = source[0].token;\n    const { line, column } = map.getGeneratedPosition(\n      sourceT,\n      lineNumber,\n      // $FlowFixMe\n      columnNumber!,\n    );\n    const originalSource = map.getSource(sourceT);\n    return new StackFrame(\n      functionName,\n      fileUri,\n      line,\n      column || null,\n      getLinesAround(line!, contextLines, fileContents || []),\n      functionName,\n      fN,\n      lineNumber,\n      columnNumber,\n      getLinesAround(lineNumber, contextLines, originalSource!),\n    );\n  });\n}\n\nexport { unmap };\nexport default unmap;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/test/StackTraceTab.spec.tsx",
    "content": "import React from 'react';\nimport { render, screen, waitFor } from '@testing-library/react';\nimport { TraceTab } from '../src/StackTraceTab.js';\n\nconst actions = {\n  0: { type: 'PERFORM_ACTION', action: { type: '@@INIT' } },\n  1: { type: 'PERFORM_ACTION', action: { type: 'INCREMENT_COUNTER' } },\n  2: {\n    type: 'PERFORM_ACTION',\n    action: { type: 'INCREMENT_COUNTER' },\n    stack:\n      'Error\\n    at fn1 (app.js:72:24)\\n    at fn2 (app.js:84:31)\\n     ' +\n      'at fn3 (chrome-extension://lmhkpmbekcpmknklioeibfkpmmfibljd/js/page.bundle.js:1269:80)',\n  },\n};\n\nconst TraceTabAsAny = TraceTab as any;\n\ndescribe('StackTraceTab component', () => {\n  it('should render with no props', async () => {\n    const { container } = render(<TraceTabAsAny />);\n    await screen.findByTestId('stack-trace');\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('should render with props, but without stack', async () => {\n    const { container } = render(\n      <TraceTabAsAny actions={actions} action={actions[0].action} />,\n    );\n    await screen.findByTestId('stack-trace');\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('should render the link to docs', () => {\n    const { container } = render(\n      <TraceTabAsAny actions={actions} action={actions[1].action} />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('should render with trace stack', async () => {\n    const { container } = render(\n      <TraceTabAsAny actions={actions} action={actions[2].action} />,\n    );\n    const stackTraceDiv = await screen.findByTestId('stack-trace');\n    await waitFor(() =>\n      expect(stackTraceDiv.querySelector('div')).toBeTruthy(),\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/test/__snapshots__/StackTraceTab.spec.tsx.snap",
    "content": "// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing\n\nexports[`StackTraceTab component should render the link to docs 1`] = `\n<div\n  style=\"padding: 5px 10px;\"\n>\n  To enable tracing action calls, you should set \\`trace\\` option to \\`true\\` for Redux DevTools enhancer. Refer to\n   \n  <a\n    href=\"#\"\n  >\n    this page\n  </a>\n   \n  for more details.\n</div>\n`;\n\nexports[`StackTraceTab component should render with no props 1`] = `\n<div\n  style=\"padding: 5px 10px;\"\n>\n  <div\n    data-testid=\"stack-trace\"\n    style=\"font-size: 1em; flex: 0 1 auto; min-height: 0px; overflow: auto;\"\n  />\n</div>\n`;\n\nexports[`StackTraceTab component should render with props, but without stack 1`] = `\n<div\n  style=\"padding: 5px 10px;\"\n>\n  <div\n    data-testid=\"stack-trace\"\n    style=\"font-size: 1em; flex: 0 1 auto; min-height: 0px; overflow: auto;\"\n  />\n</div>\n`;\n\nexports[`StackTraceTab component should render with trace stack 1`] = `\n<div\n  style=\"padding: 5px 10px;\"\n>\n  <div\n    data-testid=\"stack-trace\"\n    style=\"font-size: 1em; flex: 0 1 auto; min-height: 0px; overflow: auto;\"\n  >\n    <div>\n      <button\n        style=\"color: rgb(255, 255, 255); background-color: rgb(60, 68, 79); cursor: pointer; display: block; width: 100%; text-align: left; font-size: 1em; padding: 0px 5px; line-height: 1.5; margin-bottom: 0.6em;\"\n      >\n        ▼ 2 stack frames were expanded.\n      </button>\n      <div\n        style=\"display: block;\"\n      >\n        <div>\n          <div>\n            fn1\n          </div>\n          <div\n            style=\"font-size: 0.9em; margin-bottom: 0.9em;\"\n          >\n            <span>\n              app.js:72:24\n            </span>\n          </div>\n        </div>\n        <div>\n          <div>\n            fn2\n          </div>\n          <div\n            style=\"font-size: 0.9em; margin-bottom: 0.9em;\"\n          >\n            <span>\n              app.js:84:31\n            </span>\n          </div>\n        </div>\n        <button\n          style=\"color: rgb(255, 255, 255); background-color: rgb(60, 68, 79); cursor: pointer; display: block; width: 100%; text-align: left; font-size: 1em; padding: 0px 5px; line-height: 1.5; margin-bottom: 0.6em;\"\n        >\n          ▲ 2 stack frames were expanded.\n        </button>\n      </div>\n    </div>\n  </div>\n</div>\n`;\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\",\n    \"types\": [\"chrome\", \"node\"]\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-inspector-monitor-trace-tab/tsconfig.test.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"jest\", \"node\", \"chrome\"]\n  },\n  \"include\": [\"src\", \"test\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-instrument/CHANGELOG.md",
    "content": "# Change Log\n\n## 3.0.0\n\n### Major Changes\n\n- 3f90241: Convert @redux-devtools/instrument to ESM\n\n## 2.2.0\n\n### Minor Changes\n\n- 6fc18ed7: Add new Redux version to peer dependencies\n\n## 2.1.2\n\n### Patch Changes\n\n- 262ea85c: Remove unnecessary exported functions from instrument\n\n## 2.1.1\n\n### Patch Changes\n\n- 42531c50: Bump versions\n\n## 2.0.0\n\n- Adds ESM build (https://github.com/reduxjs/redux-devtools/pull/997) and switches the default export to a named export in order to ensure that the CommonJS output and the ESM output are [interchangeable](https://rollupjs.org/guide/en/#outputexports):\n\n```diff\n- import instrument from '@redux-devtools/instrument';\n+ import { instrument } from '@redux-devtools/instrument';\n```\n\n## 1.11.0 (2021-03-06)\n\n### Features\n\n- **instrument:** use latest symbol-observable (compatibility with frozen Symbol) ([#660](https://github.com/reduxjs/redux-devtools/issues/660)) ([4d73c3f](https://github.com/reduxjs/redux-devtools/commit/4d73c3f98cb9e3308a1e888213ca4faaec9f1b5e))\n- **redux-devtools-instrument:** export type PerformAction ([#614](https://github.com/reduxjs/redux-devtools/issues/614)) ([9e59cfd](https://github.com/reduxjs/redux-devtools/commit/9e59cfdc7d1d0595f0718feaebc0a9bf814b0b63))\n- **redux-devtools-serialize:** convert to TypeScript ([#621](https://github.com/reduxjs/redux-devtools/issues/621)) ([d586f19](https://github.com/reduxjs/redux-devtools/commit/d586f1955a3648883107f8c981ee17eeb4c013a3))\n\n## [1.10.0](https://github.com/reduxjs/redux-devtools/compare/redux-devtools-instrument@1.9.7...redux-devtools-instrument@1.10.0) (2020-09-07)\n\n### Features\n\n- **redux-devtools-instrument:** export type PerformAction ([#614](https://github.com/reduxjs/redux-devtools/issues/614)) ([9e59cfd](https://github.com/reduxjs/redux-devtools/commit/9e59cfdc7d1d0595f0718feaebc0a9bf814b0b63))\n- **redux-devtools-serialize:** convert to TypeScript ([#621](https://github.com/reduxjs/redux-devtools/issues/621)) ([d586f19](https://github.com/reduxjs/redux-devtools/commit/d586f1955a3648883107f8c981ee17eeb4c013a3))\n\n## 1.9.7 (2020-08-14)\n\n**Note:** Version bump only for package redux-devtools-instrument\n"
  },
  {
    "path": "packages/redux-devtools-instrument/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Dan Abramov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/redux-devtools-instrument/README.md",
    "content": "# Redux DevTools Instrumentation\n\nRedux enhancer used along with [Redux DevTools](https://github.com/reduxjs/redux-devtools) or [Remote Redux DevTools](https://github.com/zalmoxisus/remote-redux-devtools).\n\n### Installation\n\n```\nyarn add @redux-devtools/instrument\n```\n\n### Usage\n\nAdd the store enhancer:\n\n##### `store/configureStore.js`\n\n```js\nimport { createStore, applyMiddleware, compose } from 'redux';\nimport thunk from 'redux-thunk';\nimport devTools from 'remote-redux-devtools';\nimport reducer from '../reducers';\n\n// Usually you import the reducer from the monitor\n// or apply with createDevTools as explained in Redux DevTools\nconst monitorReducer = (state = {}, action) => state;\n\nexport default function configureStore(initialState) {\n  const enhancer = compose(\n    applyMiddleware(...middlewares),\n    // other enhancers and applyMiddleware should be added before the instrumentation\n    instrument(monitorReducer, { maxAge: 50 }),\n  );\n\n  // Note: passing enhancer as last argument requires redux@>=3.1.0\n  return createStore(reducer, initialState, enhancer);\n}\n```\n\n### API\n\n`instrument(monitorReducer, [options])`\n\n- arguments\n  - **monitorReducer** _function_ called whenever an action is dispatched ([see the example of a monitor reducer](https://github.com/reduxjs/redux-devtools/blob/master/packages/redux-devtools-log-monitor/src/reducers.ts#L34)).\n  - **options** _object_\n    - **maxAge** _number_ or _function_(currentLiftedAction, previousLiftedState) - maximum allowed actions to be stored on the history tree, the oldest actions are removed once `maxAge` is reached. Can be generated dynamically with a function getting current action as argument.\n    - **shouldCatchErrors** _boolean_ - if specified as `true`, whenever there's an exception in reducers, the monitors will show the error message, and next actions will not be dispatched.\n    - **shouldRecordChanges** _boolean_ - if specified as `false`, it will not record the changes till `pauseRecording(false)` is dispatched. Default is `true`.\n    - **pauseActionType** _string_ - if specified, whenever `pauseRecording(false)` lifted action is dispatched and there are actions in the history log, will add this action type. If not specified, will commit when paused.\n    - **shouldStartLocked** _boolean_ - if specified as `true`, it will not allow any non-monitor actions to be dispatched till `lockChanges(false)` is dispatched. Default is `false`.\n    - **shouldHotReload** _boolean_ - if set to `false`, will not recompute the states on hot reloading (or on replacing the reducers). Default to `true`.\n    - **trace** _boolean_ or _function_ - if set to `true`, will include stack trace for every dispatched action. You can use a function (with action object as argument) which should return `new Error().stack` string, getting the stack outside of reducers. Default to `false`.\n    - **traceLimit** _number_ - maximum stack trace frames to be stored (in case `trace` option was provided as `true`). By default it's `10`. If `trace` option is a function, `traceLimit` will have no effect, that should be handled there like so: `trace: () => new Error().stack.split('\\n').slice(0, limit+1).join('\\n')` (`+1` is needed for Chrome where's an extra 1st frame for `Error\\n`).\n\n### License\n\nMIT\n"
  },
  {
    "path": "packages/redux-devtools-instrument/eslint.config.mjs",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTs from '../../eslint.ts.config.base.mjs';\nimport eslintTsJest from '../../eslint.ts.jest.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTs(import.meta.dirname),\n  ...eslintTsJest(import.meta.dirname),\n  {\n    ignores: ['jest.config.ts', 'lib'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-instrument/jest.config.ts",
    "content": "import { createDefaultEsmPreset, type JestConfigWithTsJest } from 'ts-jest';\n\nconst presetConfig = createDefaultEsmPreset({\n  tsconfig: 'tsconfig.test.json',\n});\n\nconst jestConfig: JestConfigWithTsJest = {\n  ...presetConfig,\n  moduleNameMapper: {\n    '^(\\\\.{1,2}/.*)\\\\.js$': '$1',\n  },\n};\n\nexport default jestConfig;\n"
  },
  {
    "path": "packages/redux-devtools-instrument/package.json",
    "content": "{\n  \"name\": \"@redux-devtools/instrument\",\n  \"version\": \"3.0.0\",\n  \"description\": \"Redux DevTools instrumentation\",\n  \"keywords\": [\n    \"redux\",\n    \"devtools\",\n    \"flux\",\n    \"hot reloading\",\n    \"time travel\",\n    \"live edit\"\n  ],\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-instrument\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Dan Abramov <dan.abramov@me.com> (http://github.com/gaearon)\",\n  \"files\": [\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": \"./lib/instrument.js\",\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"test\": \"node --experimental-vm-modules node_modules/jest/bin/jest.js\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run type-check && pnpm run lint && pnpm run test\"\n  },\n  \"devDependencies\": {\n    \"@jest/globals\": \"^30.3.0\",\n    \"@types/jest\": \"^30.0.0\",\n    \"@types/node\": \"^24.12.0\",\n    \"jest\": \"^30.3.0\",\n    \"redux\": \"^5.0.1\",\n    \"rimraf\": \"^6.1.3\",\n    \"rxjs\": \"^7.8.2\",\n    \"ts-jest\": \"^29.4.6\",\n    \"typescript\": \"~5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"redux\": \"^3.4.0 || ^4.0.0 || ^5.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-instrument/src/getSymbolObservable.ts",
    "content": "export default function getSymbolObservable() {\n  return (typeof Symbol === 'function' && Symbol.observable) || '@@observable';\n}\n"
  },
  {
    "path": "packages/redux-devtools-instrument/src/instrument.ts",
    "content": "import {\n  Action,\n  isPlainObject,\n  Observer,\n  Reducer,\n  Store,\n  StoreEnhancer,\n  StoreEnhancerStoreCreator,\n} from 'redux';\nimport getSymbolObservable from './getSymbolObservable.js';\n\nexport const ActionTypes = {\n  PERFORM_ACTION: 'PERFORM_ACTION',\n  RESET: 'RESET',\n  ROLLBACK: 'ROLLBACK',\n  COMMIT: 'COMMIT',\n  SWEEP: 'SWEEP',\n  TOGGLE_ACTION: 'TOGGLE_ACTION',\n  SET_ACTIONS_ACTIVE: 'SET_ACTIONS_ACTIVE',\n  JUMP_TO_STATE: 'JUMP_TO_STATE',\n  JUMP_TO_ACTION: 'JUMP_TO_ACTION',\n  REORDER_ACTION: 'REORDER_ACTION',\n  IMPORT_STATE: 'IMPORT_STATE',\n  LOCK_CHANGES: 'LOCK_CHANGES',\n  PAUSE_RECORDING: 'PAUSE_RECORDING',\n} as const;\n\nconst isChrome =\n  typeof window === 'object' &&\n  (typeof (window as typeof window & { chrome: unknown }).chrome !==\n    'undefined' ||\n    (typeof window.process !== 'undefined' &&\n      (window.process as typeof window.process & { type: unknown }).type ===\n        'renderer'));\n\nconst isChromeOrNode =\n  isChrome ||\n  (typeof process !== 'undefined' &&\n    process.release &&\n    process.release.name === 'node');\n\nexport interface PerformAction<A extends Action<string>> {\n  type: typeof ActionTypes.PERFORM_ACTION;\n  action: A;\n  timestamp: number;\n  stack: string | undefined;\n}\n\ninterface ResetAction {\n  type: typeof ActionTypes.RESET;\n  timestamp: number;\n}\n\ninterface RollbackAction {\n  type: typeof ActionTypes.ROLLBACK;\n  timestamp: number;\n}\n\ninterface CommitAction {\n  type: typeof ActionTypes.COMMIT;\n  timestamp: number;\n}\n\ninterface SweepAction {\n  type: typeof ActionTypes.SWEEP;\n}\n\ninterface ToggleAction {\n  type: typeof ActionTypes.TOGGLE_ACTION;\n  id: number;\n}\n\ninterface SetActionsActiveAction {\n  type: typeof ActionTypes.SET_ACTIONS_ACTIVE;\n  start: number;\n  end: number;\n  active: boolean;\n}\n\ninterface ReorderAction {\n  type: typeof ActionTypes.REORDER_ACTION;\n  actionId: number;\n  beforeActionId: number;\n}\n\ninterface JumpToStateAction {\n  type: typeof ActionTypes.JUMP_TO_STATE;\n  index: number;\n}\n\ninterface JumpToActionAction {\n  type: typeof ActionTypes.JUMP_TO_ACTION;\n  actionId: number;\n}\n\ninterface ImportStateAction<S, A extends Action<string>, MonitorState> {\n  type: typeof ActionTypes.IMPORT_STATE;\n  nextLiftedState: LiftedState<S, A, MonitorState> | readonly A[];\n  preloadedState?: S;\n  noRecompute?: boolean | undefined;\n}\n\ninterface LockChangesAction {\n  type: typeof ActionTypes.LOCK_CHANGES;\n  status: boolean;\n}\n\ninterface PauseRecordingAction {\n  type: typeof ActionTypes.PAUSE_RECORDING;\n  status: boolean;\n}\n\nexport type LiftedAction<S, A extends Action<string>, MonitorState> =\n  | PerformAction<A>\n  | ResetAction\n  | RollbackAction\n  | CommitAction\n  | SweepAction\n  | ToggleAction\n  | SetActionsActiveAction\n  | ReorderAction\n  | JumpToStateAction\n  | JumpToActionAction\n  | ImportStateAction<S, A, MonitorState>\n  | LockChangesAction\n  | PauseRecordingAction;\n\n/**\n * Action creators to change the History state.\n */\nexport const ActionCreators = {\n  performAction<A extends Action<string>>(\n    this: void,\n    action: A,\n    trace?: ((action: A) => string | undefined) | boolean,\n    traceLimit?: number,\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n    toExcludeFromTrace?: Function,\n  ) {\n    if (!isPlainObject(action)) {\n      throw new Error(\n        'Actions must be plain objects. ' +\n          'Use custom middleware for async actions.',\n      );\n    }\n\n    if (typeof action.type === 'undefined') {\n      throw new Error(\n        'Actions may not have an undefined \"type\" property. ' +\n          'Have you misspelled a constant?',\n      );\n    }\n\n    let stack;\n    if (trace) {\n      let extraFrames = 0;\n      if (typeof trace === 'function') {\n        stack = trace(action);\n      } else {\n        const error = Error();\n        let prevStackTraceLimit;\n        if (Error.captureStackTrace && isChromeOrNode) {\n          // avoid error-polyfill\n          if (traceLimit && Error.stackTraceLimit < traceLimit) {\n            prevStackTraceLimit = Error.stackTraceLimit;\n            Error.stackTraceLimit = traceLimit;\n          }\n          Error.captureStackTrace(error, toExcludeFromTrace);\n        } else {\n          extraFrames = 3;\n        }\n        stack = error.stack;\n        if (prevStackTraceLimit) Error.stackTraceLimit = prevStackTraceLimit;\n        if (\n          extraFrames ||\n          typeof Error.stackTraceLimit !== 'number' ||\n          (traceLimit && Error.stackTraceLimit > traceLimit)\n        ) {\n          if (stack != null) {\n            const frames = stack.split('\\n');\n            if (traceLimit && frames.length > traceLimit) {\n              stack = frames\n                .slice(\n                  0,\n                  traceLimit +\n                    extraFrames +\n                    (frames[0].startsWith('Error') ? 1 : 0),\n                )\n                .join('\\n');\n            }\n          }\n        }\n      }\n    }\n\n    return {\n      type: ActionTypes.PERFORM_ACTION,\n      action,\n      timestamp: Date.now(),\n      stack,\n    };\n  },\n\n  reset(this: void): ResetAction {\n    return { type: ActionTypes.RESET, timestamp: Date.now() };\n  },\n\n  rollback(this: void): RollbackAction {\n    return { type: ActionTypes.ROLLBACK, timestamp: Date.now() };\n  },\n\n  commit(this: void): CommitAction {\n    return { type: ActionTypes.COMMIT, timestamp: Date.now() };\n  },\n\n  sweep(this: void): SweepAction {\n    return { type: ActionTypes.SWEEP };\n  },\n\n  toggleAction(this: void, id: number): ToggleAction {\n    return { type: ActionTypes.TOGGLE_ACTION, id };\n  },\n\n  setActionsActive(\n    this: void,\n    start: number,\n    end: number,\n    active = true,\n  ): SetActionsActiveAction {\n    return { type: ActionTypes.SET_ACTIONS_ACTIVE, start, end, active };\n  },\n\n  reorderAction(\n    this: void,\n    actionId: number,\n    beforeActionId: number,\n  ): ReorderAction {\n    return { type: ActionTypes.REORDER_ACTION, actionId, beforeActionId };\n  },\n\n  jumpToState(this: void, index: number): JumpToStateAction {\n    return { type: ActionTypes.JUMP_TO_STATE, index };\n  },\n\n  jumpToAction(this: void, actionId: number): JumpToActionAction {\n    return { type: ActionTypes.JUMP_TO_ACTION, actionId };\n  },\n\n  importState<S, A extends Action<string>, MonitorState = null>(\n    this: void,\n    nextLiftedState: LiftedState<S, A, MonitorState> | readonly A[],\n    noRecompute?: boolean,\n  ): ImportStateAction<S, A, MonitorState> {\n    return { type: ActionTypes.IMPORT_STATE, nextLiftedState, noRecompute };\n  },\n\n  lockChanges(this: void, status: boolean): LockChangesAction {\n    return { type: ActionTypes.LOCK_CHANGES, status };\n  },\n\n  pauseRecording(this: void, status: boolean): PauseRecordingAction {\n    return { type: ActionTypes.PAUSE_RECORDING, status };\n  },\n};\n\nexport const INIT_ACTION = { type: '@@INIT' };\n\n/**\n * Computes the next entry with exceptions catching.\n */\nfunction computeWithTryCatch<S, A extends Action<string>, PreloadedState>(\n  reducer: Reducer<S, A, PreloadedState>,\n  action: A,\n  state: S,\n) {\n  let nextState = state;\n  let nextError;\n  try {\n    nextState = reducer(state, action);\n  } catch (err) {\n    nextError = (err as object).toString();\n    if (isChrome) {\n      // In Chrome, rethrowing provides better source map support\n      setTimeout(() => {\n        throw err;\n      });\n    } else {\n      console.error(err); // eslint-disable-line no-console\n    }\n  }\n\n  return {\n    state: nextState,\n    error: nextError,\n  };\n}\n\n/**\n * Computes the next entry in the log by applying an action.\n */\nfunction computeNextEntry<S, A extends Action<string>, PreloadedState>(\n  reducer: Reducer<S, A, PreloadedState>,\n  action: A,\n  state: S,\n  shouldCatchErrors: boolean | undefined,\n) {\n  if (!shouldCatchErrors) {\n    return { state: reducer(state, action) };\n  }\n  return computeWithTryCatch(reducer, action, state);\n}\n\n/**\n * Runs the reducer on invalidated actions to get a fresh computation log.\n */\nfunction recomputeStates<S, A extends Action<string>, PreloadedState>(\n  computedStates: { state: S; error?: string }[],\n  minInvalidatedStateIndex: number,\n  reducer: Reducer<S, A, PreloadedState>,\n  committedState: S,\n  actionsById: { [actionId: number]: PerformAction<A> },\n  stagedActionIds: number[],\n  skippedActionIds: number[],\n  shouldCatchErrors: boolean | undefined,\n) {\n  // Optimization: exit early and return the same reference\n  // if we know nothing could have changed.\n  if (\n    !computedStates ||\n    minInvalidatedStateIndex === -1 ||\n    (minInvalidatedStateIndex >= computedStates.length &&\n      computedStates.length === stagedActionIds.length)\n  ) {\n    return computedStates;\n  }\n\n  const nextComputedStates = computedStates.slice(0, minInvalidatedStateIndex);\n  for (let i = minInvalidatedStateIndex; i < stagedActionIds.length; i++) {\n    const actionId = stagedActionIds[i];\n    const action = actionsById[actionId].action;\n\n    const previousEntry = nextComputedStates[i - 1];\n    const previousState = previousEntry ? previousEntry.state : committedState;\n\n    const shouldSkip = skippedActionIds.includes(actionId);\n    let entry;\n    if (shouldSkip) {\n      entry = previousEntry;\n    } else {\n      if (shouldCatchErrors && previousEntry && previousEntry.error) {\n        entry = {\n          state: previousState,\n          error: 'Interrupted by an error up the chain',\n        };\n      } else {\n        entry = computeNextEntry(\n          reducer,\n          action,\n          previousState,\n          shouldCatchErrors,\n        );\n      }\n    }\n    nextComputedStates.push(entry);\n  }\n\n  return nextComputedStates;\n}\n\n/**\n * Lifts an app's action into an action on the lifted store.\n */\nfunction liftAction<A extends Action<string>>(\n  action: A,\n  trace?: ((action: A) => string | undefined) | boolean,\n  traceLimit?: number,\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n  toExcludeFromTrace?: Function,\n) {\n  return ActionCreators.performAction(\n    action,\n    trace,\n    traceLimit,\n    toExcludeFromTrace,\n  );\n}\n\nfunction isArray<S, A extends Action<string>, MonitorState>(\n  nextLiftedState: LiftedState<S, A, MonitorState> | readonly A[],\n): nextLiftedState is readonly A[] {\n  return Array.isArray(nextLiftedState);\n}\n\nexport interface LiftedState<S, A extends Action<string>, MonitorState> {\n  monitorState: MonitorState;\n  nextActionId: number;\n  actionsById: { [actionId: number]: PerformAction<A> };\n  stagedActionIds: number[];\n  skippedActionIds: number[];\n  committedState: S;\n  currentStateIndex: number;\n  computedStates: { state: S; error?: string }[];\n  isLocked: boolean;\n  isPaused: boolean;\n}\n\n/**\n * Creates a history state reducer from an app's reducer.\n */\nfunction liftReducerWith<\n  S,\n  A extends Action<string>,\n  PreloadedState,\n  MonitorState,\n  MonitorAction extends Action<string>,\n>(\n  reducer: Reducer<S, A, PreloadedState>,\n  initialCommittedState: S | PreloadedState | undefined,\n  monitorReducer: Reducer<MonitorState, MonitorAction>,\n  options: Options<S, A, MonitorState, MonitorAction>,\n): Reducer<LiftedState<S, A, MonitorState>, LiftedAction<S, A, MonitorState>> {\n  const initialLiftedState: LiftedState<S, A, MonitorState> = {\n    monitorState: monitorReducer(undefined, {} as MonitorAction),\n    nextActionId: 1,\n    actionsById: { 0: liftAction(INIT_ACTION as A) },\n    stagedActionIds: [0],\n    skippedActionIds: [],\n    committedState: initialCommittedState as S,\n    currentStateIndex: 0,\n    computedStates: [],\n    isLocked: options.shouldStartLocked === true,\n    isPaused: options.shouldRecordChanges === false,\n  };\n\n  /**\n   * Manages how the history actions modify the history state.\n   */\n  return (\n    liftedState: LiftedState<S, A, MonitorState> | undefined,\n    liftedAction: LiftedAction<S, A, MonitorState>,\n  ): LiftedState<S, A, MonitorState> => {\n    let {\n      monitorState,\n      actionsById,\n      nextActionId,\n      stagedActionIds,\n      skippedActionIds,\n      committedState,\n      currentStateIndex,\n      computedStates,\n      isLocked,\n      isPaused,\n    } = liftedState || initialLiftedState;\n\n    if (!liftedState) {\n      // Prevent mutating initialLiftedState\n      actionsById = { ...actionsById };\n    }\n\n    function commitExcessActions(n: number) {\n      // Auto-commits n-number of excess actions.\n      let excess = n;\n      let idsToDelete = stagedActionIds.slice(1, excess + 1);\n\n      for (let i = 0; i < idsToDelete.length; i++) {\n        if (computedStates[i + 1].error) {\n          // Stop if error is found. Commit actions up to error.\n          excess = i;\n          idsToDelete = stagedActionIds.slice(1, excess + 1);\n          break;\n        } else {\n          delete actionsById[idsToDelete[i]];\n        }\n      }\n\n      skippedActionIds = skippedActionIds.filter(\n        (id) => !idsToDelete.includes(id),\n      );\n      stagedActionIds = [0, ...stagedActionIds.slice(excess + 1)];\n      committedState = computedStates[excess].state;\n      computedStates = computedStates.slice(excess);\n      currentStateIndex =\n        currentStateIndex > excess ? currentStateIndex - excess : 0;\n    }\n\n    function computePausedAction(\n      shouldInit?: boolean,\n    ): LiftedState<S, A, MonitorState> {\n      let computedState;\n      if (shouldInit) {\n        computedState = computedStates[currentStateIndex];\n        monitorState = monitorReducer(\n          monitorState,\n          liftedAction as MonitorAction,\n        );\n      } else {\n        computedState = computeNextEntry(\n          reducer,\n          (liftedAction as PerformAction<A>).action,\n          computedStates[currentStateIndex].state,\n          false,\n        );\n      }\n      if (!options.pauseActionType || nextActionId === 1) {\n        return {\n          monitorState,\n          actionsById: { 0: liftAction(INIT_ACTION as A) },\n          nextActionId: 1,\n          stagedActionIds: [0],\n          skippedActionIds: [],\n          committedState: computedState.state,\n          currentStateIndex: 0,\n          computedStates: [computedState],\n          isLocked,\n          isPaused: true,\n        };\n      }\n      if (shouldInit) {\n        if (currentStateIndex === stagedActionIds.length - 1) {\n          currentStateIndex++;\n        }\n        stagedActionIds = [...stagedActionIds, nextActionId];\n        nextActionId++;\n      }\n      return {\n        monitorState,\n        actionsById: {\n          ...actionsById,\n          [nextActionId - 1]: liftAction({\n            type: options.pauseActionType,\n          } as A),\n        },\n        nextActionId,\n        stagedActionIds,\n        skippedActionIds,\n        committedState,\n        currentStateIndex,\n        computedStates: [\n          ...computedStates.slice(0, stagedActionIds.length - 1),\n          computedState,\n        ],\n        isLocked,\n        isPaused: true,\n      };\n    }\n\n    // By default, aggressively recompute every state whatever happens.\n    // This has O(n) performance, so we'll override this to a sensible\n    // value whenever we feel like we don't have to recompute the states.\n    let minInvalidatedStateIndex = 0;\n\n    // maxAge number can be changed dynamically\n    let maxAge = options.maxAge;\n    if (typeof maxAge === 'function')\n      maxAge = maxAge(liftedAction, liftedState);\n\n    if (/^@@redux\\/(INIT|REPLACE)/.test(liftedAction.type)) {\n      if (options.shouldHotReload === false) {\n        actionsById = { 0: liftAction(INIT_ACTION as A) };\n        nextActionId = 1;\n        stagedActionIds = [0];\n        skippedActionIds = [];\n        committedState =\n          computedStates.length === 0\n            ? (initialCommittedState as S)\n            : computedStates[currentStateIndex].state;\n        currentStateIndex = 0;\n        computedStates = [];\n      }\n\n      // Recompute states on hot reload and init.\n      minInvalidatedStateIndex = 0;\n\n      if (maxAge && stagedActionIds.length > maxAge) {\n        // States must be recomputed before committing excess.\n        computedStates = recomputeStates<S, A, PreloadedState>(\n          computedStates,\n          minInvalidatedStateIndex,\n          reducer,\n          committedState,\n          actionsById,\n          stagedActionIds,\n          skippedActionIds,\n          options.shouldCatchErrors,\n        );\n\n        commitExcessActions(stagedActionIds.length - maxAge);\n\n        // Avoid double computation.\n        minInvalidatedStateIndex = Infinity;\n      }\n    } else {\n      switch (liftedAction.type) {\n        case ActionTypes.PERFORM_ACTION: {\n          if (isLocked) return liftedState || initialLiftedState;\n          if (isPaused) return computePausedAction();\n\n          // Auto-commit as new actions come in.\n          if (maxAge && stagedActionIds.length >= maxAge) {\n            commitExcessActions(stagedActionIds.length - maxAge + 1);\n          }\n\n          if (currentStateIndex === stagedActionIds.length - 1) {\n            currentStateIndex++;\n          }\n          const actionId = nextActionId++;\n          // Mutation! This is the hottest path, and we optimize on purpose.\n          // It is safe because we set a new key in a cache dictionary.\n          actionsById[actionId] = liftedAction;\n          stagedActionIds = [...stagedActionIds, actionId];\n          // Optimization: we know that only the new action needs computing.\n          minInvalidatedStateIndex = stagedActionIds.length - 1;\n          break;\n        }\n        case ActionTypes.RESET: {\n          // Get back to the state the store was created with.\n          actionsById = { 0: liftAction(INIT_ACTION as A) };\n          nextActionId = 1;\n          stagedActionIds = [0];\n          skippedActionIds = [];\n          committedState = initialCommittedState as S;\n          currentStateIndex = 0;\n          computedStates = [];\n          break;\n        }\n        case ActionTypes.COMMIT: {\n          // Consider the last committed state the new starting point.\n          // Squash any staged actions into a single committed state.\n          actionsById = { 0: liftAction(INIT_ACTION as A) };\n          nextActionId = 1;\n          stagedActionIds = [0];\n          skippedActionIds = [];\n          committedState = computedStates[currentStateIndex].state;\n          currentStateIndex = 0;\n          computedStates = [];\n          break;\n        }\n        case ActionTypes.ROLLBACK: {\n          // Forget about any staged actions.\n          // Start again from the last committed state.\n          actionsById = { 0: liftAction(INIT_ACTION as A) };\n          nextActionId = 1;\n          stagedActionIds = [0];\n          skippedActionIds = [];\n          currentStateIndex = 0;\n          computedStates = [];\n          break;\n        }\n        case ActionTypes.TOGGLE_ACTION: {\n          // Toggle whether an action with given ID is skipped.\n          // Being skipped means it is a no-op during the computation.\n          const { id: actionId } = liftedAction;\n          const index = skippedActionIds.indexOf(actionId);\n          if (index === -1) {\n            skippedActionIds = [actionId, ...skippedActionIds];\n          } else {\n            skippedActionIds = skippedActionIds.filter((id) => id !== actionId);\n          }\n          // Optimization: we know history before this action hasn't changed\n          minInvalidatedStateIndex = stagedActionIds.indexOf(actionId);\n          break;\n        }\n        case ActionTypes.SET_ACTIONS_ACTIVE: {\n          // Toggle whether an action with given ID is skipped.\n          // Being skipped means it is a no-op during the computation.\n          const { start, end, active } = liftedAction;\n          const actionIds = [];\n          for (let i = start; i < end; i++) actionIds.push(i);\n          if (active) {\n            const actionIdsSet = new Set(actionIds);\n            skippedActionIds = skippedActionIds.filter(\n              (actionId) => !actionIdsSet.has(actionId),\n            );\n          } else {\n            const skippedActionIdsSet = new Set(skippedActionIds);\n            skippedActionIds = [\n              ...skippedActionIds,\n              ...actionIds.filter(\n                (actionId) => !skippedActionIdsSet.has(actionId),\n              ),\n            ];\n          }\n\n          // Optimization: we know history before this action hasn't changed\n          minInvalidatedStateIndex = stagedActionIds.indexOf(start);\n          break;\n        }\n        case ActionTypes.JUMP_TO_STATE: {\n          // Without recomputing anything, move the pointer that tell us\n          // which state is considered the current one. Useful for sliders.\n          currentStateIndex = liftedAction.index;\n          // Optimization: we know the history has not changed.\n          minInvalidatedStateIndex = Infinity;\n          break;\n        }\n        case ActionTypes.JUMP_TO_ACTION: {\n          // Jumps to a corresponding state to a specific action.\n          // Useful when filtering actions.\n          const index = stagedActionIds.indexOf(liftedAction.actionId);\n          if (index !== -1) currentStateIndex = index;\n          minInvalidatedStateIndex = Infinity;\n          break;\n        }\n        case ActionTypes.SWEEP: {\n          // Forget any actions that are currently being skipped.\n          const skippedActionIdsSet = new Set(skippedActionIds);\n          stagedActionIds = stagedActionIds.filter(\n            (actionId) => !skippedActionIdsSet.has(actionId),\n          );\n          skippedActionIds = [];\n          currentStateIndex = Math.min(\n            currentStateIndex,\n            stagedActionIds.length - 1,\n          );\n          break;\n        }\n        case ActionTypes.REORDER_ACTION: {\n          // Recompute actions in a new order.\n          const actionId = liftedAction.actionId;\n          const idx = stagedActionIds.indexOf(actionId);\n          // do nothing in case the action is already removed or trying to move the first action\n          if (idx < 1) break;\n          const beforeActionId = liftedAction.beforeActionId;\n          let newIdx = stagedActionIds.indexOf(beforeActionId);\n          if (newIdx < 1) {\n            // move to the beginning or to the end\n            const count = stagedActionIds.length;\n            newIdx = beforeActionId > stagedActionIds[count - 1] ? count : 1;\n          }\n          const diff = idx - newIdx;\n\n          if (diff > 0) {\n            // move left\n            stagedActionIds = [\n              ...stagedActionIds.slice(0, newIdx),\n              actionId,\n              ...stagedActionIds.slice(newIdx, idx),\n              ...stagedActionIds.slice(idx + 1),\n            ];\n            minInvalidatedStateIndex = newIdx;\n          } else if (diff < 0) {\n            // move right\n            stagedActionIds = [\n              ...stagedActionIds.slice(0, idx),\n              ...stagedActionIds.slice(idx + 1, newIdx),\n              actionId,\n              ...stagedActionIds.slice(newIdx),\n            ];\n            minInvalidatedStateIndex = idx;\n          }\n          break;\n        }\n        case ActionTypes.IMPORT_STATE: {\n          if (isArray(liftedAction.nextLiftedState)) {\n            // recompute array of actions\n            actionsById = { 0: liftAction(INIT_ACTION as A) };\n            nextActionId = 1;\n            stagedActionIds = [0];\n            skippedActionIds = [];\n            currentStateIndex = liftedAction.nextLiftedState.length;\n            computedStates = [];\n            committedState = liftedAction.preloadedState as S;\n            minInvalidatedStateIndex = 0;\n            // iterate through actions\n            liftedAction.nextLiftedState.forEach((action) => {\n              actionsById[nextActionId] = liftAction(\n                action,\n                options.trace || options.shouldIncludeCallstack,\n              );\n              stagedActionIds.push(nextActionId);\n              nextActionId++;\n            });\n          } else {\n            // Completely replace everything.\n            ({\n              monitorState,\n              actionsById,\n              nextActionId,\n              stagedActionIds,\n              skippedActionIds,\n              committedState,\n              currentStateIndex,\n              computedStates,\n            } = liftedAction.nextLiftedState);\n\n            if (liftedAction.noRecompute) {\n              minInvalidatedStateIndex = Infinity;\n            }\n          }\n\n          break;\n        }\n        case ActionTypes.LOCK_CHANGES: {\n          isLocked = liftedAction.status;\n          minInvalidatedStateIndex = Infinity;\n          break;\n        }\n        case ActionTypes.PAUSE_RECORDING: {\n          isPaused = liftedAction.status;\n          if (isPaused) {\n            return computePausedAction(true);\n          }\n          // Commit when unpausing\n          actionsById = { 0: liftAction(INIT_ACTION as A) };\n          nextActionId = 1;\n          stagedActionIds = [0];\n          skippedActionIds = [];\n          committedState = computedStates[currentStateIndex].state;\n          currentStateIndex = 0;\n          computedStates = [];\n          break;\n        }\n        default: {\n          // If the action is not recognized, it's a monitor action.\n          // Optimization: a monitor action can't change history.\n          minInvalidatedStateIndex = Infinity;\n          break;\n        }\n      }\n    }\n\n    computedStates = recomputeStates(\n      computedStates,\n      minInvalidatedStateIndex,\n      reducer,\n      committedState,\n      actionsById,\n      stagedActionIds,\n      skippedActionIds,\n      options.shouldCatchErrors,\n    );\n    monitorState = monitorReducer(monitorState, liftedAction as MonitorAction);\n    return {\n      monitorState,\n      actionsById,\n      nextActionId,\n      stagedActionIds,\n      skippedActionIds,\n      committedState,\n      currentStateIndex,\n      computedStates,\n      isLocked,\n      isPaused,\n    };\n  };\n}\n\n/**\n * Provides an app's view into the state of the lifted store.\n */\nfunction unliftState<S, A extends Action<string>, MonitorState, NextStateExt>(\n  liftedState: LiftedState<S, A, MonitorState> & NextStateExt,\n): S & NextStateExt {\n  const { computedStates, currentStateIndex } = liftedState;\n  const { state } = computedStates[currentStateIndex];\n  return state as S & NextStateExt;\n}\n\nexport type LiftedReducer<S, A extends Action<string>, MonitorState> = Reducer<\n  LiftedState<S, A, MonitorState>,\n  LiftedAction<S, A, MonitorState>\n>;\n\nexport type LiftedStore<S, A extends Action<string>, MonitorState> = Store<\n  LiftedState<S, A, MonitorState>,\n  LiftedAction<S, A, MonitorState>\n>;\n\nexport type InstrumentExt<S, A extends Action<string>, MonitorState> = {\n  liftedStore: LiftedStore<S, A, MonitorState>;\n};\n\nexport type EnhancedStore<S, A extends Action<string>, MonitorState> = Store<\n  S,\n  A\n> &\n  InstrumentExt<S, A, MonitorState>;\n\n/**\n * Provides an app's view into the lifted store.\n */\nfunction unliftStore<\n  S,\n  A extends Action<string>,\n  PreloadedState,\n  MonitorState,\n  MonitorAction extends Action<string>,\n  NextExt,\n  NextStateExt,\n>(\n  liftedStore: Store<\n    LiftedState<S, A, MonitorState> & NextStateExt,\n    LiftedAction<S, A, MonitorState>\n  > &\n    NextExt,\n  liftReducer: (\n    r: Reducer<S, A, PreloadedState>,\n  ) => LiftedReducer<S, A, MonitorState>,\n  options: Options<S, A, MonitorState, MonitorAction>,\n) {\n  let lastDefinedState: S & NextStateExt;\n  const trace = options.trace || options.shouldIncludeCallstack;\n  const traceLimit = options.traceLimit || 10;\n\n  function getState(): S & NextStateExt {\n    const state = unliftState<S, A, MonitorState, NextStateExt>(\n      liftedStore.getState(),\n    );\n    if (state !== undefined) {\n      lastDefinedState = state;\n    }\n    return lastDefinedState;\n  }\n\n  function dispatch<T extends A>(action: T): T {\n    liftedStore.dispatch(liftAction<A>(action, trace, traceLimit, dispatch));\n    return action;\n  }\n\n  const $$observable = getSymbolObservable();\n  if (!($$observable in liftedStore)) {\n    console.warn(\n      'Symbol.observable as defined by Redux and Redux DevTools do not match. This could cause your app to behave differently if the DevTools are not loaded. Consider polyfilling Symbol.observable before Redux is imported or avoid polyfilling Symbol.observable altogether.',\n    );\n  }\n\n  return {\n    liftedStore,\n\n    dispatch,\n\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    subscribe: liftedStore.subscribe,\n\n    getState,\n\n    replaceReducer(nextReducer: Reducer<S & NextStateExt, A>) {\n      liftedStore.replaceReducer(\n        liftReducer(\n          nextReducer as unknown as Reducer<S, A, PreloadedState>,\n        ) as unknown as Reducer<\n          LiftedState<S, A, MonitorState> & NextStateExt,\n          LiftedAction<S, A, MonitorState>\n        >,\n      );\n    },\n\n    [$$observable]() {\n      return {\n        subscribe(observer: Observer<S>) {\n          if (typeof observer !== 'object') {\n            throw new TypeError('Expected the observer to be an object.');\n          }\n\n          function observeState() {\n            if (observer.next) {\n              observer.next(getState());\n            }\n          }\n\n          observeState();\n          const unsubscribe = liftedStore.subscribe(observeState);\n          return { unsubscribe };\n        },\n\n        [$$observable]() {\n          return this;\n        },\n      };\n    },\n  } as unknown as Store<S & NextStateExt, A> &\n    NextExt & {\n      liftedStore: Store<\n        LiftedState<S, A, MonitorState> & NextStateExt,\n        LiftedAction<S, A, MonitorState>\n      >;\n    };\n}\n\nexport interface Options<\n  S,\n  A extends Action<string>,\n  MonitorState,\n  MonitorAction extends Action<string>,\n> {\n  maxAge?:\n    | number\n    | ((\n        currentLiftedAction: LiftedAction<S, A, MonitorState>,\n        previousLiftedState: LiftedState<S, A, MonitorState> | undefined,\n      ) => number);\n  shouldCatchErrors?: boolean;\n  shouldRecordChanges?: boolean;\n  pauseActionType?: unknown;\n  shouldStartLocked?: boolean;\n  shouldHotReload?: boolean;\n  trace?: boolean | ((action: A) => string | undefined);\n  traceLimit?: number;\n  shouldIncludeCallstack?: boolean;\n}\n\n/**\n * Redux instrumentation store enhancer.\n */\nexport function instrument<\n  OptionsS,\n  OptionsA extends Action<string>,\n  MonitorState = null,\n  MonitorAction extends Action<string> = never,\n>(\n  monitorReducer: Reducer<MonitorState, MonitorAction> = (() =>\n    null) as unknown as Reducer<MonitorState, MonitorAction>,\n  options: Options<OptionsS, OptionsA, MonitorState, MonitorAction> = {},\n): StoreEnhancer<InstrumentExt<any, any, MonitorState>> {\n  if (typeof options.maxAge === 'number' && options.maxAge < 2) {\n    throw new Error(\n      'DevTools.instrument({ maxAge }) option, if specified, ' +\n        'may not be less than 2.',\n    );\n  }\n\n  return <\n      NextExt extends NonNullable<unknown>,\n      NextStateExt extends NonNullable<unknown>,\n    >(\n      createStore: StoreEnhancerStoreCreator<NextExt, NextStateExt>,\n    ) =>\n    <S, A extends Action<string>, PreloadedState>(\n      reducer: Reducer<S, A, PreloadedState>,\n      initialState?: PreloadedState | undefined,\n    ) => {\n      function liftReducer(r: Reducer<S, A, PreloadedState>) {\n        if (typeof r !== 'function') {\n          if (r && typeof (r as { default: unknown }).default === 'function') {\n            throw new Error(\n              'Expected the reducer to be a function. ' +\n                'Instead got an object with a \"default\" field. ' +\n                'Did you pass a module instead of the default export? ' +\n                'Try passing require(...).default instead.',\n            );\n          }\n          throw new Error('Expected the reducer to be a function.');\n        }\n        return liftReducerWith<\n          S,\n          A,\n          PreloadedState,\n          MonitorState,\n          MonitorAction\n        >(\n          r,\n          initialState,\n          monitorReducer,\n          options as unknown as Options<S, A, MonitorState, MonitorAction>,\n        );\n      }\n\n      const liftedStore = createStore(liftReducer(reducer));\n      if (\n        (\n          liftedStore as Store<\n            LiftedState<S, A, MonitorState> & NextStateExt,\n            LiftedAction<S, A, MonitorState>\n          > &\n            NextExt & {\n              liftedStore: Store<\n                LiftedState<S, A, MonitorState>,\n                LiftedAction<S, A, MonitorState>\n              >;\n            }\n        ).liftedStore\n      ) {\n        throw new Error(\n          'DevTools instrumentation should not be applied more than once. ' +\n            'Check your store configuration.',\n        );\n      }\n\n      return unliftStore<\n        S,\n        A,\n        PreloadedState,\n        MonitorState,\n        MonitorAction,\n        NextExt,\n        NextStateExt\n      >(\n        liftedStore as Store<\n          LiftedState<S, A, MonitorState> & NextStateExt,\n          LiftedAction<S, A, MonitorState>\n        > &\n          NextExt,\n        liftReducer,\n        options as unknown as Options<S, A, MonitorState, MonitorAction>,\n      );\n    };\n}\n"
  },
  {
    "path": "packages/redux-devtools-instrument/test/instrument.spec.ts",
    "content": "import { jest } from '@jest/globals';\nimport {\n  createStore,\n  compose,\n  Reducer,\n  Store,\n  Action,\n  StoreEnhancer,\n} from 'redux';\nimport { from, Observable } from 'rxjs';\nimport {\n  ActionCreators,\n  EnhancedStore,\n  instrument,\n  LiftedAction,\n  LiftedStore,\n  LiftedState,\n} from '../src/instrument.js';\n\ntype CounterAction = { type: 'INCREMENT' } | { type: 'DECREMENT' };\nfunction counter(state = 0, action: CounterAction) {\n  switch (action.type) {\n    case 'INCREMENT':\n      return state + 1;\n    case 'DECREMENT':\n      return state - 1;\n    default:\n      return state;\n  }\n}\n\ntype CounterWithBugAction =\n  | { type: 'INCREMENT' }\n  | { type: 'DECREMENT' }\n  | { type: 'SET_UNDEFINED' };\nfunction counterWithBug(state = 0, action: CounterWithBugAction) {\n  switch (action.type) {\n    case 'INCREMENT':\n      return state + 1;\n    case 'DECREMENT':\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      return mistake - 1;\n    case 'SET_UNDEFINED':\n      return undefined as unknown as number;\n    default:\n      return state;\n  }\n}\n\ntype CounterWithAnotherBugAction =\n  | { type: 'INCREMENT' }\n  | { type: 'DECREMENT' }\n  | { type: 'SET_UNDEFINED' };\nfunction counterWithAnotherBug(state = 0, action: CounterWithBugAction) {\n  switch (action.type) {\n    case 'INCREMENT':\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      return (mistake as unknown as number) + 1;\n    case 'DECREMENT':\n      return state - 1;\n    case 'SET_UNDEFINED':\n      return undefined;\n    default:\n      return state;\n  }\n}\n\ntype DoubleCounterAction = { type: 'INCREMENT' } | { type: 'DECREMENT' };\nfunction doubleCounter(state = 0, action: DoubleCounterAction) {\n  switch (action.type) {\n    case 'INCREMENT':\n      return state + 2;\n    case 'DECREMENT':\n      return state - 2;\n    default:\n      return state;\n  }\n}\n\ntype CounterWithMultiplyAction =\n  | { type: 'INCREMENT' }\n  | { type: 'DECREMENT' }\n  | { type: 'MULTIPLY' };\nfunction counterWithMultiply(state = 0, action: CounterWithMultiplyAction) {\n  switch (action.type) {\n    case 'INCREMENT':\n      return state + 1;\n    case 'DECREMENT':\n      return state - 1;\n    case 'MULTIPLY':\n      return state * 2;\n    default:\n      return state;\n  }\n}\n\ndescribe('instrument', () => {\n  let store: EnhancedStore<number, CounterAction, null>;\n  let liftedStore: LiftedStore<number, CounterAction, null>;\n\n  beforeEach(() => {\n    store = createStore(counter, instrument());\n    liftedStore = store.liftedStore;\n  });\n\n  it('should perform actions', () => {\n    expect(store.getState()).toBe(0);\n    store.dispatch({ type: 'INCREMENT' });\n    expect(store.getState()).toBe(1);\n    store.dispatch({ type: 'INCREMENT' });\n    expect(store.getState()).toBe(2);\n  });\n\n  it('should provide observable', () => {\n    let lastValue;\n    // let calls = 0;\n\n    from(store as unknown as Observable<number>).subscribe((state) => {\n      lastValue = state;\n      // calls++;\n    });\n\n    expect(lastValue).toBe(0);\n    store.dispatch({ type: 'INCREMENT' });\n    expect(lastValue).toBe(1);\n  });\n\n  it('should rollback state to the last committed state', () => {\n    store.dispatch({ type: 'INCREMENT' });\n    store.dispatch({ type: 'INCREMENT' });\n    expect(store.getState()).toBe(2);\n\n    liftedStore.dispatch(ActionCreators.commit());\n    expect(store.getState()).toBe(2);\n\n    store.dispatch({ type: 'INCREMENT' });\n    store.dispatch({ type: 'INCREMENT' });\n    expect(store.getState()).toBe(4);\n\n    liftedStore.dispatch(ActionCreators.rollback());\n    expect(store.getState()).toBe(2);\n\n    store.dispatch({ type: 'DECREMENT' });\n    expect(store.getState()).toBe(1);\n\n    liftedStore.dispatch(ActionCreators.rollback());\n    expect(store.getState()).toBe(2);\n  });\n\n  it('should reset to initial state', () => {\n    store.dispatch({ type: 'INCREMENT' });\n    expect(store.getState()).toBe(1);\n\n    liftedStore.dispatch(ActionCreators.commit());\n    expect(store.getState()).toBe(1);\n\n    store.dispatch({ type: 'INCREMENT' });\n    expect(store.getState()).toBe(2);\n\n    liftedStore.dispatch(ActionCreators.rollback());\n    expect(store.getState()).toBe(1);\n\n    store.dispatch({ type: 'INCREMENT' });\n    expect(store.getState()).toBe(2);\n\n    liftedStore.dispatch(ActionCreators.reset());\n    expect(store.getState()).toBe(0);\n  });\n\n  it('should toggle an action', () => {\n    // actionId 0 = @@INIT\n    store.dispatch({ type: 'INCREMENT' });\n    store.dispatch({ type: 'DECREMENT' });\n    store.dispatch({ type: 'INCREMENT' });\n    expect(store.getState()).toBe(1);\n\n    liftedStore.dispatch(ActionCreators.toggleAction(2));\n    expect(store.getState()).toBe(2);\n\n    liftedStore.dispatch(ActionCreators.toggleAction(2));\n    expect(store.getState()).toBe(1);\n  });\n\n  it('should set multiple action skip', () => {\n    // actionId 0 = @@INIT\n    store.dispatch({ type: 'INCREMENT' });\n    store.dispatch({ type: 'INCREMENT' });\n    store.dispatch({ type: 'INCREMENT' });\n    expect(store.getState()).toBe(3);\n\n    liftedStore.dispatch(ActionCreators.setActionsActive(1, 3, false));\n    expect(store.getState()).toBe(1);\n\n    liftedStore.dispatch(ActionCreators.setActionsActive(0, 2, true));\n    expect(store.getState()).toBe(2);\n\n    liftedStore.dispatch(ActionCreators.setActionsActive(0, 1, true));\n    expect(store.getState()).toBe(2);\n  });\n\n  it('should sweep disabled actions', () => {\n    // actionId 0 = @@INIT\n    store.dispatch({ type: 'INCREMENT' });\n    store.dispatch({ type: 'DECREMENT' });\n    store.dispatch({ type: 'INCREMENT' });\n    store.dispatch({ type: 'INCREMENT' });\n\n    expect(store.getState()).toBe(2);\n    expect(liftedStore.getState().stagedActionIds).toEqual([0, 1, 2, 3, 4]);\n    expect(liftedStore.getState().skippedActionIds).toEqual([]);\n\n    liftedStore.dispatch(ActionCreators.toggleAction(2));\n    expect(store.getState()).toBe(3);\n    expect(liftedStore.getState().stagedActionIds).toEqual([0, 1, 2, 3, 4]);\n    expect(liftedStore.getState().skippedActionIds).toEqual([2]);\n\n    liftedStore.dispatch(ActionCreators.sweep());\n    expect(store.getState()).toBe(3);\n    expect(liftedStore.getState().stagedActionIds).toEqual([0, 1, 3, 4]);\n    expect(liftedStore.getState().skippedActionIds).toEqual([]);\n  });\n\n  it('should jump to state', () => {\n    store.dispatch({ type: 'INCREMENT' });\n    store.dispatch({ type: 'DECREMENT' });\n    store.dispatch({ type: 'INCREMENT' });\n    expect(store.getState()).toBe(1);\n\n    liftedStore.dispatch(ActionCreators.jumpToState(0));\n    expect(store.getState()).toBe(0);\n\n    liftedStore.dispatch(ActionCreators.jumpToState(1));\n    expect(store.getState()).toBe(1);\n\n    liftedStore.dispatch(ActionCreators.jumpToState(2));\n    expect(store.getState()).toBe(0);\n\n    store.dispatch({ type: 'INCREMENT' });\n    expect(store.getState()).toBe(0);\n\n    liftedStore.dispatch(ActionCreators.jumpToState(4));\n    expect(store.getState()).toBe(2);\n  });\n\n  it('should jump to action', () => {\n    store.dispatch({ type: 'INCREMENT' });\n    store.dispatch({ type: 'DECREMENT' });\n    store.dispatch({ type: 'INCREMENT' });\n    expect(store.getState()).toBe(1);\n\n    liftedStore.dispatch(ActionCreators.jumpToAction(0));\n    expect(store.getState()).toBe(0);\n\n    liftedStore.dispatch(ActionCreators.jumpToAction(1));\n    expect(store.getState()).toBe(1);\n\n    liftedStore.dispatch(ActionCreators.jumpToAction(10));\n    expect(store.getState()).toBe(1);\n  });\n\n  it('should reorder actions', () => {\n    const storeWithMultiply = createStore(counterWithMultiply, instrument());\n    storeWithMultiply.dispatch({ type: 'INCREMENT' });\n    storeWithMultiply.dispatch({ type: 'DECREMENT' });\n    storeWithMultiply.dispatch({ type: 'INCREMENT' });\n    storeWithMultiply.dispatch({ type: 'MULTIPLY' });\n    expect(storeWithMultiply.liftedStore.getState().stagedActionIds).toEqual([\n      0, 1, 2, 3, 4,\n    ]);\n    expect(storeWithMultiply.getState()).toBe(2);\n\n    storeWithMultiply.liftedStore.dispatch(ActionCreators.reorderAction(4, 1));\n    expect(storeWithMultiply.liftedStore.getState().stagedActionIds).toEqual([\n      0, 4, 1, 2, 3,\n    ]);\n    expect(storeWithMultiply.getState()).toBe(1);\n\n    storeWithMultiply.liftedStore.dispatch(ActionCreators.reorderAction(4, 1));\n    expect(storeWithMultiply.liftedStore.getState().stagedActionIds).toEqual([\n      0, 4, 1, 2, 3,\n    ]);\n    expect(storeWithMultiply.getState()).toBe(1);\n\n    storeWithMultiply.liftedStore.dispatch(ActionCreators.reorderAction(4, 2));\n    expect(storeWithMultiply.liftedStore.getState().stagedActionIds).toEqual([\n      0, 1, 4, 2, 3,\n    ]);\n    expect(storeWithMultiply.getState()).toBe(2);\n\n    storeWithMultiply.liftedStore.dispatch(ActionCreators.reorderAction(1, 10));\n    expect(storeWithMultiply.liftedStore.getState().stagedActionIds).toEqual([\n      0, 4, 2, 3, 1,\n    ]);\n    expect(storeWithMultiply.getState()).toBe(1);\n\n    storeWithMultiply.liftedStore.dispatch(ActionCreators.reorderAction(10, 1));\n    expect(storeWithMultiply.liftedStore.getState().stagedActionIds).toEqual([\n      0, 4, 2, 3, 1,\n    ]);\n    expect(storeWithMultiply.getState()).toBe(1);\n\n    storeWithMultiply.liftedStore.dispatch(ActionCreators.reorderAction(1, -2));\n    expect(storeWithMultiply.liftedStore.getState().stagedActionIds).toEqual([\n      0, 1, 4, 2, 3,\n    ]);\n    expect(storeWithMultiply.getState()).toBe(2);\n\n    storeWithMultiply.liftedStore.dispatch(ActionCreators.reorderAction(0, 1));\n    expect(storeWithMultiply.liftedStore.getState().stagedActionIds).toEqual([\n      0, 1, 4, 2, 3,\n    ]);\n    expect(storeWithMultiply.getState()).toBe(2);\n  });\n\n  it('should replace the reducer', () => {\n    store.dispatch({ type: 'INCREMENT' });\n    store.dispatch({ type: 'DECREMENT' });\n    store.dispatch({ type: 'INCREMENT' });\n    expect(store.getState()).toBe(1);\n\n    store.replaceReducer(doubleCounter);\n    expect(store.getState()).toBe(2);\n  });\n\n  it('should replace the reducer without recomputing actions', () => {\n    store = createStore(\n      counter,\n      instrument(undefined, { shouldHotReload: false }),\n    );\n    expect(store.getState()).toBe(0);\n    store.dispatch({ type: 'INCREMENT' });\n    store.dispatch({ type: 'DECREMENT' });\n    store.dispatch({ type: 'INCREMENT' });\n    expect(store.getState()).toBe(1);\n\n    store.replaceReducer(doubleCounter);\n    expect(store.getState()).toBe(1);\n    store.dispatch({ type: 'INCREMENT' });\n    expect(store.getState()).toBe(3);\n\n    store.replaceReducer(\n      (() => ({ test: true }) as unknown) as Reducer<number, CounterAction>,\n    );\n    const newStore = store as unknown as Store<{ test: boolean }>;\n    expect(newStore.getState()).toEqual({ test: true });\n  });\n\n  it('should catch and record errors', () => {\n    const spy = jest.spyOn(console, 'error').mockImplementation(() => {\n      // noop\n    });\n    const storeWithBug = createStore(\n      counterWithBug,\n      instrument(undefined, { shouldCatchErrors: true }),\n    );\n\n    storeWithBug.dispatch({ type: 'INCREMENT' });\n    storeWithBug.dispatch({ type: 'DECREMENT' });\n    storeWithBug.dispatch({ type: 'INCREMENT' });\n\n    const { computedStates } = storeWithBug.liftedStore.getState();\n    expect(computedStates[2].error).toMatch(/ReferenceError/);\n    expect(computedStates[3].error).toMatch(\n      /Interrupted by an error up the chain/,\n    );\n    expect(spy.mock.calls[0][0].toString()).toMatch(/ReferenceError/);\n\n    spy.mockReset();\n  });\n\n  it('should catch invalid action type (undefined type)', () => {\n    expect(() => {\n      store.dispatch({ type: undefined } as unknown as CounterAction);\n    }).toThrow(\n      'Actions may not have an undefined \"type\" property. ' +\n        'Have you misspelled a constant?',\n    );\n  });\n\n  it('should catch invalid action type (function)', () => {\n    function ActionClass(this: any) {\n      this.type = 'test';\n    }\n\n    expect(() => {\n      store.dispatch(new (ActionClass as any)() as CounterAction);\n    }).toThrow(\n      'Actions must be plain objects. ' +\n        'Use custom middleware for async actions.',\n    );\n  });\n\n  it('should return the last non-undefined state from getState', () => {\n    const storeWithBug = createStore(counterWithBug, instrument());\n    storeWithBug.dispatch({ type: 'INCREMENT' });\n    storeWithBug.dispatch({ type: 'INCREMENT' });\n    expect(storeWithBug.getState()).toBe(2);\n\n    storeWithBug.dispatch({ type: 'SET_UNDEFINED' });\n    expect(storeWithBug.getState()).toBe(2);\n  });\n\n  it('should not recompute states on every action', () => {\n    let reducerCalls = 0;\n    const monitoredStore = createStore(() => reducerCalls++, instrument());\n    expect(reducerCalls).toBe(1);\n    monitoredStore.dispatch({ type: 'INCREMENT' });\n    monitoredStore.dispatch({ type: 'INCREMENT' });\n    monitoredStore.dispatch({ type: 'INCREMENT' });\n    expect(reducerCalls).toBe(4);\n  });\n\n  it('should not recompute old states when toggling an action', () => {\n    let reducerCalls = 0;\n    const monitoredStore = createStore(() => reducerCalls++, instrument());\n    const monitoredLiftedStore = monitoredStore.liftedStore;\n\n    expect(reducerCalls).toBe(1);\n    // actionId 0 = @@INIT\n    monitoredStore.dispatch({ type: 'INCREMENT' });\n    monitoredStore.dispatch({ type: 'INCREMENT' });\n    monitoredStore.dispatch({ type: 'INCREMENT' });\n    expect(reducerCalls).toBe(4);\n\n    monitoredLiftedStore.dispatch(ActionCreators.toggleAction(3));\n    expect(reducerCalls).toBe(4);\n\n    monitoredLiftedStore.dispatch(ActionCreators.toggleAction(3));\n    expect(reducerCalls).toBe(5);\n\n    monitoredLiftedStore.dispatch(ActionCreators.toggleAction(2));\n    expect(reducerCalls).toBe(6);\n\n    monitoredLiftedStore.dispatch(ActionCreators.toggleAction(2));\n    expect(reducerCalls).toBe(8);\n\n    monitoredLiftedStore.dispatch(ActionCreators.toggleAction(1));\n    expect(reducerCalls).toBe(10);\n\n    monitoredLiftedStore.dispatch(ActionCreators.toggleAction(2));\n    expect(reducerCalls).toBe(11);\n\n    monitoredLiftedStore.dispatch(ActionCreators.toggleAction(3));\n    expect(reducerCalls).toBe(11);\n\n    monitoredLiftedStore.dispatch(ActionCreators.toggleAction(1));\n    expect(reducerCalls).toBe(12);\n\n    monitoredLiftedStore.dispatch(ActionCreators.toggleAction(3));\n    expect(reducerCalls).toBe(13);\n\n    monitoredLiftedStore.dispatch(ActionCreators.toggleAction(2));\n    expect(reducerCalls).toBe(15);\n  });\n\n  it('should not recompute states when jumping to state', () => {\n    let reducerCalls = 0;\n    const monitoredStore = createStore(() => reducerCalls++, instrument());\n    const monitoredLiftedStore = monitoredStore.liftedStore;\n\n    expect(reducerCalls).toBe(1);\n    monitoredStore.dispatch({ type: 'INCREMENT' });\n    monitoredStore.dispatch({ type: 'INCREMENT' });\n    monitoredStore.dispatch({ type: 'INCREMENT' });\n    expect(reducerCalls).toBe(4);\n\n    const savedComputedStates = monitoredLiftedStore.getState().computedStates;\n\n    monitoredLiftedStore.dispatch(ActionCreators.jumpToState(0));\n    expect(reducerCalls).toBe(4);\n\n    monitoredLiftedStore.dispatch(ActionCreators.jumpToState(1));\n    expect(reducerCalls).toBe(4);\n\n    monitoredLiftedStore.dispatch(ActionCreators.jumpToState(3));\n    expect(reducerCalls).toBe(4);\n\n    expect(monitoredLiftedStore.getState().computedStates).toBe(\n      savedComputedStates,\n    );\n  });\n\n  it('should not recompute states on monitor actions', () => {\n    let reducerCalls = 0;\n    const monitoredStore = createStore(() => reducerCalls++, instrument());\n    const monitoredLiftedStore = monitoredStore.liftedStore;\n\n    expect(reducerCalls).toBe(1);\n    monitoredStore.dispatch({ type: 'INCREMENT' });\n    monitoredStore.dispatch({ type: 'INCREMENT' });\n    monitoredStore.dispatch({ type: 'INCREMENT' });\n    expect(reducerCalls).toBe(4);\n\n    const savedComputedStates = monitoredLiftedStore.getState().computedStates;\n\n    monitoredLiftedStore.dispatch({ type: 'lol' } as unknown as LiftedAction<\n      number,\n      Action,\n      null\n    >);\n    expect(reducerCalls).toBe(4);\n\n    monitoredLiftedStore.dispatch({ type: 'wat' } as unknown as LiftedAction<\n      number,\n      Action,\n      null\n    >);\n    expect(reducerCalls).toBe(4);\n\n    expect(monitoredLiftedStore.getState().computedStates).toBe(\n      savedComputedStates,\n    );\n  });\n\n  describe('maxAge option', () => {\n    let configuredStore: EnhancedStore<number, CounterAction, null>;\n    let configuredLiftedStore: LiftedStore<number, CounterAction, null>;\n\n    beforeEach(() => {\n      configuredStore = createStore(\n        counter,\n        instrument(undefined, { maxAge: 3 }),\n      );\n      configuredLiftedStore = configuredStore.liftedStore;\n    });\n\n    it('should auto-commit earliest non-@@INIT action when maxAge is reached', () => {\n      configuredStore.dispatch({ type: 'INCREMENT' });\n      configuredStore.dispatch({ type: 'INCREMENT' });\n      let liftedStoreState = configuredLiftedStore.getState();\n\n      expect(configuredStore.getState()).toBe(2);\n      expect(Object.keys(liftedStoreState.actionsById)).toHaveLength(3);\n      expect(liftedStoreState.committedState).toBeUndefined();\n      expect(liftedStoreState.stagedActionIds).toContain(1);\n\n      // Trigger auto-commit.\n      configuredStore.dispatch({ type: 'INCREMENT' });\n      liftedStoreState = configuredLiftedStore.getState();\n\n      expect(configuredStore.getState()).toBe(3);\n      expect(Object.keys(liftedStoreState.actionsById)).toHaveLength(3);\n      expect(liftedStoreState.stagedActionIds).not.toContain(1);\n      expect(liftedStoreState.computedStates[0].state).toBe(1);\n      expect(liftedStoreState.committedState).toBe(1);\n      expect(liftedStoreState.currentStateIndex).toBe(2);\n    });\n\n    it('should remove skipped actions once committed', () => {\n      configuredStore.dispatch({ type: 'INCREMENT' });\n      configuredLiftedStore.dispatch(ActionCreators.toggleAction(1));\n      configuredStore.dispatch({ type: 'INCREMENT' });\n      expect(configuredLiftedStore.getState().skippedActionIds).toContain(1);\n      configuredStore.dispatch({ type: 'INCREMENT' });\n      expect(configuredLiftedStore.getState().skippedActionIds).not.toContain(\n        1,\n      );\n    });\n\n    it('should not auto-commit errors', () => {\n      const spy = jest.spyOn(console, 'error');\n\n      const storeWithBug = createStore(\n        counterWithBug,\n        instrument(undefined, { maxAge: 3, shouldCatchErrors: true }),\n      );\n      const liftedStoreWithBug = storeWithBug.liftedStore;\n      storeWithBug.dispatch({ type: 'DECREMENT' });\n      storeWithBug.dispatch({ type: 'INCREMENT' });\n      expect(liftedStoreWithBug.getState().stagedActionIds).toHaveLength(3);\n\n      storeWithBug.dispatch({ type: 'INCREMENT' });\n      expect(liftedStoreWithBug.getState().stagedActionIds).toHaveLength(4);\n\n      spy.mockReset();\n    });\n\n    it('should auto-commit actions after hot reload fixes error', () => {\n      const spy = jest.spyOn(console, 'error');\n\n      const storeWithBug = createStore(\n        counterWithBug,\n        instrument(undefined, { maxAge: 3, shouldCatchErrors: true }),\n      );\n      const liftedStoreWithBug = storeWithBug.liftedStore;\n      storeWithBug.dispatch({ type: 'DECREMENT' });\n      storeWithBug.dispatch({ type: 'DECREMENT' });\n      storeWithBug.dispatch({ type: 'INCREMENT' });\n      storeWithBug.dispatch({ type: 'DECREMENT' });\n      storeWithBug.dispatch({ type: 'DECREMENT' });\n      storeWithBug.dispatch({ type: 'DECREMENT' });\n      expect(liftedStoreWithBug.getState().stagedActionIds).toHaveLength(7);\n\n      // Auto-commit 2 actions by \"fixing\" reducer bug, but introducing another.\n      storeWithBug.replaceReducer(\n        counterWithAnotherBug as Reducer<number, CounterWithBugAction>,\n      );\n      const liftedStoreWithAnotherBug =\n        liftedStoreWithBug as unknown as LiftedStore<\n          number,\n          CounterWithAnotherBugAction,\n          null\n        >;\n      expect(liftedStoreWithAnotherBug.getState().stagedActionIds).toHaveLength(\n        5,\n      );\n\n      // Auto-commit 2 more actions by \"fixing\" other reducer bug.\n      storeWithBug.replaceReducer(\n        counter as Reducer<number, CounterWithBugAction>,\n      );\n      const liftedStore = liftedStoreWithBug as LiftedStore<\n        number,\n        CounterAction,\n        null\n      >;\n      expect(liftedStore.getState().stagedActionIds).toHaveLength(3);\n\n      spy.mockReset();\n    });\n\n    it('should update currentStateIndex when auto-committing', () => {\n      let liftedStoreState;\n\n      configuredStore.dispatch({ type: 'INCREMENT' });\n      configuredStore.dispatch({ type: 'INCREMENT' });\n      liftedStoreState = configuredLiftedStore.getState();\n      expect(liftedStoreState.currentStateIndex).toBe(2);\n\n      // currentStateIndex should stay at 2 as actions are committed.\n      configuredStore.dispatch({ type: 'INCREMENT' });\n      liftedStoreState = configuredLiftedStore.getState();\n      const currentComputedState =\n        liftedStoreState.computedStates[liftedStoreState.currentStateIndex];\n      expect(liftedStoreState.currentStateIndex).toBe(2);\n      expect(currentComputedState.state).toBe(3);\n    });\n\n    it('should continue to increment currentStateIndex while error blocks commit', () => {\n      const spy = jest.spyOn(console, 'error');\n\n      const storeWithBug = createStore(\n        counterWithBug,\n        instrument(undefined, { maxAge: 3, shouldCatchErrors: true }),\n      );\n      const liftedStoreWithBug = storeWithBug.liftedStore;\n\n      storeWithBug.dispatch({ type: 'DECREMENT' });\n      storeWithBug.dispatch({ type: 'DECREMENT' });\n      storeWithBug.dispatch({ type: 'DECREMENT' });\n      storeWithBug.dispatch({ type: 'DECREMENT' });\n\n      const liftedStoreState = liftedStoreWithBug.getState();\n      const currentComputedState =\n        liftedStoreState.computedStates[liftedStoreState.currentStateIndex];\n      expect(liftedStoreState.currentStateIndex).toBe(4);\n      expect(currentComputedState.state).toBe(0);\n      expect(currentComputedState.error).toBeTruthy();\n\n      spy.mockReset();\n    });\n\n    it('should adjust currentStateIndex correctly when multiple actions are committed', () => {\n      const spy = jest.spyOn(console, 'error');\n\n      const storeWithBug = createStore(\n        counterWithBug,\n        instrument(undefined, { maxAge: 3, shouldCatchErrors: true }),\n      );\n      const liftedStoreWithBug = storeWithBug.liftedStore;\n\n      storeWithBug.dispatch({ type: 'DECREMENT' });\n      storeWithBug.dispatch({ type: 'DECREMENT' });\n      storeWithBug.dispatch({ type: 'DECREMENT' });\n      storeWithBug.dispatch({ type: 'DECREMENT' });\n\n      // Auto-commit 2 actions by \"fixing\" reducer bug.\n      storeWithBug.replaceReducer(\n        counter as Reducer<number, CounterWithBugAction>,\n      );\n      const liftedStore = liftedStoreWithBug as LiftedStore<\n        number,\n        CounterAction,\n        null\n      >;\n      const liftedStoreState = liftedStore.getState();\n      const currentComputedState =\n        liftedStoreState.computedStates[liftedStoreState.currentStateIndex];\n      expect(liftedStoreState.currentStateIndex).toBe(2);\n      expect(currentComputedState.state).toBe(-4);\n\n      spy.mockReset();\n    });\n\n    it('should not allow currentStateIndex to drop below 0', () => {\n      const spy = jest.spyOn(console, 'error');\n\n      const storeWithBug = createStore(\n        counterWithBug,\n        instrument(undefined, { maxAge: 3, shouldCatchErrors: true }),\n      );\n      const liftedStoreWithBug = storeWithBug.liftedStore;\n\n      storeWithBug.dispatch({ type: 'DECREMENT' });\n      storeWithBug.dispatch({ type: 'DECREMENT' });\n      storeWithBug.dispatch({ type: 'DECREMENT' });\n      storeWithBug.dispatch({ type: 'DECREMENT' });\n      liftedStoreWithBug.dispatch(ActionCreators.jumpToState(1));\n\n      // Auto-commit 2 actions by \"fixing\" reducer bug.\n      storeWithBug.replaceReducer(\n        counter as Reducer<number, CounterWithBugAction>,\n      );\n      const liftedStore = liftedStoreWithBug as LiftedStore<\n        number,\n        CounterAction,\n        null\n      >;\n      const liftedStoreState = liftedStore.getState();\n      const currentComputedState =\n        liftedStoreState.computedStates[liftedStoreState.currentStateIndex];\n      expect(liftedStoreState.currentStateIndex).toBe(0);\n      expect(currentComputedState.state).toBe(-2);\n\n      spy.mockReset();\n    });\n\n    it('should use dynamic maxAge', () => {\n      let max = 3;\n      const getMaxAge = jest.fn().mockImplementation(() => max);\n      store = createStore(\n        counter,\n        instrument(undefined, { maxAge: getMaxAge }),\n      );\n\n      expect(getMaxAge.mock.calls).toHaveLength(1);\n      store.dispatch({ type: 'INCREMENT' });\n      expect(getMaxAge.mock.calls).toHaveLength(2);\n      store.dispatch({ type: 'INCREMENT' });\n      expect(getMaxAge.mock.calls).toHaveLength(3);\n      let liftedStoreState = store.liftedStore.getState();\n\n      expect(getMaxAge.mock.calls[0][0].type).toContain('INIT');\n      expect(getMaxAge.mock.calls[0][1]).toBeUndefined();\n      expect(getMaxAge.mock.calls[1][0].type).toBe('PERFORM_ACTION');\n      expect(getMaxAge.mock.calls[1][1].nextActionId).toBe(1);\n      expect(getMaxAge.mock.calls[1][1].stagedActionIds).toEqual([0]);\n      expect(getMaxAge.mock.calls[2][1].nextActionId).toBe(2);\n      expect(getMaxAge.mock.calls[2][1].stagedActionIds).toEqual([0, 1]);\n\n      expect(store.getState()).toBe(2);\n      expect(Object.keys(liftedStoreState.actionsById)).toHaveLength(3);\n      expect(liftedStoreState.committedState).toBeUndefined();\n      expect(liftedStoreState.stagedActionIds).toContain(1);\n\n      // Trigger auto-commit.\n      store.dispatch({ type: 'INCREMENT' });\n      liftedStoreState = store.liftedStore.getState();\n\n      expect(store.getState()).toBe(3);\n      expect(Object.keys(liftedStoreState.actionsById)).toHaveLength(3);\n      expect(liftedStoreState.stagedActionIds).not.toContain(1);\n      expect(liftedStoreState.computedStates[0].state).toBe(1);\n      expect(liftedStoreState.committedState).toBe(1);\n      expect(liftedStoreState.currentStateIndex).toBe(2);\n\n      max = 4;\n      store.dispatch({ type: 'INCREMENT' });\n      liftedStoreState = store.liftedStore.getState();\n\n      expect(store.getState()).toBe(4);\n      expect(Object.keys(liftedStoreState.actionsById)).toHaveLength(4);\n      expect(liftedStoreState.stagedActionIds).not.toContain(1);\n      expect(liftedStoreState.computedStates[0].state).toBe(1);\n      expect(liftedStoreState.committedState).toBe(1);\n      expect(liftedStoreState.currentStateIndex).toBe(3);\n\n      max = 3;\n      store.dispatch({ type: 'INCREMENT' });\n      liftedStoreState = store.liftedStore.getState();\n\n      expect(store.getState()).toBe(5);\n      expect(Object.keys(liftedStoreState.actionsById)).toHaveLength(3);\n      expect(liftedStoreState.stagedActionIds).not.toContain(1);\n      expect(liftedStoreState.computedStates[0].state).toBe(3);\n      expect(liftedStoreState.committedState).toBe(3);\n      expect(liftedStoreState.currentStateIndex).toBe(2);\n\n      store.dispatch({ type: 'INCREMENT' });\n      liftedStoreState = store.liftedStore.getState();\n\n      expect(store.getState()).toBe(6);\n      expect(Object.keys(liftedStoreState.actionsById)).toHaveLength(3);\n      expect(liftedStoreState.stagedActionIds).not.toContain(1);\n      expect(liftedStoreState.computedStates[0].state).toBe(4);\n      expect(liftedStoreState.committedState).toBe(4);\n      expect(liftedStoreState.currentStateIndex).toBe(2);\n    });\n\n    it('should throw error when maxAge < 2', () => {\n      expect(() => {\n        createStore(counter, instrument(undefined, { maxAge: 1 }));\n      }).toThrow(/may not be less than 2/);\n    });\n  });\n\n  describe('trace option', () => {\n    let monitoredStore;\n    let monitoredLiftedStore;\n    let exportedState;\n\n    it('should not include stack trace', () => {\n      monitoredStore = createStore(counter, instrument());\n      monitoredLiftedStore = monitoredStore.liftedStore;\n      monitoredStore.dispatch({ type: 'INCREMENT' });\n\n      exportedState = monitoredLiftedStore.getState();\n      expect(exportedState.actionsById[0].stack).toBeUndefined();\n      expect(exportedState.actionsById[1].stack).toBeUndefined();\n    });\n\n    it('should include stack trace', () => {\n      function fn1() {\n        monitoredStore = createStore(\n          counter,\n          instrument(undefined, { trace: true }),\n        );\n        monitoredLiftedStore = monitoredStore.liftedStore;\n        monitoredStore.dispatch({ type: 'INCREMENT' });\n\n        exportedState = monitoredLiftedStore.getState();\n        expect(exportedState.actionsById[0].stack).toBeUndefined();\n        expect(typeof exportedState.actionsById[1].stack).toBe('string');\n        expect(exportedState.actionsById[1].stack).toMatch(/^Error/);\n        expect(exportedState.actionsById[1].stack).not.toMatch(/instrument.ts/);\n        expect(exportedState.actionsById[1].stack).toMatch(/\\bfn1\\b/);\n        expect(exportedState.actionsById[1].stack).toMatch(/\\bfn2\\b/);\n        expect(exportedState.actionsById[1].stack).toMatch(/\\bfn3\\b/);\n        expect(exportedState.actionsById[1].stack).toMatch(/\\bfn4\\b/);\n        expect(exportedState.actionsById[1].stack).toContain(\n          'instrument.spec.ts',\n        );\n        expect(exportedState.actionsById[1].stack!.split('\\n')).toHaveLength(\n          10 + 1,\n        ); // +1 is for `Error\\n`\n      }\n\n      function fn2() {\n        return fn1();\n      }\n\n      function fn3() {\n        return fn2();\n      }\n\n      function fn4() {\n        return fn3();\n      }\n\n      fn4();\n    });\n\n    it('should include only 3 frames for stack trace', () => {\n      function fn1() {\n        monitoredStore = createStore(\n          counter,\n          instrument(undefined, { trace: true, traceLimit: 3 }),\n        );\n        monitoredLiftedStore = monitoredStore.liftedStore;\n        monitoredStore.dispatch({ type: 'INCREMENT' });\n\n        exportedState = monitoredLiftedStore.getState();\n        expect(exportedState.actionsById[0].stack).toBeUndefined();\n        expect(typeof exportedState.actionsById[1].stack).toBe('string');\n        expect(exportedState.actionsById[1].stack).toMatch(/\\bfn1\\b/);\n        expect(exportedState.actionsById[1].stack).toMatch(/\\bfn2\\b/);\n        expect(exportedState.actionsById[1].stack).toMatch(/\\bfn3\\b/);\n        expect(exportedState.actionsById[1].stack).not.toMatch(/\\bfn4\\b/);\n        expect(exportedState.actionsById[1].stack).toContain(\n          'instrument.spec.ts',\n        );\n        expect(exportedState.actionsById[1].stack!.split('\\n')).toHaveLength(\n          3 + 1,\n        );\n      }\n\n      function fn2() {\n        return fn1();\n      }\n\n      function fn3() {\n        return fn2();\n      }\n\n      function fn4() {\n        return fn3();\n      }\n\n      fn4();\n    });\n\n    it('should force traceLimit value of 3 when Error.stackTraceLimit is 10', () => {\n      const stackTraceLimit = Error.stackTraceLimit;\n      Error.stackTraceLimit = 10;\n\n      function fn1() {\n        monitoredStore = createStore(\n          counter,\n          instrument(undefined, { trace: true, traceLimit: 3 }),\n        );\n        monitoredLiftedStore = monitoredStore.liftedStore;\n        monitoredStore.dispatch({ type: 'INCREMENT' });\n\n        exportedState = monitoredLiftedStore.getState();\n        expect(exportedState.actionsById[0].stack).toBeUndefined();\n        expect(typeof exportedState.actionsById[1].stack).toBe('string');\n        expect(exportedState.actionsById[1].stack).toMatch(/\\bfn1\\b/);\n        expect(exportedState.actionsById[1].stack).toMatch(/\\bfn2\\b/);\n        expect(exportedState.actionsById[1].stack).toMatch(/\\bfn3\\b/);\n        expect(exportedState.actionsById[1].stack).not.toMatch(/\\bfn4\\b/);\n        expect(exportedState.actionsById[1].stack).toContain(\n          'instrument.spec.ts',\n        );\n        expect(exportedState.actionsById[1].stack!.split('\\n')).toHaveLength(\n          3 + 1,\n        );\n      }\n\n      function fn2() {\n        return fn1();\n      }\n\n      function fn3() {\n        return fn2();\n      }\n\n      function fn4() {\n        return fn3();\n      }\n\n      fn4();\n      Error.stackTraceLimit = stackTraceLimit;\n    });\n\n    it('should force traceLimit value of 5 even when Error.stackTraceLimit is 2', () => {\n      const stackTraceLimit = Error.stackTraceLimit;\n      Error.stackTraceLimit = 2;\n      monitoredStore = createStore(\n        counter,\n        instrument(undefined, { trace: true, traceLimit: 5 }),\n      );\n      monitoredLiftedStore = monitoredStore.liftedStore;\n      monitoredStore.dispatch({ type: 'INCREMENT' });\n      Error.stackTraceLimit = stackTraceLimit;\n\n      exportedState = monitoredLiftedStore.getState();\n      expect(exportedState.actionsById[0].stack).toBeUndefined();\n      expect(typeof exportedState.actionsById[1].stack).toBe('string');\n      expect(exportedState.actionsById[1].stack).toMatch(/^Error/);\n      expect(exportedState.actionsById[1].stack).toContain(\n        'instrument.spec.ts',\n      );\n      expect(exportedState.actionsById[1].stack!.split('\\n')).toHaveLength(\n        5 + 1,\n      );\n    });\n\n    it('should force default limit of 10 even when Error.stackTraceLimit is 3', () => {\n      const stackTraceLimit = Error.stackTraceLimit;\n      Error.stackTraceLimit = 3;\n\n      function fn1() {\n        monitoredStore = createStore(\n          counter,\n          instrument(undefined, { trace: true }),\n        );\n        monitoredLiftedStore = monitoredStore.liftedStore;\n        monitoredStore.dispatch({ type: 'INCREMENT' });\n        Error.stackTraceLimit = stackTraceLimit;\n\n        exportedState = monitoredLiftedStore.getState();\n        expect(exportedState.actionsById[0].stack).toBeUndefined();\n        expect(typeof exportedState.actionsById[1].stack).toBe('string');\n        expect(exportedState.actionsById[1].stack).toMatch(/\\bfn1\\b/);\n        expect(exportedState.actionsById[1].stack).toMatch(/\\bfn2\\b/);\n        expect(exportedState.actionsById[1].stack).toMatch(/\\bfn3\\b/);\n        expect(exportedState.actionsById[1].stack).toMatch(/\\bfn4\\b/);\n        expect(exportedState.actionsById[1].stack).toContain(\n          'instrument.spec.ts',\n        );\n        expect(exportedState.actionsById[1].stack!.split('\\n')).toHaveLength(\n          10 + 1,\n        );\n      }\n\n      function fn2() {\n        return fn1();\n      }\n\n      function fn3() {\n        return fn2();\n      }\n\n      function fn4() {\n        return fn3();\n      }\n\n      fn4();\n    });\n\n    it('should include 3 extra frames when Error.captureStackTrace not suported', () => {\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      const captureStackTrace = Error.captureStackTrace;\n      Error.captureStackTrace = undefined as unknown as () => unknown;\n      monitoredStore = createStore(\n        counter,\n        instrument(undefined, { trace: true, traceLimit: 5 }),\n      );\n      monitoredLiftedStore = monitoredStore.liftedStore;\n      monitoredStore.dispatch({ type: 'INCREMENT' });\n      Error.captureStackTrace = captureStackTrace;\n\n      exportedState = monitoredLiftedStore.getState();\n      expect(exportedState.actionsById[0].stack).toBeUndefined();\n      expect(typeof exportedState.actionsById[1].stack).toBe('string');\n      expect(exportedState.actionsById[1].stack).toMatch(/^Error/);\n      expect(exportedState.actionsById[1].stack).toContain('instrument.ts');\n      expect(exportedState.actionsById[1].stack).toContain(\n        'instrument.spec.ts',\n      );\n      expect(exportedState.actionsById[1].stack!.split('\\n')).toHaveLength(\n        5 + 3 + 1,\n      );\n    });\n\n    it('should get stack trace from a function', () => {\n      const traceFn = () => new Error().stack;\n      monitoredStore = createStore(\n        counter,\n        instrument(undefined, { trace: traceFn }),\n      );\n      monitoredLiftedStore = monitoredStore.liftedStore;\n      monitoredStore.dispatch({ type: 'INCREMENT' });\n\n      exportedState = monitoredLiftedStore.getState();\n      expect(exportedState.actionsById[0].stack).toBeUndefined();\n      expect(typeof exportedState.actionsById[1].stack).toBe('string');\n      expect(exportedState.actionsById[1].stack).toContain(\n        'at Object.performAction',\n      );\n      expect(exportedState.actionsById[1].stack).toContain('instrument.ts');\n      expect(exportedState.actionsById[1].stack).toContain(\n        'instrument.spec.ts',\n      );\n    });\n\n    it('should get stack trace inside setTimeout using a function', () =>\n      new Promise<void>((done) => {\n        const stack = new Error().stack;\n        setTimeout(() => {\n          const traceFn = () => stack! + new Error().stack!;\n          monitoredStore = createStore(\n            counter,\n            instrument(undefined, { trace: traceFn }),\n          );\n          monitoredLiftedStore = monitoredStore.liftedStore;\n          monitoredStore.dispatch({ type: 'INCREMENT' });\n\n          exportedState = monitoredLiftedStore.getState();\n          expect(exportedState.actionsById[0].stack).toBeUndefined();\n          expect(typeof exportedState.actionsById[1].stack).toBe('string');\n          expect(exportedState.actionsById[1].stack).toContain(\n            'at Object.performAction',\n          );\n          expect(exportedState.actionsById[1].stack).toContain('instrument.ts');\n          expect(exportedState.actionsById[1].stack).toContain(\n            'instrument.spec.ts',\n          );\n          done();\n        });\n      }));\n  });\n\n  describe('Import State', () => {\n    let monitoredStore: EnhancedStore<number, CounterAction, null>;\n    let monitoredLiftedStore: LiftedStore<number, CounterAction, null>;\n    let exportedState: LiftedState<number, CounterAction, null>;\n\n    beforeEach(() => {\n      monitoredStore = createStore(counter, instrument());\n      monitoredLiftedStore = monitoredStore.liftedStore;\n      // Set up state to export\n      monitoredStore.dispatch({ type: 'INCREMENT' });\n      monitoredStore.dispatch({ type: 'INCREMENT' });\n      monitoredStore.dispatch({ type: 'INCREMENT' });\n\n      exportedState = monitoredLiftedStore.getState();\n    });\n\n    it('should replay all the steps when a state is imported', () => {\n      const importMonitoredStore = createStore(counter, instrument());\n      const importMonitoredLiftedStore = importMonitoredStore.liftedStore;\n\n      importMonitoredLiftedStore.dispatch(\n        ActionCreators.importState(exportedState),\n      );\n      expect(importMonitoredLiftedStore.getState()).toEqual(exportedState);\n    });\n\n    it('should replace the existing action log with the one imported', () => {\n      const importMonitoredStore = createStore(counter, instrument());\n      const importMonitoredLiftedStore = importMonitoredStore.liftedStore;\n\n      importMonitoredStore.dispatch({ type: 'DECREMENT' });\n      importMonitoredStore.dispatch({ type: 'DECREMENT' });\n\n      importMonitoredLiftedStore.dispatch(\n        ActionCreators.importState(exportedState),\n      );\n      expect(importMonitoredLiftedStore.getState()).toEqual(exportedState);\n    });\n\n    it('should allow for state to be imported without replaying actions', () => {\n      const importMonitoredStore = createStore(counter, instrument());\n      const importMonitoredLiftedStore = importMonitoredStore.liftedStore;\n\n      const noComputedExportedState = Object.assign({}, exportedState);\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      delete noComputedExportedState.computedStates;\n\n      importMonitoredLiftedStore.dispatch(\n        ActionCreators.importState(noComputedExportedState, true),\n      );\n\n      const expectedImportedState = Object.assign({}, noComputedExportedState, {\n        computedStates: undefined,\n      });\n      expect(importMonitoredLiftedStore.getState()).toEqual(\n        expectedImportedState,\n      );\n    });\n\n    it('should include stack trace', () => {\n      const importMonitoredStore = createStore(\n        counter,\n        instrument(undefined, { trace: true }),\n      );\n      const importMonitoredLiftedStore = importMonitoredStore.liftedStore;\n\n      importMonitoredStore.dispatch({ type: 'DECREMENT' });\n      importMonitoredStore.dispatch({ type: 'DECREMENT' });\n\n      const oldState = importMonitoredLiftedStore.getState();\n      expect(oldState.actionsById[0].stack).toBeUndefined();\n      expect(typeof oldState.actionsById[1].stack).toBe('string');\n\n      importMonitoredLiftedStore.dispatch(ActionCreators.importState(oldState));\n      expect(importMonitoredLiftedStore.getState()).toEqual(oldState);\n      expect(\n        importMonitoredLiftedStore.getState().actionsById[0].stack,\n      ).toBeUndefined();\n      expect(importMonitoredLiftedStore.getState().actionsById[1]).toEqual(\n        oldState.actionsById[1],\n      );\n    });\n  });\n\n  function filterStackAndTimestamps<S, A extends Action<string>>(\n    state: LiftedState<S, A, null>,\n  ) {\n    state.actionsById = Object.fromEntries(\n      Object.entries(state.actionsById).map(([actionId, action]) => {\n        // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n        // @ts-ignore\n        delete action.timestamp;\n        delete action.stack;\n        return [actionId, action];\n      }),\n    );\n    return state;\n  }\n\n  describe('Import Actions', () => {\n    let monitoredStore: EnhancedStore<number, CounterAction, null>;\n    let monitoredLiftedStore: LiftedStore<number, CounterAction, null>;\n    let exportedState: LiftedState<number, CounterAction, null>;\n    const savedActions = [\n      { type: 'INCREMENT' },\n      { type: 'INCREMENT' },\n      { type: 'INCREMENT' },\n    ] as const;\n\n    beforeEach(() => {\n      monitoredStore = createStore(counter, instrument());\n      monitoredLiftedStore = monitoredStore.liftedStore;\n      // Pass actions through component\n      savedActions.forEach((action) => monitoredStore.dispatch(action));\n      // get the final state\n      exportedState = filterStackAndTimestamps(monitoredLiftedStore.getState());\n    });\n\n    it('should replay all the steps when a state is imported', () => {\n      const importMonitoredStore = createStore(counter, instrument());\n      const importMonitoredLiftedStore = importMonitoredStore.liftedStore;\n\n      importMonitoredLiftedStore.dispatch(\n        ActionCreators.importState(savedActions),\n      );\n      expect(\n        filterStackAndTimestamps(importMonitoredLiftedStore.getState()),\n      ).toEqual(exportedState);\n    });\n\n    it('should replace the existing action log with the one imported', () => {\n      const importMonitoredStore = createStore(counter, instrument());\n      const importMonitoredLiftedStore = importMonitoredStore.liftedStore;\n\n      importMonitoredStore.dispatch({ type: 'DECREMENT' });\n      importMonitoredStore.dispatch({ type: 'DECREMENT' });\n\n      importMonitoredLiftedStore.dispatch(\n        ActionCreators.importState(savedActions),\n      );\n      expect(\n        filterStackAndTimestamps(importMonitoredLiftedStore.getState()),\n      ).toEqual(exportedState);\n    });\n\n    it('should include stack trace', () => {\n      const importMonitoredStore = createStore(\n        counter,\n        instrument(undefined, { trace: true }),\n      );\n      const importMonitoredLiftedStore = importMonitoredStore.liftedStore;\n\n      importMonitoredStore.dispatch({ type: 'DECREMENT' });\n      importMonitoredStore.dispatch({ type: 'DECREMENT' });\n\n      importMonitoredLiftedStore.dispatch(\n        ActionCreators.importState(savedActions),\n      );\n      expect(\n        importMonitoredLiftedStore.getState().actionsById[0].stack,\n      ).toBeUndefined();\n      expect(\n        typeof importMonitoredLiftedStore.getState().actionsById[1].stack,\n      ).toBe('string');\n      expect(\n        filterStackAndTimestamps(importMonitoredLiftedStore.getState()),\n      ).toEqual(exportedState);\n    });\n  });\n\n  describe('Lock Changes', () => {\n    it('should lock', () => {\n      store.dispatch({ type: 'INCREMENT' });\n      store.liftedStore.dispatch({ type: 'LOCK_CHANGES', status: true });\n      expect(store.liftedStore.getState().isLocked).toBe(true);\n      expect(store.liftedStore.getState().nextActionId).toBe(2);\n      expect(store.getState()).toBe(1);\n\n      store.dispatch({ type: 'INCREMENT' });\n      expect(store.liftedStore.getState().nextActionId).toBe(2);\n      expect(store.getState()).toBe(1);\n\n      liftedStore.dispatch(ActionCreators.toggleAction(1));\n      expect(store.getState()).toBe(0);\n      liftedStore.dispatch(ActionCreators.toggleAction(1));\n      expect(store.getState()).toBe(1);\n\n      store.liftedStore.dispatch({ type: 'LOCK_CHANGES', status: false });\n      expect(store.liftedStore.getState().isLocked).toBe(false);\n      expect(store.liftedStore.getState().nextActionId).toBe(2);\n\n      store.dispatch({ type: 'INCREMENT' });\n      expect(store.liftedStore.getState().nextActionId).toBe(3);\n      expect(store.getState()).toBe(2);\n    });\n    it('should start locked', () => {\n      store = createStore(\n        counter,\n        instrument(undefined, { shouldStartLocked: true }),\n      );\n      store.dispatch({ type: 'INCREMENT' });\n      expect(store.liftedStore.getState().isLocked).toBe(true);\n      expect(store.liftedStore.getState().nextActionId).toBe(1);\n      expect(store.getState()).toBe(0);\n\n      const savedActions = [\n        { type: 'INCREMENT' },\n        { type: 'INCREMENT' },\n      ] as const;\n      store.liftedStore.dispatch(\n        ActionCreators.importState<number, CounterAction, null>(savedActions),\n      );\n      expect(store.liftedStore.getState().nextActionId).toBe(3);\n      expect(store.getState()).toBe(2);\n\n      store.liftedStore.dispatch({ type: 'LOCK_CHANGES', status: false });\n      expect(store.liftedStore.getState().isLocked).toBe(false);\n\n      store.dispatch({ type: 'INCREMENT' });\n      expect(store.liftedStore.getState().nextActionId).toBe(4);\n      expect(store.getState()).toBe(3);\n    });\n  });\n\n  describe('Pause recording', () => {\n    it('should pause', () => {\n      expect(store.liftedStore.getState().isPaused).toBe(false);\n      store.dispatch({ type: 'INCREMENT' });\n      store.dispatch({ type: 'INCREMENT' });\n      expect(store.liftedStore.getState().nextActionId).toBe(3);\n      expect(store.getState()).toBe(2);\n\n      store.liftedStore.dispatch(ActionCreators.pauseRecording(true));\n      expect(store.liftedStore.getState().isPaused).toBe(true);\n      expect(store.liftedStore.getState().nextActionId).toBe(1);\n      expect(store.liftedStore.getState().actionsById[0].action).toEqual({\n        type: '@@INIT',\n      });\n      expect(store.getState()).toBe(2);\n\n      store.dispatch({ type: 'INCREMENT' });\n      store.dispatch({ type: 'INCREMENT' });\n      expect(store.liftedStore.getState().nextActionId).toBe(1);\n      expect(store.liftedStore.getState().actionsById[0].action).toEqual({\n        type: '@@INIT',\n      });\n      expect(store.getState()).toBe(4);\n\n      store.liftedStore.dispatch(ActionCreators.pauseRecording(false));\n      expect(store.liftedStore.getState().isPaused).toBe(false);\n\n      store.dispatch({ type: 'INCREMENT' });\n      store.dispatch({ type: 'INCREMENT' });\n      expect(store.liftedStore.getState().nextActionId).toBe(3);\n      expect(store.liftedStore.getState().actionsById[2].action).toEqual({\n        type: 'INCREMENT',\n      });\n      expect(store.getState()).toBe(6);\n    });\n    it('should maintain the history while paused', () => {\n      store = createStore(\n        counter,\n        instrument(undefined, { pauseActionType: '@@PAUSED' }),\n      );\n      store.dispatch({ type: 'INCREMENT' });\n      store.dispatch({ type: 'INCREMENT' });\n      expect(store.getState()).toBe(2);\n      expect(store.liftedStore.getState().nextActionId).toBe(3);\n      expect(store.liftedStore.getState().isPaused).toBe(false);\n\n      store.liftedStore.dispatch(ActionCreators.pauseRecording(true));\n      expect(store.liftedStore.getState().isPaused).toBe(true);\n      expect(store.liftedStore.getState().nextActionId).toBe(4);\n      expect(store.getState()).toBe(2);\n\n      store.dispatch({ type: 'INCREMENT' });\n      expect(store.liftedStore.getState().nextActionId).toBe(4);\n      store.dispatch({ type: 'INCREMENT' });\n      expect(store.liftedStore.getState().nextActionId).toBe(4);\n      expect(store.getState()).toBe(4);\n\n      store.liftedStore.dispatch(ActionCreators.pauseRecording(false));\n      expect(store.liftedStore.getState().isPaused).toBe(false);\n      expect(store.liftedStore.getState().nextActionId).toBe(1);\n      expect(store.getState()).toBe(4);\n      store.dispatch({ type: 'INCREMENT' });\n      expect(store.liftedStore.getState().nextActionId).toBe(2);\n      expect(store.getState()).toBe(5);\n\n      store.liftedStore.dispatch(ActionCreators.commit());\n      store.liftedStore.dispatch(ActionCreators.pauseRecording(true));\n      store.dispatch({ type: 'INCREMENT' });\n      expect(store.liftedStore.getState().nextActionId).toBe(1);\n      expect(store.getState()).toBe(6);\n    });\n  });\n\n  it('throws if reducer is not a function', () => {\n    expect(() =>\n      createStore(undefined as unknown as Reducer, instrument()),\n    ).toThrow(\n      \"Expected the root reducer to be a function. Instead, received: 'undefined'\",\n    );\n  });\n\n  it('warns if the reducer is not a function but has a default field that is', () => {\n    expect(() =>\n      createStore(\n        {\n          default: () => {\n            // noop\n          },\n        } as unknown as Reducer,\n        instrument(),\n      ),\n    ).toThrow(\n      \"Expected the root reducer to be a function. Instead, received: 'object'\",\n    );\n  });\n\n  it('throws if there are more than one instrument enhancer included', () => {\n    expect(() => {\n      createStore(\n        counter,\n        compose(instrument(), instrument()) as StoreEnhancer,\n      );\n    }).toThrow(\n      'DevTools instrumentation should not be applied more than once. ' +\n        'Check your store configuration.',\n    );\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-instrument/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\",\n    \"types\": [\"node\"]\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-instrument/tsconfig.test.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"jest\", \"node\"]\n  },\n  \"include\": [\"src\", \"test\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-log-monitor/CHANGELOG.md",
    "content": "# Change Log\n\n## 6.0.0\n\n### Major Changes\n\n- 12849a4: Convert monitors to ESM\n\n### Patch Changes\n\n- Updated dependencies [804d6bd]\n  - @redux-devtools/core@5.0.0\n\n## 5.1.1\n\n### Patch Changes\n\n- Updated dependencies [91f21b2]\n  - @redux-devtools/core@4.1.1\n\n## 5.1.0\n\n### Minor Changes\n\n- 6830118: Add React 19 to peer deps\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - react-json-tree@0.20.0\n  - @redux-devtools/core@4.1.0\n\n## 5.0.1\n\n### Patch Changes\n\n- Updated dependencies [bbb1a40]\n  - react-base16-styling@0.10.0\n  - react-json-tree@0.19.0\n\n## 5.0.0\n\n### Major Changes\n\n- 5cfe3e5: Update min required React version to 16.8.4\n\n### Patch Changes\n\n- Updated dependencies [decc035]\n  - @redux-devtools/core@4.0.0\n\n## 4.1.0\n\n### Minor Changes\n\n- 6fc18ed7: Add new Redux version to peer dependencies\n\n### Patch Changes\n\n- 7f5bddbd: Widen peer dependencies\n\n## 4.0.3\n\n### Patch Changes\n\n- 42531c50: Bump versions\n- Updated dependencies [42531c50]\n  - @redux-devtools/core@3.13.3\n\n## 4.0.2\n\n### Patch Changes\n\n- Updated dependencies [81926f32]\n  - react-json-tree@0.18.0\n\n## 4.0.1\n\n### Patch Changes\n\n- a55ba302: Fix peer dependencies on @redux-devtools/core\n- Updated dependencies [a55ba302]\n  - @redux-devtools/core@3.13.1\n\n## 4.0.0\n\n### Minor Changes\n\n- 8a7eae4: Add React 18 to peerDependencies range\n\n### Patch Changes\n\n- Updated dependencies [8a7eae4]\n  - react-json-tree@0.17.0\n  - @redux-devtools/core@3.13.0\n\n## 3.1.1\n\n### Patch Changes\n\n- Updated dependencies [4891bf6]\n  - @redux-devtools/core@3.12.0\n\n## 3.0.0\n\n- Adds ESM build (https://github.com/reduxjs/redux-devtools/pull/997) and switches the default export to a named export in order to ensure that the CommonJS output and the ESM output are [interchangeable](https://rollupjs.org/guide/en/#outputexports):\n\n```diff\n- import LogMonitor from '@redux-devtools/log-monitor';\n+ import { LogMonitor } from '@redux-devtools/log-monitor';\n```\n\n## [2.3.0](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/log-monitor@2.2.0...@redux-devtools/log-monitor@2.3.0) (2021-03-06)\n\n### Features\n\n- update peer dependencies to allow react@^17 ([#703](https://github.com/reduxjs/redux-devtools/issues/703)) ([2aaa9c1](https://github.com/reduxjs/redux-devtools/commit/2aaa9c10a383e3a7ab20b3ab14639781fd7bb2eb))\n\n## 2.2.0 (2021-03-06)\n\n### Bug Fixes\n\n- **cli:** resolve dependency issues ([#666](https://github.com/reduxjs/redux-devtools/issues/666)) ([e39e439](https://github.com/reduxjs/redux-devtools/commit/e39e43968b445ecbdcdab515050c5338cadabbe6))\n- **redux-devtools-log-monitor:** update react-json-tree dependency ([#533](https://github.com/reduxjs/redux-devtools/issues/533)) ([5f00930](https://github.com/reduxjs/redux-devtools/commit/5f00930eef78de97aa4a477d054801f93add6070))\n\n### Features\n\n- **d3-state-visualizer:** convert to TypeScript ([#640](https://github.com/reduxjs/redux-devtools/issues/640)) ([0c78a5a](https://github.com/reduxjs/redux-devtools/commit/0c78a5a9a76ee7eff37dcd8e39272d98c03e0869))\n- **redux-devtools:** convert counter example to TypeScript ([#616](https://github.com/reduxjs/redux-devtools/issues/616)) ([f1e3f4f](https://github.com/reduxjs/redux-devtools/commit/f1e3f4f8340dea288de5229006acf9dc1ef1cccf))\n- **redux-devtools-log-monitor:** convert to TypeScript ([#613](https://github.com/reduxjs/redux-devtools/issues/613)) ([2faa163](https://github.com/reduxjs/redux-devtools/commit/2faa16319b59ece946757af7630ca4ab1264f1f5))\n- **redux-devtools-serialize:** convert to TypeScript ([#621](https://github.com/reduxjs/redux-devtools/issues/621)) ([d586f19](https://github.com/reduxjs/redux-devtools/commit/d586f1955a3648883107f8c981ee17eeb4c013a3))\n- **redux-devtools-slider-monitor:** convert to TypeScript ([#631](https://github.com/reduxjs/redux-devtools/issues/631)) ([8991732](https://github.com/reduxjs/redux-devtools/commit/89917320e5ecf33dc3625b05daa1e9fe120a783d))\n\n## [2.1.0](https://github.com/reduxjs/redux-devtools/compare/redux-devtools-log-monitor@2.0.1...redux-devtools-log-monitor@2.1.0) (2020-09-07)\n\n### Features\n\n- **redux-devtools:** convert counter example to TypeScript ([#616](https://github.com/reduxjs/redux-devtools/issues/616)) ([f1e3f4f](https://github.com/reduxjs/redux-devtools/commit/f1e3f4f8340dea288de5229006acf9dc1ef1cccf))\n- **redux-devtools-log-monitor:** convert to TypeScript ([#613](https://github.com/reduxjs/redux-devtools/issues/613)) ([2faa163](https://github.com/reduxjs/redux-devtools/commit/2faa16319b59ece946757af7630ca4ab1264f1f5))\n- **redux-devtools-serialize:** convert to TypeScript ([#621](https://github.com/reduxjs/redux-devtools/issues/621)) ([d586f19](https://github.com/reduxjs/redux-devtools/commit/d586f1955a3648883107f8c981ee17eeb4c013a3))\n\n## [2.0.1](https://github.com/reduxjs/redux-devtools/compare/redux-devtools-log-monitor@2.0.0...redux-devtools-log-monitor@2.0.1) (2020-08-14)\n\n**Note:** Version bump only for package redux-devtools-log-monitor\n"
  },
  {
    "path": "packages/redux-devtools-log-monitor/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Dan Abramov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/redux-devtools-log-monitor/README.md",
    "content": "# Redux DevTools Log Monitor\n\nThe default monitor for [Redux DevTools](https://github.com/gaearon/redux-devtools) with a tree view.  \nIt shows a log of states and actions, and lets you change their history. Created by [Dan Abramov](http://github.com/gaearon) and merged into `redux-devtools` monorepo from [here](https://github.com/gaearon/redux-devtools-log-monitor).\n\n![](http://i.imgur.com/J4GeW0M.gif)\n\n### Installation\n\n```\nyarn add @redux-devtools/log-monitor\n```\n\n### Usage\n\nYou can use `LogMonitor` as the only monitor in your app:\n\n##### `containers/DevTools.js`\n\n```js\nimport React from 'react';\nimport { createDevTools } from '@redux-devtools/core';\nimport { LogMonitor } from '@redux-devtools/log-monitor';\n\nexport default createDevTools(<LogMonitor />);\n```\n\nThen you can render `<DevTools>` to any place inside app or even into a separate popup window.\n\nAlternative, you can use it together with [`DockMonitor`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-dock-monitor) to make it dockable.  \nConsult the [`DockMonitor` README](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-dock-monitor) for details of this approach.\n\n[Read how to start using Redux DevTools.](https://github.com/reduxjs/redux-devtools)\n\n### Features\n\nEvery action is displayed in the log. You can expand the tree view to inspect the `action` object and the `state` after it.\n\nIf a reducer throws while handling an action, you will see “Interrupted by an error up the chain” instead of the state and action tree view. Scroll up until you find the action which caused the error. You will see the error message in the action log entry. If you use a hot reloading tool, you can edit the reducer, and the error will automatically update or go away.\n\nClicking an action will disable it. It will appear crossed out, and the state will be recalculated as if the action never happened. Clicking it once again will enable it back. Use this together with a hot reloading solution to work sequentially on different states of your app without reproducing them by hand. You can toggle any action except for the initial one.\n\nThere are four buttons at the very top. “Reset” takes your app to the state you created the store with. The other three buttons work together. You might find it useful to think of them like you think of Git commits. “Commit” removes all actions in your log, and makes the current state your initial state. This is useful when you start working on a feature and want to remove the previous noise. After you’ve dispatched a few actions, you can press “Revert” to go back to the last committed state. Finally, if you dispatched some actions by mistake and you don’t want them around, you can toggle them by clicking on them, and press “Sweep” to completely remove all currently disabled actions from the log.\n\n### Props\n\n| Name                | Description                                                                                                                                                                                                                                                                                                                         |\n| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `theme`             | Either a string referring to one of the themes provided by [redux-devtools-themes](https://github.com/gaearon/redux-devtools-themes) (feel free to contribute!) or a custom object of the same format. Optional. By default, set to [`'nicinabox'`](https://github.com/gaearon/redux-devtools-themes/blob/master/src/nicinabox.js). |\n| `select`            | A function that selects the slice of the state for DevTools to show. For example, `state => state.thePart.iCare.about`. Optional. By default, set to `state => state`.                                                                                                                                                              |\n| `preserveScrollTop` | When `true`, records the current scroll top every second so it can be restored on refresh. This only has effect when used together with `persistState()` enhancer from Redux DevTools. By default, set to `true`.                                                                                                                   |\n| `expandActionRoot`  | When `true`, displays the action object expanded rather than collapsed. By default, set to `true`.                                                                                                                                                                                                                                  |\n| `expandStateRoot`   | When `true`, displays the state object expanded rather than collapsed. By default, set to `true`.                                                                                                                                                                                                                                   |\n| `markStateDiff`     | When `true`, mark the state's values which were changed comparing to the previous state. It affects the performance significantly! You might also want to set `expandStateRoot` to `true` as well when enabling it. By default, set to `false`.                                                                                     |\n| `hideMainButtons`   | When `true`, will show only the logs without the top button bar. By default, set to `false`.                                                                                                                                                                                                                                        |\n\n### License\n\nMIT\n"
  },
  {
    "path": "packages/redux-devtools-log-monitor/eslint.config.mjs",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTsReact from '../../eslint.ts.react.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTsReact(import.meta.dirname),\n  {\n    ignores: ['lib'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-log-monitor/package.json",
    "content": "{\n  \"name\": \"@redux-devtools/log-monitor\",\n  \"version\": \"6.0.0\",\n  \"description\": \"The default tree view monitor for Redux DevTools\",\n  \"keywords\": [\n    \"redux\",\n    \"devtools\",\n    \"flux\",\n    \"react\",\n    \"hot reloading\",\n    \"time travel\",\n    \"live edit\"\n  ],\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-log-monitor\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Dan Abramov <dan.abramov@me.com> (http://github.com/gaearon)\",\n  \"files\": [\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": \"./lib/index.js\",\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run type-check && pnpm run lint\"\n  },\n  \"dependencies\": {\n    \"@types/lodash.debounce\": \"^4.0.9\",\n    \"lodash.debounce\": \"^4.0.8\",\n    \"react-base16-styling\": \"workspace:^\",\n    \"react-json-tree\": \"workspace:^\"\n  },\n  \"devDependencies\": {\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@types/react\": \"^19.2.14\",\n    \"react\": \"^19.2.4\",\n    \"redux\": \"^5.0.1\",\n    \"rimraf\": \"^6.1.3\",\n    \"typescript\": \"~5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@types/react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react\": \"^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"redux\": \"^3.4.0 || ^4.0.0 || ^5.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-log-monitor/src/LogMonitor.tsx",
    "content": "import React, { PureComponent } from 'react';\nimport { Action, Dispatch } from 'redux';\nimport { base16Themes } from 'react-base16-styling';\nimport type { Base16Theme } from 'react-base16-styling';\nimport {\n  ActionCreators,\n  LiftedAction,\n  LiftedState,\n} from '@redux-devtools/core';\nimport debounce from 'lodash.debounce';\nimport {\n  updateScrollTop,\n  startConsecutiveToggle,\n  LogMonitorAction,\n} from './actions.js';\nimport reducer, { LogMonitorState } from './reducers.js';\nimport LogMonitorButtonBar from './LogMonitorButtonBar.js';\nimport LogMonitorEntryList from './LogMonitorEntryList.js';\n\nconst { toggleAction, setActionsActive } = ActionCreators;\n\nconst styles: {\n  container: React.CSSProperties;\n  elements: React.CSSProperties;\n} = {\n  container: {\n    fontFamily: 'monaco, Consolas, Lucida Console, monospace',\n    position: 'relative',\n    overflowY: 'hidden',\n    width: '100%',\n    height: '100%',\n    minWidth: 300,\n    direction: 'ltr',\n  },\n  elements: {\n    position: 'absolute',\n    left: 0,\n    right: 0,\n    top: 0,\n    bottom: 0,\n    overflowX: 'hidden',\n    overflowY: 'auto',\n  },\n};\n\ninterface ExternalProps<S, A extends Action<string>> {\n  dispatch: Dispatch<LogMonitorAction | LiftedAction<S, A, LogMonitorState>>;\n\n  preserveScrollTop: boolean;\n  select: (state: S) => unknown;\n  theme: keyof typeof base16Themes | Base16Theme;\n  expandActionRoot: boolean;\n  expandStateRoot: boolean;\n  markStateDiff: boolean;\n  hideMainButtons?: boolean;\n}\n\ninterface DefaultProps<S> {\n  select: (state: unknown) => unknown;\n  theme: keyof typeof base16Themes | Base16Theme;\n  preserveScrollTop: boolean;\n  expandActionRoot: boolean;\n  expandStateRoot: boolean;\n  markStateDiff: boolean;\n}\n\nexport interface LogMonitorProps<\n  S,\n  A extends Action<string>,\n> extends LiftedState<S, A, LogMonitorState> {\n  dispatch: Dispatch<LogMonitorAction | LiftedAction<S, A, LogMonitorState>>;\n\n  preserveScrollTop: boolean;\n  select: (state: S) => unknown;\n  theme: keyof typeof base16Themes | Base16Theme;\n  expandActionRoot: boolean;\n  expandStateRoot: boolean;\n  markStateDiff: boolean;\n  hideMainButtons?: boolean;\n}\n\nclass LogMonitor<S, A extends Action<string>> extends PureComponent<\n  LogMonitorProps<S, A>\n> {\n  static update = reducer;\n\n  static defaultProps: DefaultProps<unknown> = {\n    select: (state: unknown) => state,\n    theme: 'nicinabox',\n    preserveScrollTop: true,\n    expandActionRoot: true,\n    expandStateRoot: true,\n    markStateDiff: false,\n  };\n\n  scrollDown?: boolean;\n  node?: HTMLDivElement | null;\n\n  updateScrollTop = debounce(() => {\n    const node = this.node;\n    this.props.dispatch(updateScrollTop(node ? node.scrollTop : 0));\n  }, 500);\n\n  scroll() {\n    const node = this.node;\n    if (!node) {\n      return;\n    }\n    if (this.scrollDown) {\n      const { offsetHeight, scrollHeight } = node;\n      node.scrollTop = scrollHeight - offsetHeight;\n      this.scrollDown = false;\n    }\n  }\n\n  componentDidMount() {\n    const node = this.node;\n    if (!node || !this.props.monitorState) {\n      return;\n    }\n\n    if (this.props.preserveScrollTop) {\n      node.scrollTop = this.props.monitorState.initialScrollTop;\n      node.addEventListener('scroll', this.updateScrollTop);\n    } else {\n      this.scrollDown = true;\n      this.scroll();\n    }\n  }\n\n  componentWillUnmount() {\n    const node = this.node;\n    if (node && this.props.preserveScrollTop) {\n      node.removeEventListener('scroll', this.updateScrollTop);\n    }\n  }\n\n  UNSAFE_componentWillReceiveProps(nextProps: LogMonitorProps<S, A>) {\n    const node = this.node;\n    if (!node) {\n      this.scrollDown = true;\n    } else if (\n      this.props.stagedActionIds.length < nextProps.stagedActionIds.length\n    ) {\n      const { scrollTop, offsetHeight, scrollHeight } = node;\n\n      this.scrollDown =\n        Math.abs(scrollHeight - (scrollTop + offsetHeight)) < 20;\n    } else {\n      this.scrollDown = false;\n    }\n  }\n\n  componentDidUpdate() {\n    this.scroll();\n  }\n\n  handleToggleAction = (id: number) => {\n    this.props.dispatch(toggleAction(id));\n  };\n\n  handleToggleConsecutiveAction = (id: number) => {\n    const { monitorState, actionsById } = this.props;\n    const { consecutiveToggleStartId } = monitorState;\n    if (consecutiveToggleStartId && actionsById[consecutiveToggleStartId]) {\n      const { skippedActionIds } = this.props;\n      const start = Math.min(consecutiveToggleStartId, id);\n      const end = Math.max(consecutiveToggleStartId, id);\n      const active = skippedActionIds.includes(consecutiveToggleStartId);\n      this.props.dispatch(setActionsActive(start, end + 1, active));\n      this.props.dispatch(startConsecutiveToggle(null));\n    } else if (id > 0) {\n      this.props.dispatch(startConsecutiveToggle(id));\n    }\n  };\n\n  getTheme() {\n    const { theme } = this.props;\n    if (typeof theme !== 'string') {\n      return theme;\n    }\n\n    if (typeof base16Themes[theme] !== 'undefined') {\n      return base16Themes[theme];\n    }\n\n    // eslint-disable-next-line no-console\n    console.warn(\n      'DevTools theme ' + theme + ' not found, defaulting to nicinabox',\n    );\n    return base16Themes.nicinabox;\n  }\n\n  getRef: React.RefCallback<HTMLDivElement> = (node) => {\n    this.node = node;\n  };\n\n  render() {\n    const theme = this.getTheme();\n    const { consecutiveToggleStartId } = this.props.monitorState;\n\n    const {\n      dispatch,\n      actionsById,\n      skippedActionIds,\n      stagedActionIds,\n      computedStates,\n      currentStateIndex,\n      select,\n      expandActionRoot,\n      expandStateRoot,\n      markStateDiff,\n    } = this.props;\n\n    const entryListProps = {\n      theme,\n      actionsById,\n      skippedActionIds,\n      stagedActionIds,\n      computedStates,\n      currentStateIndex,\n      consecutiveToggleStartId,\n      select,\n      expandActionRoot,\n      expandStateRoot,\n      markStateDiff,\n      onActionClick: this.handleToggleAction,\n      onActionShiftClick: this.handleToggleConsecutiveAction,\n    };\n\n    return (\n      <div style={{ ...styles.container, backgroundColor: theme.base00 }}>\n        {!this.props.hideMainButtons && (\n          <LogMonitorButtonBar\n            theme={theme}\n            dispatch={dispatch}\n            hasStates={computedStates.length > 1}\n            hasSkippedActions={skippedActionIds.length > 0}\n          />\n        )}\n        <div\n          style={\n            this.props.hideMainButtons\n              ? styles.elements\n              : { ...styles.elements, top: 30 }\n          }\n          ref={this.getRef}\n        >\n          <LogMonitorEntryList {...entryListProps} />\n        </div>\n      </div>\n    );\n  }\n}\n\nexport default LogMonitor as unknown as React.ComponentType<\n  ExternalProps<unknown, Action<string>>\n> & {\n  update(\n    monitorProps: ExternalProps<unknown, Action<string>>,\n    state: LogMonitorState | undefined,\n    action: LogMonitorAction,\n  ): LogMonitorState;\n  defaultProps: DefaultProps<unknown>;\n};\n"
  },
  {
    "path": "packages/redux-devtools-log-monitor/src/LogMonitorButton.tsx",
    "content": "import React, { CSSProperties, ReactNode } from 'react';\nimport type { Base16Theme } from 'react-base16-styling';\nimport brighten from './brighten.js';\n\nconst styles: { base: CSSProperties } = {\n  base: {\n    cursor: 'pointer',\n    fontWeight: 'bold',\n    borderRadius: 3,\n    padding: 4,\n    marginLeft: 3,\n    marginRight: 3,\n    marginTop: 5,\n    marginBottom: 5,\n    flexGrow: 1,\n    display: 'inline-block',\n    fontSize: '0.8em',\n    color: 'white',\n    textDecoration: 'none',\n  },\n};\n\ninterface State {\n  hovered: boolean;\n  active: boolean;\n}\n\ninterface Props {\n  theme: Base16Theme;\n  onClick: () => void;\n  enabled: boolean;\n  children?: ReactNode;\n}\n\nexport default class LogMonitorButton extends React.PureComponent<\n  Props,\n  State\n> {\n  state: State = {\n    hovered: false,\n    active: false,\n  };\n\n  handleMouseEnter = () => {\n    this.setState({ hovered: true });\n  };\n\n  handleMouseLeave = () => {\n    this.setState({ hovered: false });\n  };\n\n  handleMouseDown = () => {\n    this.setState({ active: true });\n  };\n\n  handleMouseUp = () => {\n    this.setState({ active: false });\n  };\n\n  onClick = () => {\n    if (!this.props.enabled) {\n      return;\n    }\n    if (this.props.onClick) {\n      this.props.onClick();\n    }\n  };\n\n  render() {\n    let style = {\n      ...styles.base,\n      backgroundColor: this.props.theme.base02,\n    };\n    if (this.props.enabled && this.state.hovered) {\n      style = {\n        ...style,\n        backgroundColor: brighten(this.props.theme.base02, 0.2),\n      };\n    }\n    if (!this.props.enabled) {\n      style = {\n        ...style,\n        opacity: 0.2,\n        cursor: 'text',\n        backgroundColor: 'transparent',\n      };\n    }\n    return (\n      <a\n        onMouseEnter={this.handleMouseEnter}\n        onMouseLeave={this.handleMouseLeave}\n        onMouseDown={this.handleMouseDown}\n        onMouseUp={this.handleMouseUp}\n        onClick={this.onClick}\n        style={style}\n      >\n        {this.props.children}\n      </a>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-log-monitor/src/LogMonitorButtonBar.tsx",
    "content": "import React, { CSSProperties, PureComponent } from 'react';\nimport { ActionCreators, LiftedAction } from '@redux-devtools/core';\nimport type { Base16Theme } from 'react-base16-styling';\nimport { Action, Dispatch } from 'redux';\nimport LogMonitorButton from './LogMonitorButton.js';\nimport { LogMonitorAction } from './actions.js';\nimport { LogMonitorState } from './reducers.js';\n\nconst { reset, rollback, commit, sweep } = ActionCreators;\n\nconst style: CSSProperties = {\n  textAlign: 'center',\n  borderBottomWidth: 1,\n  borderBottomStyle: 'solid',\n  borderColor: 'transparent',\n  zIndex: 1,\n  display: 'flex',\n  flexDirection: 'row',\n};\n\ninterface Props<S, A extends Action<string>> {\n  theme: Base16Theme;\n  dispatch: Dispatch<LogMonitorAction | LiftedAction<S, A, LogMonitorState>>;\n  hasStates: boolean;\n  hasSkippedActions: boolean;\n}\n\nexport default class LogMonitorButtonBar<\n  S,\n  A extends Action<string>,\n> extends PureComponent<Props<S, A>> {\n  handleRollback = () => {\n    this.props.dispatch(rollback());\n  };\n\n  handleSweep = () => {\n    this.props.dispatch(sweep());\n  };\n\n  handleCommit = () => {\n    this.props.dispatch(commit());\n  };\n\n  handleReset = () => {\n    this.props.dispatch(reset());\n  };\n\n  render() {\n    const { theme, hasStates, hasSkippedActions } = this.props;\n    return (\n      <div style={{ ...style, borderColor: theme.base02 }}>\n        <LogMonitorButton theme={theme} onClick={this.handleReset} enabled>\n          Reset\n        </LogMonitorButton>\n        <LogMonitorButton\n          theme={theme}\n          onClick={this.handleRollback}\n          enabled={hasStates}\n        >\n          Revert\n        </LogMonitorButton>\n        <LogMonitorButton\n          theme={theme}\n          onClick={this.handleSweep}\n          enabled={hasSkippedActions}\n        >\n          Sweep\n        </LogMonitorButton>\n        <LogMonitorButton\n          theme={theme}\n          onClick={this.handleCommit}\n          enabled={hasStates}\n        >\n          Commit\n        </LogMonitorButton>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-log-monitor/src/LogMonitorEntry.tsx",
    "content": "import React, { CSSProperties, MouseEventHandler, PureComponent } from 'react';\nimport { JSONTree } from 'react-json-tree';\nimport type { ShouldExpandNodeInitially, StylingValue } from 'react-json-tree';\nimport type { Base16Theme } from 'react-base16-styling';\nimport { Action } from 'redux';\nimport LogMonitorEntryAction from './LogMonitorEntryAction.js';\n\nconst styles: { entry: CSSProperties; root: CSSProperties } = {\n  entry: {\n    display: 'block',\n    WebkitUserSelect: 'none',\n  },\n\n  root: {\n    marginLeft: 0,\n  },\n};\n\nconst getDeepItem = (data: any, path: (string | number)[]) =>\n  path.reduce((obj, key) => obj && obj[key], data);\nconst dataIsEqual = (\n  data: any,\n  previousData: unknown,\n  keyPath: (string | number)[],\n) => {\n  const path = [...keyPath].reverse().slice(1);\n\n  return getDeepItem(data, path) === getDeepItem(previousData, path);\n};\n\ninterface Props<S, A extends Action<string>> {\n  theme: Base16Theme;\n  select: (state: any) => unknown;\n  action: A;\n  actionId: number;\n  state: S;\n  previousState: S | undefined;\n  collapsed: boolean;\n  inFuture: boolean;\n  selected: boolean;\n  error: string | undefined;\n  expandActionRoot: boolean;\n  expandStateRoot: boolean;\n  markStateDiff: boolean;\n  onActionClick: (id: number) => void;\n  onActionShiftClick: (id: number) => void;\n}\n\nexport default class LogMonitorEntry<\n  S,\n  A extends Action<string>,\n> extends PureComponent<Props<S, A>> {\n  printState(state: S, error: string | undefined) {\n    let errorText = error;\n    if (!errorText) {\n      try {\n        const data = this.props.select(state);\n        let theme;\n\n        if (this.props.markStateDiff) {\n          const previousData =\n            typeof this.props.previousState !== 'undefined'\n              ? this.props.select(this.props.previousState)\n              : undefined;\n          const getValueStyle: StylingValue = (\n            { style },\n            nodeType,\n            keyPath,\n          ) => ({\n            style: {\n              ...style,\n              backgroundColor: dataIsEqual(\n                data,\n                previousData,\n                keyPath as (string | number)[],\n              )\n                ? 'transparent'\n                : this.props.theme.base01,\n            },\n          });\n          const getNestedNodeStyle: StylingValue = ({ style }, keyPath) => ({\n            style: {\n              ...style,\n              ...((keyPath as unknown[]).length > 1 ? {} : styles.root),\n            },\n          });\n          theme = {\n            extend: this.props.theme,\n            value: getValueStyle,\n            nestedNode: getNestedNodeStyle,\n          };\n        } else {\n          theme = this.props.theme;\n        }\n\n        return (\n          <JSONTree\n            theme={theme}\n            data={data}\n            invertTheme={false}\n            keyPath={['state']}\n            shouldExpandNodeInitially={this.shouldExpandNodeInitially}\n          />\n        );\n      } catch (err) {\n        errorText = 'Error selecting state.';\n      }\n    }\n\n    return (\n      <div\n        style={{\n          color: this.props.theme.base08,\n          paddingTop: 20,\n          paddingLeft: 30,\n          paddingRight: 30,\n          paddingBottom: 35,\n        }}\n      >\n        {errorText}\n      </div>\n    );\n  }\n\n  handleActionClick: MouseEventHandler<HTMLDivElement> = (e) => {\n    const { actionId, onActionClick, onActionShiftClick } = this.props;\n    if (actionId > 0) {\n      if (e.shiftKey) {\n        onActionShiftClick(actionId);\n      } else {\n        onActionClick(actionId);\n      }\n    }\n  };\n\n  shouldExpandNodeInitially: ShouldExpandNodeInitially = (\n    keyPath,\n    data,\n    level,\n  ) => {\n    return this.props.expandStateRoot && level === 0;\n  };\n\n  render() {\n    const { actionId, error, action, state, collapsed, selected, inFuture } =\n      this.props;\n    const styleEntry = {\n      opacity: collapsed ? 0.5 : 1,\n      cursor: actionId > 0 ? 'pointer' : 'default',\n    };\n\n    return (\n      <div\n        style={{\n          opacity: selected ? 0.4 : inFuture ? 0.6 : 1, // eslint-disable-line no-nested-ternary\n          textDecoration: collapsed ? 'line-through' : 'none',\n          color: this.props.theme.base06,\n        }}\n      >\n        <LogMonitorEntryAction\n          theme={this.props.theme}\n          collapsed={collapsed}\n          action={action}\n          expandActionRoot={this.props.expandActionRoot}\n          onClick={this.handleActionClick}\n          style={{ ...styles.entry, ...styleEntry }}\n        />\n        {!collapsed && (\n          <div style={{ paddingLeft: 16 }}>{this.printState(state, error)}</div>\n        )}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-log-monitor/src/LogMonitorEntryAction.tsx",
    "content": "import React, { Component, CSSProperties, MouseEventHandler } from 'react';\nimport { JSONTree } from 'react-json-tree';\nimport type { ShouldExpandNodeInitially } from 'react-json-tree';\nimport type { Base16Theme } from 'react-base16-styling';\nimport { Action } from 'redux';\n\nconst styles = {\n  actionBar: {\n    paddingTop: 8,\n    paddingBottom: 7,\n    paddingLeft: 16,\n  },\n  payload: {\n    margin: 0,\n    paddingLeft: 16,\n    overflow: 'auto',\n  },\n};\n\ninterface Props<A extends Action<string>> {\n  theme: Base16Theme;\n  collapsed: boolean;\n  action: A;\n  expandActionRoot: boolean;\n  onClick: MouseEventHandler<HTMLDivElement>;\n  style: CSSProperties;\n}\n\nexport default class LogMonitorAction<\n  A extends Action<string>,\n> extends Component<Props<A>> {\n  renderPayload(payload: Record<string, unknown>) {\n    return (\n      <div\n        style={{\n          ...styles.payload,\n          backgroundColor: this.props.theme.base00,\n        }}\n      >\n        {Object.keys(payload).length > 0 ? (\n          <JSONTree\n            theme={this.props.theme}\n            invertTheme={false}\n            keyPath={['action']}\n            data={payload}\n            shouldExpandNodeInitially={this.shouldExpandNodeInitially}\n          />\n        ) : (\n          ''\n        )}\n      </div>\n    );\n  }\n\n  shouldExpandNodeInitially: ShouldExpandNodeInitially = (\n    keyPath,\n    data,\n    level,\n  ) => {\n    return this.props.expandActionRoot && level === 0;\n  };\n\n  render() {\n    const { type, ...payload } = this.props.action;\n    return (\n      <div\n        style={{\n          backgroundColor: this.props.theme.base02,\n          color: this.props.theme.base06,\n          ...this.props.style,\n        }}\n      >\n        <div style={styles.actionBar} onClick={this.props.onClick}>\n          {type !== null && type.toString()}\n        </div>\n        {!this.props.collapsed ? this.renderPayload(payload) : ''}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-log-monitor/src/LogMonitorEntryList.tsx",
    "content": "import React, { PureComponent } from 'react';\nimport { Action } from 'redux';\nimport { PerformAction } from '@redux-devtools/core';\nimport type { Base16Theme } from 'react-base16-styling';\nimport LogMonitorEntry from './LogMonitorEntry.js';\n\ninterface Props<S, A extends Action<string>> {\n  actionsById: { [actionId: number]: PerformAction<A> };\n  computedStates: { state: S; error?: string }[];\n  stagedActionIds: number[];\n  skippedActionIds: number[];\n  currentStateIndex: number;\n  consecutiveToggleStartId: number | null | undefined;\n\n  select: (state: S) => unknown;\n  onActionClick: (id: number) => void;\n  theme: Base16Theme;\n  expandActionRoot: boolean;\n  expandStateRoot: boolean;\n  markStateDiff: boolean;\n  onActionShiftClick: (id: number) => void;\n}\n\nexport default class LogMonitorEntryList<\n  S,\n  A extends Action<string>,\n> extends PureComponent<Props<S, A>> {\n  render() {\n    const elements = [];\n    const {\n      theme,\n      actionsById,\n      computedStates,\n      currentStateIndex,\n      consecutiveToggleStartId,\n      select,\n      skippedActionIds,\n      stagedActionIds,\n      expandActionRoot,\n      expandStateRoot,\n      markStateDiff,\n      onActionClick,\n      onActionShiftClick,\n    } = this.props;\n\n    for (let i = 0; i < stagedActionIds.length; i++) {\n      const actionId = stagedActionIds[i];\n      const action = actionsById[actionId].action;\n      const { state, error } = computedStates[i];\n      let previousState;\n      if (i > 0) {\n        previousState = computedStates[i - 1].state;\n      }\n      elements.push(\n        <LogMonitorEntry\n          key={actionId}\n          theme={theme}\n          select={select}\n          action={action}\n          actionId={actionId}\n          state={state}\n          previousState={previousState}\n          collapsed={skippedActionIds.includes(actionId)}\n          inFuture={i > currentStateIndex}\n          selected={consecutiveToggleStartId === i}\n          error={error}\n          expandActionRoot={expandActionRoot}\n          expandStateRoot={expandStateRoot}\n          markStateDiff={markStateDiff}\n          onActionClick={onActionClick}\n          onActionShiftClick={onActionShiftClick}\n        />,\n      );\n    }\n\n    return <div>{elements}</div>;\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-log-monitor/src/actions.ts",
    "content": "export const UPDATE_SCROLL_TOP =\n  '@@redux-devtools-log-monitor/UPDATE_SCROLL_TOP';\ninterface UpdateScrollTopAction {\n  type: typeof UPDATE_SCROLL_TOP;\n  scrollTop: number;\n}\nexport function updateScrollTop(scrollTop: number): UpdateScrollTopAction {\n  return { type: UPDATE_SCROLL_TOP, scrollTop };\n}\n\nexport const START_CONSECUTIVE_TOGGLE =\n  '@@redux-devtools-log-monitor/START_CONSECUTIVE_TOGGLE';\ninterface StartConsecutiveToggleAction {\n  type: typeof START_CONSECUTIVE_TOGGLE;\n  id: number | null;\n}\nexport function startConsecutiveToggle(\n  id: number | null,\n): StartConsecutiveToggleAction {\n  return { type: START_CONSECUTIVE_TOGGLE, id };\n}\n\nexport type LogMonitorAction =\n  | UpdateScrollTopAction\n  | StartConsecutiveToggleAction;\n"
  },
  {
    "path": "packages/redux-devtools-log-monitor/src/brighten.ts",
    "content": "export default function (hexColor: string, lightness: number) {\n  let hex = String(hexColor).replace(/[^0-9a-f]/gi, '');\n  if (hex.length < 6) {\n    hex = hex.replace(/(.)/g, '$1$1');\n  }\n  const lum = lightness || 0;\n\n  let rgb = '#';\n  let c;\n  for (let i = 0; i < 3; ++i) {\n    c = parseInt(hex.substr(i * 2, 2), 16);\n    c = Math.round(Math.min(Math.max(0, c + c * lum), 255)).toString(16);\n    rgb += ('00' + c).substr(c.length);\n  }\n  return rgb;\n}\n"
  },
  {
    "path": "packages/redux-devtools-log-monitor/src/index.ts",
    "content": "export { default as LogMonitor } from './LogMonitor.js';\n"
  },
  {
    "path": "packages/redux-devtools-log-monitor/src/reducers.ts",
    "content": "import { Action } from 'redux';\nimport {\n  UPDATE_SCROLL_TOP,\n  START_CONSECUTIVE_TOGGLE,\n  LogMonitorAction,\n} from './actions.js';\nimport { LogMonitorProps } from './LogMonitor.js';\n\nfunction initialScrollTop<S, A extends Action<string>>(\n  props: LogMonitorProps<S, A>,\n  state = 0,\n  action: LogMonitorAction,\n) {\n  if (!props.preserveScrollTop) {\n    return 0;\n  }\n\n  return action.type === UPDATE_SCROLL_TOP ? action.scrollTop : state;\n}\n\nfunction startConsecutiveToggle<S, A extends Action<string>>(\n  props: LogMonitorProps<S, A>,\n  state: number | null | undefined,\n  action: LogMonitorAction,\n) {\n  return action.type === START_CONSECUTIVE_TOGGLE ? action.id : state;\n}\n\nexport interface LogMonitorState {\n  initialScrollTop: number;\n  consecutiveToggleStartId: number | null | undefined;\n}\n\nexport default function reducer<S, A extends Action<string>>(\n  props: LogMonitorProps<S, A>,\n  state: Partial<LogMonitorState> = {},\n  action: LogMonitorAction,\n): LogMonitorState {\n  return {\n    initialScrollTop: initialScrollTop(props, state.initialScrollTop, action),\n    consecutiveToggleStartId: startConsecutiveToggle(\n      props,\n      state.consecutiveToggleStartId,\n      action,\n    ),\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-log-monitor/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-remote/CHANGELOG.md",
    "content": "# Change Log\n\n## 1.0.0\n\n### Major Changes\n\n- 6481386: Convert remaining packages to ESM\n\n### Patch Changes\n\n- Updated dependencies [3f90241]\n- Updated dependencies [6481386]\n  - @redux-devtools/instrument@3.0.0\n  - @redux-devtools/utils@4.0.0\n\n## 0.9.5\n\n### Patch Changes\n\n- @redux-devtools/utils@3.1.1\n\n## 0.9.4\n\n### Patch Changes\n\n- @redux-devtools/utils@4.0.0\n\n## 0.9.3\n\n### Patch Changes\n\n- f387854: Revert \"Add polyfill for Symbol.asyncIterator (#1642)\"\n\n## 0.9.2\n\n### Patch Changes\n\n- 138f4f3: Fix Hermes support by adding polyfill for Symbol.asyncIterator\n\n## 0.9.1\n\n### Patch Changes\n\n- @redux-devtools/utils@3.0.0\n\n## 0.9.0\n\n### Minor Changes\n\n- 6fc18ed7: Add new Redux version to peer dependencies\n\n### Patch Changes\n\n- Updated dependencies [7f5bddbd]\n- Updated dependencies [6fc18ed7]\n  - @redux-devtools/utils@2.1.0\n  - @redux-devtools/instrument@2.2.0\n\n## 0.8.2\n\n### Patch Changes\n\n- 42531c50: Bump versions\n- Updated dependencies [42531c50]\n  - @redux-devtools/instrument@2.1.1\n  - @redux-devtools/utils@2.0.2\n\n## 0.8.1\n\n### Patch Changes\n\n- 7e6d0438: Transform `for await...of` syntax for @redux-devtools/remote to support Hermes Engine\n\n## 0.8.0\n\n### Minor Changes\n\n- 421ea476: Upgrade SocketCluster (#1167)\n\n## 0.7.5\n\n### Patch Changes\n\n- @redux-devtools/utils@2.0.0\n\n## 0.7.4\n\n### Patch Changes\n\n- @redux-devtools/utils@1.2.1\n\n## 0.7.0\n\n- Adds ESM build (https://github.com/reduxjs/redux-devtools/pull/997) and switches the default export to a named export in order to ensure that the CommonJS output and the ESM output are [interchangeable](https://rollupjs.org/guide/en/#outputexports):\n\n```diff\n- import devToolsEnhancer from '@redux-devtools/remote';\n+ import { devToolsEnhancer } from '@redux-devtools/remote';\n```\n"
  },
  {
    "path": "packages/redux-devtools-remote/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Mihail Diordiev\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/redux-devtools-remote/README.md",
    "content": "# Remote Redux DevTools\n\n![Demo](demo.gif)\n\nUse [Redux DevTools](https://github.com/reduxjs/redux-devtools) remotely for React Native, hybrid, desktop and server side Redux apps.\n\n### Installation\n\n```\nyarn add @redux-devtools/remote\n```\n\n### Usage\n\nThere are 2 ways of usage depending if you're using other store enhancers (middlewares) or not.\n\n#### Add DevTools enhancer to your store\n\nIf you have a basic [store](http://redux.js.org/docs/api/createStore.html) as described in the official [redux-docs](http://redux.js.org/index.html), simply replace:\n\n```javascript\nimport { createStore } from 'redux';\nconst store = createStore(reducer);\n```\n\nwith\n\n```javascript\nimport { createStore } from 'redux';\nimport { devToolsEnhancer } from '@redux-devtools/remote';\nconst store = createStore(reducer, devToolsEnhancer());\n// or const store = createStore(reducer, preloadedState, devToolsEnhancer());\n```\n\n> Note: passing enhancer as last argument requires redux@>=3.1.0\n\n#### When to use DevTools compose helper\n\nIf you setup your store with [middlewares and enhancers](http://redux.js.org/docs/api/applyMiddleware.html) like [redux-saga](https://github.com/redux-saga/redux-saga) and similar, it is crucial to use `composeWithDevTools` export. Otherwise, actions dispatched from Redux DevTools will not flow to your middlewares.\n\nIn that case change this:\n\n```javascript\nimport { createStore, applyMiddleware, compose } from 'redux';\n\nconst store = createStore(\n  reducer,\n  preloadedState,\n  compose(\n    applyMiddleware(...middleware),\n    // other store enhancers if any\n  ),\n);\n```\n\nto:\n\n```javascript\nimport { createStore, applyMiddleware } from 'redux';\nimport { composeWithDevTools } from '@redux-devtools/remote';\n\nconst store = createStore(\n  reducer,\n  /* preloadedState, */ composeWithDevTools(\n    applyMiddleware(...middleware),\n    // other store enhancers if any\n  ),\n);\n```\n\nor with devTools' options:\n\n```javascript\nimport { createStore, applyMiddleware } from 'redux';\nimport { composeWithDevTools } from '@redux-devtools/remote';\n\nconst composeEnhancers = composeWithDevTools({ realtime: true, port: 8000 });\nconst store = createStore(\n  reducer,\n  /* preloadedState, */ composeEnhancers(\n    applyMiddleware(...middleware),\n    // other store enhancers if any\n  ),\n);\n```\n\n### Enabling\n\nIn order not to allow it in production by default, the enhancer will have effect only when `process.env.NODE_ENV === 'development'`.\n\nFor Webpack you should add it as following (`webpack.config.dev.js`):\n\n```js\n// ...\nplugins: [\n  new webpack.DefinePlugin({\n    'process.env.NODE_ENV': JSON.stringify('development')\n  })\n],\n// ...\n```\n\nIn case you don't set `NODE_ENV`, you can set `realtime` parameter to `true` or to other global variable to turn it off in production:\n\n```js\nconst store = createStore(reducer, devToolsEnhancer({ realtime: true }));\n```\n\n### Monitoring\n\nUse one of our monitor apps to inspect and dispatch actions:\n\n- [redux-devtools-extension](https://github.com/reduxjs/redux-devtools/tree/main/extension) - Click \"Remote\" button (or press [`Cmd+Ctrl+Arrow up`](https://github.com/zalmoxisus/redux-devtools-extension#keyboard-shortcuts)) to open remote monitoring.\n- [remotedev-rn-debugger](https://github.com/jhen0409/remotedev-rn-debugger) - Used in React Native debugger as a dock monitor.\n- [atom-redux-devtools](https://github.com/zalmoxisus/atom-redux-devtools) - Used in Atom editor.\n- [redux-dispatch-cli](https://github.com/jhen0409/redux-dispatch-cli) - A CLI tool for Redux remote dispatch.\n- [vscode-redux-devtools](https://github.com/jkzing/vscode-redux-devtools) - Used in Visual Studio Code.\n\nUse [@redux-devtools/app](https://github.com/reduxjs/redux-devtools/tree/main/packages/redux-devtools-app) to create your own monitor app.\n\n### Communicate via local server\n\nUse [@redux-devtools/cli](https://github.com/reduxjs/redux-devtools/tree/main/packages/redux-devtools-cli).\nYou can import it in your `server.js` script and start remotedev server together with your development server:\n\n```js\nvar reduxDevTools = require('@redux-devtools/cli');\nreduxDevTools({ hostname: 'localhost', port: 8000 });\n```\n\nSee [@redux-devtools/cli](https://github.com/reduxjs/redux-devtools/tree/main/packages/redux-devtools-cli) for more details.\nFor React Native you can use [remotedev-rn-debugger](https://github.com/jhen0409/remotedev-rn-debugger), which already include `@redux-devtools/cli`.\n\n### Parameters\n\n| Name                    | Description                                                                                                                                                                                                                                                                                                   |\n| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `name`                  | _String_ representing the instance name to be shown on the remote monitor.                                                                                                                                                                                                                                    |\n| `realtime`              | _Boolean_ specifies whether to allow remote monitoring. By default is `process.env.NODE_ENV === 'development'`.                                                                                                                                                                                               |\n| `hostname`              | _String_ used to specify host for [@redux-devtools/cli](https://github.com/reduxjs/redux-devtools/tree/main/packages/redux-devtools-cli). If `port` is specified, default value is `localhost`.                                                                                                               |\n| `port`                  | _Number_ used to specify host's port for [@redux-devtools/cli](https://github.com/reduxjs/redux-devtools/tree/main/packages/redux-devtools-cli).                                                                                                                                                              |\n| `secure`                | _Boolean_ specifies whether to use `https` protocol for [@redux-devtools/cli](https://github.com/reduxjs/redux-devtools/tree/main/packages/redux-devtools-cli).                                                                                                                                               |\n| `maxAge`                | _Number_ of maximum allowed actions to be stored on the history tree, the oldest actions are removed once maxAge is reached. Default is `30`.                                                                                                                                                                 |\n| `actionsDenylist`       | _array_ of actions to be hidden in DevTools. Overwrites corresponding global setting in the options page. See the example bellow.                                                                                                                                                                             |\n| `actionsAllowlist`      | _array_ of actions to be shown. All other actions will be hidden in DevTools.                                                                                                                                                                                                                                 |\n| `actionSanitizer`       | _Function_ which takes action object and id number as arguments, and should return action object back. See the example bellow.                                                                                                                                                                                |\n| `stateSanitizer`        | _Function_ which takes state object and index as arguments, and should return state object back. See the example bellow.                                                                                                                                                                                      |\n| `startOn`               | _String_ or _Array of strings_ indicating an action or a list of actions, which should start remote monitoring (when `realtime` is `false`).                                                                                                                                                                  |\n| `stopOn`                | _String_ or _Array of strings_ indicating an action or a list of actions, which should stop remote monitoring.                                                                                                                                                                                                |\n| `sendOn`                | _String_ or _Array of strings_ indicating an action or a list of actions, which should trigger sending the history to the monitor (without starting it). _Note_: when using it, add a `fetch` polyfill if needed.                                                                                             |\n| `sendOnError`           | _Numeric_ code: `0` - disabled (default), `1` - send all uncaught exception messages, `2` - send only reducers error messages.                                                                                                                                                                                |\n| `sendTo`                | _String_ url of the monitor to send the history when `sendOn` is triggered. By default is `${secure ? 'https' : 'http'}://${hostname}:${port}`.                                                                                                                                                               |\n| `actionCreators`        | _Array_ or _Object_ of action creators to dispatch remotely. See [the example](https://github.com/zalmoxisus/remote-redux-devtools/commit/b54652930dfd4e057991df8471c343957fd7bff7).                                                                                                                          |\n| `shouldHotReload`       | _Boolean_ - if set to `false`, will not recompute the states on hot reloading (or on replacing the reducers). Default to `true`.                                                                                                                                                                              |\n| `shouldRecordChanges`   | _Boolean_ - if specified as `false`, it will not record the changes till clicked on \"Start recording\" button on the monitor app. Default is `true`.                                                                                                                                                           |\n| `shouldStartLocked`     | _Boolean_ - if specified as `true`, it will not allow any non-monitor actions to be dispatched till `lockChanges(false)` is dispatched. Default is `false`.                                                                                                                                                   |\n| `id`                    | _String_ to identify the instance when sending the history triggered by `sendOn`. You can use, for example, user id here, to know who sent the data.                                                                                                                                                          |\n| `suppressConnectErrors` | _Boolean_ - if set to `false`, all socket errors thrown while trying to connect will be printed to the console, regardless of if they've been thrown before. This is primarily for suppressing `SocketProtocolError` errors, which get repeatedly thrown when trying to make a connection. Default is `true`. |\n\nAll parameters are optional. You have to provide the `port` property to use the `hostname` or `secure` properties.\n\nExample:\n\n```js\nexport default function configureStore(preloadedState) {\n  const store = createStore(\n    reducer,\n    preloadedState,\n    devToolsEnhancer({\n      name: 'Android app',\n      realtime: true,\n      hostname: 'localhost',\n      port: 8000,\n      maxAge: 30,\n      actionsDenylist: ['EFFECT_RESOLVED'],\n      actionSanitizer: (action) =>\n        action.type === 'FILE_DOWNLOAD_SUCCESS' && action.data\n          ? { ...action, data: '<<LONG_BLOB>>' }\n          : action,\n      stateSanitizer: (state) =>\n        state.data ? { ...state, data: '<<LONG_BLOB>>' } : state,\n    }),\n  );\n  return store;\n}\n```\n\n### Demo\n\n- [Toggle monitoring](http://zalmoxisus.github.io/monitoring/)\n\n### Examples\n\n- [Web](https://github.com/reduxjs/redux-devtools/tree/main/packages/redux-devtools-remote/examples)\n- [React Native](https://github.com/chentsulin/react-native-counter-ios-android)\n\n### License\n\nMIT\n"
  },
  {
    "path": "packages/redux-devtools-remote/eslint.config.mjs",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTs from '../../eslint.ts.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTs(import.meta.dirname),\n  {\n    ignores: ['examples', 'lib'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-remote/package.json",
    "content": "{\n  \"name\": \"@redux-devtools/remote\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Relay Redux actions to remote Redux DevTools.\",\n  \"keywords\": [\n    \"redux\",\n    \"devtools\",\n    \"flux\",\n    \"react\",\n    \"hot reloading\",\n    \"time travel\",\n    \"live edit\"\n  ],\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-remote\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)\",\n  \"files\": [\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": \"./lib/index.js\",\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run type-check && pnpm run lint\"\n  },\n  \"dependencies\": {\n    \"@redux-devtools/instrument\": \"workspace:^\",\n    \"@redux-devtools/utils\": \"workspace:^\",\n    \"jsan\": \"^3.1.14\",\n    \"rn-host-detect\": \"^1.2.0\",\n    \"socketcluster-client\": \"^20.0.1\"\n  },\n  \"devDependencies\": {\n    \"@types/jsan\": \"^3.1.5\",\n    \"@types/node\": \"^24.12.0\",\n    \"@types/rn-host-detect\": \"^1.2.2\",\n    \"@types/socketcluster-client\": \"^20.0.0\",\n    \"@typescript-eslint/eslint-plugin\": \"^8.57.0\",\n    \"@typescript-eslint/parser\": \"^8.57.0\",\n    \"eslint\": \"^9.39.4\",\n    \"eslint-config-prettier\": \"^10.1.8\",\n    \"redux\": \"^5.0.1\",\n    \"rimraf\": \"^6.1.3\",\n    \"typescript\": \"~5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"redux\": \"^3.5.2 || ^4.0.0 || ^5.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-remote/src/configureStore.ts",
    "content": "import { instrument, Options } from '@redux-devtools/instrument';\nimport { Action, Reducer, StoreEnhancerStoreCreator } from 'redux';\n\nexport default function configureStore<\n  S,\n  A extends Action<string>,\n  MonitorState,\n  MonitorAction extends Action<string>,\n>(\n  next: StoreEnhancerStoreCreator,\n  subscriber: Reducer<MonitorState, MonitorAction>,\n  options: Options<S, A, MonitorState, MonitorAction>,\n) {\n  return instrument(subscriber, options)(next);\n}\n"
  },
  {
    "path": "packages/redux-devtools-remote/src/constants.ts",
    "content": "export const defaultSocketOptions = {\n  secure: false,\n  hostname: 'localhost',\n  port: 8000,\n  autoReconnect: true,\n  autoReconnectOptions: {\n    randomness: 30000,\n  },\n};\n"
  },
  {
    "path": "packages/redux-devtools-remote/src/devTools.ts",
    "content": "import { stringify, parse } from 'jsan';\nimport socketClusterClient, { AGClientSocket } from 'socketcluster-client';\nimport configureStore from './configureStore.js';\nimport { defaultSocketOptions } from './constants.js';\nimport getHostForRN from 'rn-host-detect';\nimport {\n  Action,\n  ActionCreator,\n  Reducer,\n  StoreEnhancer,\n  StoreEnhancerStoreCreator,\n} from 'redux';\nimport {\n  EnhancedStore,\n  LiftedAction,\n  LiftedState,\n  PerformAction,\n} from '@redux-devtools/instrument';\nimport {\n  ActionCreatorObject,\n  ErrorAction,\n  evalAction,\n  catchErrors,\n  getActionsArray,\n  getLocalFilter,\n  isFiltered,\n  filterStagedActions,\n  filterState,\n  LocalFilter,\n  State,\n} from '@redux-devtools/utils';\n\nfunction async(fn: () => unknown) {\n  setTimeout(fn, 0);\n}\n\nfunction str2array(\n  str: string | readonly string[] | undefined,\n): readonly string[] | undefined {\n  return typeof str === 'string'\n    ? [str]\n    : str && str.length > 0\n      ? str\n      : undefined;\n}\n\nfunction getRandomId() {\n  return Math.random().toString(36).substr(2);\n}\n\ninterface AutoReconnectOptions {\n  readonly randomness?: number;\n}\n\ninterface SocketOptions {\n  readonly secure?: boolean;\n  readonly hostname: string;\n  readonly port: number;\n  readonly autoReconnect?: boolean;\n  readonly autoReconnectOptions?: AutoReconnectOptions;\n}\n\ninterface Filters {\n  /**\n   * @deprecated Use actionsDenylist instead.\n   */\n  readonly blacklist?: string | readonly string[];\n  /**\n   * @deprecated Use actionsAllowlist instead.\n   */\n  readonly whitelist?: string | readonly string[];\n  readonly denylist?: string | readonly string[];\n  readonly allowlist?: string | readonly string[];\n}\n\ninterface Options<S, A extends Action<string>> {\n  readonly hostname?: string;\n  readonly realtime?: boolean;\n  readonly maxAge?: number;\n  readonly trace?: boolean | ((action: A) => string | undefined);\n  readonly traceLimit?: number;\n  readonly shouldHotReload?: boolean;\n  readonly shouldRecordChanges?: boolean;\n  readonly shouldStartLocked?: boolean;\n  readonly pauseActionType?: unknown;\n  readonly name?: string;\n  readonly filters?: Filters;\n  /**\n   * @deprecated Use actionsDenylist instead.\n   */\n  readonly actionsBlacklist?: string | readonly string[];\n  /**\n   * @deprecated Use actionsAllowlist instead.\n   */\n  readonly actionsWhitelist?: string | readonly string[];\n  readonly actionsDenylist?: string | readonly string[];\n  readonly actionsAllowlist?: string | readonly string[];\n  readonly port?: number;\n  readonly secure?: boolean;\n  readonly suppressConnectErrors?: boolean;\n  readonly startOn?: string | readonly string[];\n  readonly stopOn?: string | readonly string[];\n  readonly sendOn?: string | readonly string[];\n  readonly sendOnError?: number;\n  readonly sendTo?: string;\n  readonly id?: string;\n  readonly actionCreators?: {\n    [key: string]: ActionCreator<Action<string>>;\n  };\n  readonly stateSanitizer?: ((state: S, index?: number) => S) | undefined;\n  readonly actionSanitizer?:\n    | (<A extends Action<string>>(action: A, id?: number) => A)\n    | undefined;\n}\n\ninterface MessageToRelay {\n  type: 'STATE' | 'ACTION' | 'START' | 'STOP' | 'ERROR';\n  id: string;\n  name: string | undefined;\n  instanceId: string;\n  payload?: string;\n  action?: string | ActionCreatorObject[];\n  isExcess?: boolean | undefined;\n  nextActionId?: number | undefined;\n}\n\ninterface ImportMessage {\n  readonly type: 'IMPORT';\n  readonly state: string;\n}\n\ninterface SyncMessage {\n  readonly type: 'SYNC';\n  readonly state: string;\n  readonly id: string | undefined;\n  readonly instanceId: string | number;\n}\n\ninterface UpdateMessage {\n  readonly type: 'UPDATE';\n}\n\ninterface StartMessage {\n  readonly type: 'START';\n}\n\ninterface StopMessage {\n  readonly type: 'STOP';\n}\n\ninterface DisconnectedMessage {\n  readonly type: 'DISCONNECTED';\n}\n\ninterface ActionMessage {\n  readonly type: 'ACTION';\n  readonly action: string | { args: string[]; rest: string; selected: number };\n}\n\ninterface DispatchMessage<S, A extends Action<string>> {\n  readonly type: 'DISPATCH';\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  readonly action: LiftedAction<S, A, {}>;\n}\n\ntype Message<S, A extends Action<string>> =\n  | ImportMessage\n  | SyncMessage\n  | UpdateMessage\n  | StartMessage\n  | StopMessage\n  | DisconnectedMessage\n  | ActionMessage\n  | DispatchMessage<S, A>;\n\nclass DevToolsEnhancer<S, A extends Action<string>, PreloadedState> {\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  store!: EnhancedStore<S, A, {}>;\n  filters: LocalFilter | undefined;\n  instanceId?: string;\n  socket?: AGClientSocket;\n  sendTo?: string;\n  instanceName: string | undefined;\n  appInstanceId!: string;\n  stateSanitizer: ((state: S, index?: number) => S) | undefined;\n  actionSanitizer: ((action: A, id?: number) => A) | undefined;\n  isExcess?: boolean;\n  actionCreators?: (() => ActionCreatorObject[]) | ActionCreatorObject[];\n  isMonitored?: boolean;\n  lastErrorMsg?: string | Event;\n  started?: boolean;\n  socketOptions!: SocketOptions;\n  suppressConnectErrors!: boolean;\n  startOn: readonly string[] | undefined;\n  stopOn: readonly string[] | undefined;\n  sendOn: readonly string[] | undefined;\n  sendOnError: number | undefined;\n  channel?: string;\n  errorCounts: { [errorName: string]: number } = {};\n  lastAction?: unknown;\n  paused?: boolean;\n  locked?: boolean;\n\n  getLiftedStateRaw() {\n    return this.store.liftedStore.getState();\n  }\n\n  getLiftedState() {\n    return filterStagedActions(this.getLiftedStateRaw(), this.filters);\n  }\n\n  send = () => {\n    if (!this.instanceId)\n      this.instanceId = (this.socket && this.socket.id) || getRandomId();\n    try {\n      fetch(this.sendTo!, {\n        method: 'POST',\n        headers: {\n          'content-type': 'application/json',\n        },\n        body: JSON.stringify({\n          type: 'STATE',\n          id: this.instanceId,\n          name: this.instanceName,\n          payload: stringify(this.getLiftedState()),\n        }),\n      }).catch(function (err) {\n        console.log(err);\n      });\n    } catch (err) {\n      console.log(err);\n    }\n  };\n\n  relay(\n    type: 'STATE' | 'ACTION' | 'START' | 'STOP' | 'ERROR',\n    state?: State | S | string,\n    action?: PerformAction<A> | ActionCreatorObject[],\n    nextActionId?: number,\n  ) {\n    const message: MessageToRelay = {\n      type,\n      // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n      id: this.socket!.id!,\n      name: this.instanceName,\n      instanceId: this.appInstanceId,\n    };\n    if (state) {\n      message.payload =\n        type === 'ERROR'\n          ? (state as string)\n          : stringify(\n              filterState(\n                state as State,\n                type,\n                this.filters,\n                this.stateSanitizer as (\n                  state: unknown,\n                  index?: number,\n                ) => unknown,\n                this.actionSanitizer as\n                  | ((action: Action<string>, id: number) => Action)\n                  | undefined,\n                nextActionId!,\n              ),\n            );\n    }\n    if (type === 'ACTION') {\n      message.action = stringify(\n        !this.actionSanitizer\n          ? action\n          : this.actionSanitizer(\n              (action as PerformAction<A>).action,\n              nextActionId! - 1,\n            ),\n      );\n      message.isExcess = this.isExcess;\n      message.nextActionId = nextActionId;\n    } else if (action) {\n      message.action = action as ActionCreatorObject[];\n    }\n    // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n    void this.socket!.transmit(this.socket!.id ? 'log' : 'log-noid', message);\n  }\n\n  dispatchRemotely(\n    action: string | { args: string[]; rest: string; selected: number },\n  ) {\n    try {\n      const result = evalAction(\n        action,\n        this.actionCreators as ActionCreatorObject[],\n      );\n      this.store.dispatch(result);\n    } catch (e: unknown) {\n      this.relay('ERROR', (e as Error).message);\n    }\n  }\n\n  handleMessages = (message: Message<S, A>) => {\n    if (\n      message.type === 'IMPORT' ||\n      (message.type === 'SYNC' &&\n        // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n        this.socket!.id &&\n        // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n        message.id !== this.socket!.id)\n    ) {\n      this.store.liftedStore.dispatch({\n        type: 'IMPORT_STATE',\n        // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n        nextLiftedState: parse(message.state) as LiftedState<S, A, {}>,\n      });\n    } else if (message.type === 'UPDATE') {\n      this.relay('STATE', this.getLiftedState());\n    } else if (message.type === 'START') {\n      this.isMonitored = true;\n      if (typeof this.actionCreators === 'function')\n        this.actionCreators = this.actionCreators();\n      this.relay('STATE', this.getLiftedState(), this.actionCreators);\n    } else if (message.type === 'STOP' || message.type === 'DISCONNECTED') {\n      this.isMonitored = false;\n      this.relay('STOP');\n    } else if (message.type === 'ACTION') {\n      this.dispatchRemotely(message.action);\n    } else if (message.type === 'DISPATCH') {\n      this.store.liftedStore.dispatch(message.action);\n    }\n  };\n\n  sendError = (errorAction: ErrorAction) => {\n    // Prevent flooding\n    if (errorAction.message && errorAction.message === this.lastErrorMsg)\n      return;\n    this.lastErrorMsg = errorAction.message;\n\n    async(() => {\n      this.store.dispatch(errorAction as A);\n      if (!this.started) this.send();\n    });\n  };\n\n  init(options: Options<S, A>) {\n    this.instanceName = options.name;\n    this.appInstanceId = getRandomId();\n    const { blacklist, whitelist, denylist, allowlist } = options.filters || {};\n    this.filters = getLocalFilter({\n      actionsDenylist:\n        denylist ??\n        options.actionsDenylist ??\n        blacklist ??\n        options.actionsBlacklist,\n      actionsAllowlist:\n        allowlist ??\n        options.actionsAllowlist ??\n        whitelist ??\n        options.actionsWhitelist,\n    });\n    if (options.port) {\n      this.socketOptions = {\n        port: options.port,\n        hostname: options.hostname || 'localhost',\n        secure: options.secure,\n      };\n    } else this.socketOptions = defaultSocketOptions;\n\n    this.suppressConnectErrors =\n      options.suppressConnectErrors !== undefined\n        ? options.suppressConnectErrors\n        : true;\n\n    this.startOn = str2array(options.startOn);\n    this.stopOn = str2array(options.stopOn);\n    this.sendOn = str2array(options.sendOn);\n    this.sendOnError = options.sendOnError;\n    if (this.sendOn || this.sendOnError) {\n      this.sendTo =\n        options.sendTo ||\n        `${this.socketOptions.secure ? 'https' : 'http'}://${\n          this.socketOptions.hostname\n        }:${this.socketOptions.port}`;\n      this.instanceId = options.id;\n    }\n    if (this.sendOnError === 1) catchErrors(this.sendError);\n\n    if (options.actionCreators)\n      this.actionCreators = () => getActionsArray(options.actionCreators!);\n    this.stateSanitizer = options.stateSanitizer;\n    this.actionSanitizer = options.actionSanitizer;\n  }\n\n  login() {\n    void (async () => {\n      try {\n        // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n        const channelName = (await this.socket!.invoke(\n          'login',\n          'master',\n        )) as string;\n        this.channel = channelName;\n        // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n        for await (const data of this.socket!.subscribe(channelName)) {\n          this.handleMessages(data as Message<S, A>);\n        }\n      } catch (error) {\n        console.log(error);\n      }\n    })();\n    this.started = true;\n    this.relay('START');\n  }\n\n  stop = (keepConnected?: boolean) => {\n    this.started = false;\n    this.isMonitored = false;\n    if (!this.socket) return;\n    void this.socket.unsubscribe(this.channel!);\n    this.socket.closeChannel(this.channel!);\n    if (!keepConnected) {\n      this.socket.disconnect();\n    }\n  };\n\n  start = () => {\n    if (\n      this.started ||\n      (this.socket && this.socket.getState() === this.socket.CONNECTING)\n    )\n      return;\n\n    this.socket = socketClusterClient.create(this.socketOptions);\n\n    void (async () => {\n      // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n      for await (const data of this.socket!.listener('error')) {\n        // if we've already had this error before, increment it's counter, otherwise assign it '1' since we've had the error once.\n        // eslint-disable-next-line no-prototype-builtins,@typescript-eslint/no-unsafe-argument\n        this.errorCounts[data.error.name] = this.errorCounts.hasOwnProperty(\n          data.error.name,\n        )\n          ? this.errorCounts[data.error.name] + 1\n          : 1;\n\n        if (this.suppressConnectErrors) {\n          if (this.errorCounts[data.error.name] === 1) {\n            console.log(\n              'remote-redux-devtools: Socket connection errors are being suppressed. ' +\n                '\\n' +\n                \"This can be disabled by setting suppressConnectErrors to 'false'.\",\n            );\n            console.log(data.error);\n          }\n        } else {\n          console.log(data.error);\n        }\n      }\n    })();\n\n    void (async () => {\n      // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n      for await (const data of this.socket!.listener('connect')) {\n        console.log('connected to remotedev-server');\n        this.errorCounts = {}; // clear the errorCounts object, so that we'll log any new errors in the event of a disconnect\n        this.login();\n      }\n    })();\n    void (async () => {\n      // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n      for await (const data of this.socket!.listener('disconnect')) {\n        this.stop(true);\n      }\n    })();\n  };\n\n  checkForReducerErrors = (liftedState = this.getLiftedStateRaw()) => {\n    if (liftedState.computedStates[liftedState.currentStateIndex].error) {\n      if (this.started)\n        this.relay('STATE', filterStagedActions(liftedState, this.filters));\n      else this.send();\n      return true;\n    }\n    return false;\n  };\n\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  monitorReducer = (state = {}, action: LiftedAction<S, A, {}>) => {\n    this.lastAction = action.type;\n    if (!this.started && this.sendOnError === 2 && this.store.liftedStore)\n      async(this.checkForReducerErrors);\n    else if ((action as PerformAction<A>).action) {\n      if (\n        this.startOn &&\n        !this.started &&\n        this.startOn.includes((action as PerformAction<A>).action.type)\n      )\n        async(this.start);\n      else if (\n        this.stopOn &&\n        this.started &&\n        this.stopOn.includes((action as PerformAction<A>).action.type)\n      )\n        async(this.stop);\n      else if (\n        this.sendOn &&\n        !this.started &&\n        this.sendOn.includes((action as PerformAction<A>).action.type)\n      )\n        async(this.send);\n    }\n    return state;\n  };\n\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  handleChange(state: S, liftedState: LiftedState<S, A, {}>, maxAge: number) {\n    if (this.checkForReducerErrors(liftedState)) return;\n\n    if (this.lastAction === 'PERFORM_ACTION') {\n      const nextActionId = liftedState.nextActionId;\n      const liftedAction = liftedState.actionsById[nextActionId - 1];\n      if (isFiltered(liftedAction.action, this.filters)) return;\n      this.relay('ACTION', state, liftedAction, nextActionId);\n      if (!this.isExcess && maxAge)\n        this.isExcess = liftedState.stagedActionIds.length >= maxAge;\n    } else {\n      if (this.lastAction === 'JUMP_TO_STATE') return;\n      if (this.lastAction === 'PAUSE_RECORDING') {\n        this.paused = liftedState.isPaused;\n      } else if (this.lastAction === 'LOCK_CHANGES') {\n        this.locked = liftedState.isLocked;\n      }\n      if (this.paused || this.locked) {\n        if (this.lastAction) this.lastAction = undefined;\n        else return;\n      }\n      this.relay('STATE', filterStagedActions(liftedState, this.filters));\n    }\n  }\n\n  enhance = (options: Options<S, A> = {}): StoreEnhancer => {\n    this.init({\n      ...options,\n      hostname: getHostForRN(options.hostname || 'localhost'),\n    });\n    const realtime =\n      typeof options.realtime === 'undefined'\n        ? process.env.NODE_ENV === 'development'\n        : options.realtime;\n    if (!realtime && !(this.startOn || this.sendOn || this.sendOnError))\n      return (f) => f;\n\n    const maxAge = options.maxAge || 30;\n    return ((next: StoreEnhancerStoreCreator) => {\n      return (\n        reducer: Reducer<S, A, PreloadedState>,\n        initialState?: PreloadedState | undefined,\n      ) => {\n        this.store = configureStore(next, this.monitorReducer, {\n          maxAge,\n          trace: options.trace,\n          traceLimit: options.traceLimit,\n          shouldCatchErrors: !!this.sendOnError,\n          shouldHotReload: options.shouldHotReload,\n          shouldRecordChanges: options.shouldRecordChanges,\n          shouldStartLocked: options.shouldStartLocked,\n          pauseActionType: options.pauseActionType || '@@PAUSED',\n        })(reducer, initialState);\n\n        if (realtime) this.start();\n        this.store.subscribe(() => {\n          if (this.isMonitored)\n            this.handleChange(\n              this.store.getState(),\n              this.getLiftedStateRaw(),\n              maxAge,\n            );\n        });\n        return this.store;\n      };\n    }) as any;\n  };\n}\n\nexport default <S, A extends Action<string>, PreloadedState>(\n  options?: Options<S, A>,\n) => new DevToolsEnhancer<S, A, PreloadedState>().enhance(options);\n\nconst compose =\n  (options: Options<unknown, Action<string>>) =>\n  (...funcs: StoreEnhancer[]) =>\n  (...args: unknown[]) => {\n    const devToolsEnhancer = new DevToolsEnhancer();\n\n    function preEnhancer(createStore: StoreEnhancerStoreCreator) {\n      return <S, A extends Action<string>, PreloadedState>(\n        reducer: Reducer<S, A, PreloadedState>,\n        preloadedState?: PreloadedState | undefined,\n      ) => {\n        devToolsEnhancer.store = createStore(reducer, preloadedState) as any;\n        return {\n          ...devToolsEnhancer.store,\n          dispatch: (action: Action<string>) =>\n            devToolsEnhancer.locked\n              ? action\n              : devToolsEnhancer.store.dispatch(action),\n        };\n      };\n    }\n\n    return [preEnhancer, ...funcs].reduceRight(\n      (composed, f) => f(composed) as any,\n      devToolsEnhancer.enhance(options)(\n        ...(args as [StoreEnhancerStoreCreator]),\n      ),\n    );\n  };\n\nexport function composeWithDevTools(\n  ...funcs: [Options<unknown, Action<string>>] | StoreEnhancer[]\n) {\n  if (funcs.length === 0) {\n    return new DevToolsEnhancer().enhance();\n  }\n  if (funcs.length === 1 && typeof funcs[0] === 'object') {\n    return compose(funcs[0]);\n  }\n  return compose({})(...(funcs as StoreEnhancer[]));\n}\n"
  },
  {
    "path": "packages/redux-devtools-remote/src/index.ts",
    "content": "export {\n  default as devToolsEnhancer,\n  composeWithDevTools,\n} from './devTools.js';\n"
  },
  {
    "path": "packages/redux-devtools-remote/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/CHANGELOG.md",
    "content": "# Change Log\n\n## 7.0.0\n\n### Major Changes\n\n- 12849a4: Convert monitors to ESM\n\n### Patch Changes\n\n- Updated dependencies [d61d31a]\n- Updated dependencies [804e729]\n- Updated dependencies [804d6bd]\n  - @redux-devtools/ui@3.0.0\n  - @redux-devtools/core@5.0.0\n\n## 6.0.0\n\n### Major Changes\n\n- 6163276: Replace styled-components with Emotion\n\n### Patch Changes\n\n- Updated dependencies [6163276]\n  - @redux-devtools/ui@2.0.0\n\n## 5.2.0\n\n### Minor Changes\n\n- 17b55ef: Handle api.provided state changes in RTKQ 2.6.2\n\n## 5.1.1\n\n### Patch Changes\n\n- Updated dependencies [91f21b2]\n  - @redux-devtools/core@4.1.1\n\n## 5.1.0\n\n### Minor Changes\n\n- 6830118: Add React 19 to peer deps\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - react-json-tree@0.20.0\n  - @redux-devtools/ui@1.4.0\n  - @redux-devtools/core@4.1.0\n\n## 5.0.1\n\n### Patch Changes\n\n- Updated dependencies [bbb1a40]\n  - react-base16-styling@0.10.0\n  - react-json-tree@0.19.0\n  - @redux-devtools/ui@1.3.2\n\n## 5.0.0\n\n### Major Changes\n\n- 5cfe3e5: Update min required React version to 16.8.4\n\n### Patch Changes\n\n- Updated dependencies [decc035]\n  - @redux-devtools/core@4.0.0\n\n## 4.0.1\n\n### Patch Changes\n\n- 3205269: Add explicit return types\n\n## 4.0.0\n\n### Major Changes\n\n- 6954eb9: Replace jss with Emotion in inspector-monitor. `@emotion/react` is now a required peer dependency.\n\n## 3.2.0\n\n### Minor Changes\n\n- 7f5bddbd: Widen peer dependencies\n- 6fc18ed7: Add new Redux version to peer dependencies\n\n### Patch Changes\n\n- Updated dependencies [7f5bddbd]\n  - @redux-devtools/ui@1.3.1\n\n## 3.1.2\n\n### Patch Changes\n\n- 42531c50: Bump versions\n- Updated dependencies [42531c50]\n  - @redux-devtools/core@3.13.3\n\n## 3.1.1\n\n### Patch Changes\n\n- Updated dependencies [81926f32]\n  - react-json-tree@0.18.0\n\n## 3.1.0\n\n### Minor Changes\n\n- 24f60a7a: feat(rtk-query): add Data tab to rtk-query-monitor #1126 #1129\n\n## 3.0.1\n\n### Patch Changes\n\n- a55ba302: Fix peer dependencies on @redux-devtools/core\n- Updated dependencies [a55ba302]\n  - @redux-devtools/core@3.13.1\n\n## 3.0.0\n\n### Minor Changes\n\n- 8a7eae4: Add React 18 to peerDependencies range\n\n### Patch Changes\n\n- Updated dependencies [8a7eae4]\n  - react-json-tree@0.17.0\n  - @redux-devtools/ui@1.3.0\n  - @redux-devtools/core@3.13.0\n\n## 2.1.2\n\n### Patch Changes\n\n- Updated dependencies [4891bf6]\n  - @redux-devtools/core@3.12.0\n\n## 2.0.0\n\n- Adds ESM build (https://github.com/reduxjs/redux-devtools/pull/997) and switches the default export to a named export in order to ensure that the CommonJS output and the ESM output are [interchangeable](https://rollupjs.org/guide/en/#outputexports):\n\n```diff\n- import RtkQueryrMonitor from '@redux-devtools/rtk-query-monitor';\n+ import { RtkQueryrMonitor } from '@redux-devtools/rtk-query-monitor';\n```\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2021 Fabrizio Vitale\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/README.md",
    "content": "# Redux DevTools RTK Query inspector monitor\n\nA monitor that displays [RTK query](https://redux-toolkit.js.org/rtk-query/overview) queries and mutations for [Redux DevTools](https://github.com/gaearon/redux-devtools).\n\nCreated by [FaberVitale](https://github.com/FaberVitale), inspired by [react-query devtools](https://github.com/tannerlinsley/react-query/tree/master/devtools).\n\n## Demo\n\n- [link](https://rtk-query-monitor-demo.netlify.app/)\n- [demo source](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-rtk-query-monitor/demo)\n\n## Preview\n\n![RTK Query inspector monitor demo](./monitor-demo.gif)\n\n## Installation\n\n### npm\n\n```bash\nnpm i @redux-devtools/rtk-query-monitor --save\n```\n\n### yarn\n\n```bash\nyarn add @redux-devtools/rtk-query-monitor\n```\n\n## Usage\n\nYou can use `RtkQueryMonitor` as the only monitor in your app:\n\n#### `containers/DevTools.js`\n\n```ts\nimport React from 'react';\nimport { createDevTools } from '@redux-devtools/core';\nimport { RtkQueryrMonitor } from '@redux-devtools/rtk-query-monitor';\n\nexport default createDevTools(<RtkQueryrMonitor />);\n```\n\nThen you can render `<DevTools>` to any place inside app or even into a separate popup window.\n\nAlternatively, you can use it together with [`DockMonitor`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-dock-monitor) to make it dockable.\n\n### See also\n\n- [`DockMonitor` README](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-dock-monitor)\n\n- [Read how to start using Redux DevTools.](https://github.com/reduxjs/redux-devtools)\n\n- [Redux Devtools walkthrough](https://github.com/reduxjs/redux-devtools/tree/master/docs/Walkthrough.md)\n\n## Features\n\n- sorts active queries and mutations in ascending or descending order by:\n  - fulfilledTimeStamp\n  - query key\n  - query status\n  - endpoint\n  - api reducerPath\n- filters active queries and mutations by:\n  - fulfilledTimeStamp\n  - query key\n  - query status\n  - endpoint\n  - api reducerPath\n- toggleable regular expression search\n- Displays\n  - status flags\n  - query state\n  - tags\n  - subscriptions\n  - api state\n  - api stats\n  - actions relevant to the selected query or mutation\n\n## Redux DevTools props\n\n| Name          | Description                                                                                                                                                                                                                                                                                                                         |\n| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `theme`       | Either a string referring to one of the themes provided by [redux-devtools-themes](https://github.com/gaearon/redux-devtools-themes) (feel free to contribute!) or a custom object of the same format. Optional. By default, set to [`'nicinabox'`](https://github.com/gaearon/redux-devtools-themes/blob/master/src/nicinabox.js). |\n| `invertTheme` | Boolean value that will invert the colors of the selected theme. Optional. By default, set to `false`                                                                                                                                                                                                                               |\n\n<br/>\n\n### Development\n\n#### Start Demo\n\n```bash\npnpm --filter \"rtk-query-demo\" start\n```\n\n<br/>\n\n## License\n\n[MIT](./LICENSE.md)\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/CHANGELOG.md",
    "content": "# rtk-query-demo\n\n## 0.1.17\n\n### Patch Changes\n\n- Updated dependencies [12849a4]\n- Updated dependencies [804d6bd]\n  - @redux-devtools/dock-monitor@5.0.0\n  - @redux-devtools/rtk-query-monitor@7.0.0\n  - @redux-devtools/core@5.0.0\n\n## 0.1.16\n\n### Patch Changes\n\n- Updated dependencies [6163276]\n  - @redux-devtools/rtk-query-monitor@6.0.0\n\n## 0.1.15\n\n### Patch Changes\n\n- Updated dependencies [17b55ef]\n  - @redux-devtools/rtk-query-monitor@5.2.0\n\n## 0.1.14\n\n### Patch Changes\n\n- Updated dependencies [91f21b2]\n  - @redux-devtools/core@4.1.1\n  - @redux-devtools/dock-monitor@4.1.1\n  - @redux-devtools/rtk-query-monitor@5.1.1\n\n## 0.1.13\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - @redux-devtools/dock-monitor@5.0.0\n  - @redux-devtools/rtk-query-monitor@6.0.0\n  - @redux-devtools/core@4.1.0\n\n## 0.1.12\n\n### Patch Changes\n\n- Updated dependencies [5cfe3e5]\n- Updated dependencies [decc035]\n  - @redux-devtools/dock-monitor@4.0.0\n  - @redux-devtools/rtk-query-monitor@5.0.0\n  - @redux-devtools/core@4.0.0\n\n## 0.1.11\n\n### Patch Changes\n\n- Updated dependencies [6954eb9]\n  - @redux-devtools/rtk-query-monitor@4.0.0\n\n## 0.1.10\n\n### Patch Changes\n\n- 24f60a7a: fix: rtk-query-monitor demo not working #1126 #1129\n- Updated dependencies [24f60a7a]\n  - @redux-devtools/rtk-query-monitor@3.1.0\n\n## 0.1.9\n\n### Patch Changes\n\n- Updated dependencies [8a7eae4]\n  - @redux-devtools/dock-monitor@3.0.0\n  - @redux-devtools/rtk-query-monitor@3.0.0\n  - @redux-devtools/core@3.13.0\n\n## 0.1.8\n\n### Patch Changes\n\n- Updated dependencies [4891bf6]\n  - @redux-devtools/core@3.12.0\n  - @redux-devtools/dock-monitor@2.1.1\n  - @redux-devtools/rtk-query-monitor@2.1.2\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/eslint.config.mjs",
    "content": "import eslintJs from '../../../eslint.js.config.base.mjs';\nimport eslintTs from '../../../eslint.ts.react.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTs(import.meta.dirname),\n  ...eslintTs(\n    import.meta.dirname,\n    ['webpack.config.ts'],\n    ['./tsconfig.webpack.json'],\n  ),\n  {\n    ignores: ['dist'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <meta\n      name=\"description\"\n      content=\"@redux-devtools/rtk-query-monitor demo site\"\n    />\n    <title>RTK Query monitor demo</title>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <noscript>You need to enable JavaScript to run this app.</noscript>\n    <!--\n      This HTML file is a template.\n      If you open it directly in the browser, you will see an empty page.\n\n      You can add webfonts, meta tags, or analytics to this file.\n      The build step will place the bundled scripts into the <body> tag.\n\n      To begin the development, run `npm start` or `yarn start`.\n      To create a production bundle, use `npm run build` or `yarn build`.\n    -->\n  </body>\n</html>\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/package.json",
    "content": "{\n  \"private\": true,\n  \"name\": \"rtk-query-demo\",\n  \"version\": \"0.1.17\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"start\": \"cross-env TS_NODE_PROJECT=\\\"tsconfig.webpack.json\\\" webpack serve --open\",\n    \"build\": \"cross-env TS_NODE_PROJECT=\\\"tsconfig.webpack.json\\\" webpack\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\"\n  },\n  \"dependencies\": {\n    \"@babel/runtime\": \"^7.28.6\",\n    \"@chakra-ui/react\": \"^3.34.0\",\n    \"@emotion/react\": \"^11.14.0\",\n    \"@emotion/styled\": \"^11.14.1\",\n    \"@mswjs/data\": \"^0.16.2\",\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@redux-devtools/dock-monitor\": \"workspace:^\",\n    \"@redux-devtools/rtk-query-monitor\": \"workspace:^\",\n    \"@reduxjs/toolkit\": \"^2.11.2\",\n    \"msw\": \"^2.12.10\",\n    \"react\": \"^19.2.4\",\n    \"react-dom\": \"^19.2.4\",\n    \"react-icons\": \"^5.6.0\",\n    \"react-is\": \"^19.2.4\",\n    \"react-redux\": \"^9.2.0\",\n    \"react-router-dom\": \"^7.13.1\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.29.0\",\n    \"@babel/plugin-transform-runtime\": \"^7.29.0\",\n    \"@babel/preset-env\": \"^7.29.0\",\n    \"@babel/preset-react\": \"^7.28.5\",\n    \"@babel/preset-typescript\": \"^7.28.5\",\n    \"@types/node\": \"^24.12.0\",\n    \"@types/react\": \"^19.2.14\",\n    \"@types/react-dom\": \"^19.2.3\",\n    \"babel-loader\": \"^10.1.1\",\n    \"copy-webpack-plugin\": \"^14.0.0\",\n    \"cross-env\": \"^10.1.0\",\n    \"css-loader\": \"^7.1.4\",\n    \"fork-ts-checker-webpack-plugin\": \"^9.1.0\",\n    \"html-webpack-plugin\": \"^5.6.6\",\n    \"style-loader\": \"^4.0.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"~5.9.3\",\n    \"webpack\": \"^5.105.4\",\n    \"webpack-cli\": \"^7.0.0\",\n    \"webpack-dev-server\": \"^5.2.3\"\n  },\n  \"msw\": {\n    \"workerDirectory\": [\n      \"public\"\n    ]\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/public/mockServiceWorker.js",
    "content": "/* eslint-disable */\n/* tslint:disable */\n\n/**\n * Mock Service Worker.\n * @see https://github.com/mswjs/msw\n * - Please do NOT modify this file.\n */\n\nconst PACKAGE_VERSION = '2.12.10'\nconst INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82'\nconst IS_MOCKED_RESPONSE = Symbol('isMockedResponse')\nconst activeClientIds = new Set()\n\naddEventListener('install', function () {\n  self.skipWaiting()\n})\n\naddEventListener('activate', function (event) {\n  event.waitUntil(self.clients.claim())\n})\n\naddEventListener('message', async function (event) {\n  const clientId = Reflect.get(event.source || {}, 'id')\n\n  if (!clientId || !self.clients) {\n    return\n  }\n\n  const client = await self.clients.get(clientId)\n\n  if (!client) {\n    return\n  }\n\n  const allClients = await self.clients.matchAll({\n    type: 'window',\n  })\n\n  switch (event.data) {\n    case 'KEEPALIVE_REQUEST': {\n      sendToClient(client, {\n        type: 'KEEPALIVE_RESPONSE',\n      })\n      break\n    }\n\n    case 'INTEGRITY_CHECK_REQUEST': {\n      sendToClient(client, {\n        type: 'INTEGRITY_CHECK_RESPONSE',\n        payload: {\n          packageVersion: PACKAGE_VERSION,\n          checksum: INTEGRITY_CHECKSUM,\n        },\n      })\n      break\n    }\n\n    case 'MOCK_ACTIVATE': {\n      activeClientIds.add(clientId)\n\n      sendToClient(client, {\n        type: 'MOCKING_ENABLED',\n        payload: {\n          client: {\n            id: client.id,\n            frameType: client.frameType,\n          },\n        },\n      })\n      break\n    }\n\n    case 'CLIENT_CLOSED': {\n      activeClientIds.delete(clientId)\n\n      const remainingClients = allClients.filter((client) => {\n        return client.id !== clientId\n      })\n\n      // Unregister itself when there are no more clients\n      if (remainingClients.length === 0) {\n        self.registration.unregister()\n      }\n\n      break\n    }\n  }\n})\n\naddEventListener('fetch', function (event) {\n  const requestInterceptedAt = Date.now()\n\n  // Bypass navigation requests.\n  if (event.request.mode === 'navigate') {\n    return\n  }\n\n  // Opening the DevTools triggers the \"only-if-cached\" request\n  // that cannot be handled by the worker. Bypass such requests.\n  if (\n    event.request.cache === 'only-if-cached' &&\n    event.request.mode !== 'same-origin'\n  ) {\n    return\n  }\n\n  // Bypass all requests when there are no active clients.\n  // Prevents the self-unregistered worked from handling requests\n  // after it's been terminated (still remains active until the next reload).\n  if (activeClientIds.size === 0) {\n    return\n  }\n\n  const requestId = crypto.randomUUID()\n  event.respondWith(handleRequest(event, requestId, requestInterceptedAt))\n})\n\n/**\n * @param {FetchEvent} event\n * @param {string} requestId\n * @param {number} requestInterceptedAt\n */\nasync function handleRequest(event, requestId, requestInterceptedAt) {\n  const client = await resolveMainClient(event)\n  const requestCloneForEvents = event.request.clone()\n  const response = await getResponse(\n    event,\n    client,\n    requestId,\n    requestInterceptedAt,\n  )\n\n  // Send back the response clone for the \"response:*\" life-cycle events.\n  // Ensure MSW is active and ready to handle the message, otherwise\n  // this message will pend indefinitely.\n  if (client && activeClientIds.has(client.id)) {\n    const serializedRequest = await serializeRequest(requestCloneForEvents)\n\n    // Clone the response so both the client and the library could consume it.\n    const responseClone = response.clone()\n\n    sendToClient(\n      client,\n      {\n        type: 'RESPONSE',\n        payload: {\n          isMockedResponse: IS_MOCKED_RESPONSE in response,\n          request: {\n            id: requestId,\n            ...serializedRequest,\n          },\n          response: {\n            type: responseClone.type,\n            status: responseClone.status,\n            statusText: responseClone.statusText,\n            headers: Object.fromEntries(responseClone.headers.entries()),\n            body: responseClone.body,\n          },\n        },\n      },\n      responseClone.body ? [serializedRequest.body, responseClone.body] : [],\n    )\n  }\n\n  return response\n}\n\n/**\n * Resolve the main client for the given event.\n * Client that issues a request doesn't necessarily equal the client\n * that registered the worker. It's with the latter the worker should\n * communicate with during the response resolving phase.\n * @param {FetchEvent} event\n * @returns {Promise<Client | undefined>}\n */\nasync function resolveMainClient(event) {\n  const client = await self.clients.get(event.clientId)\n\n  if (activeClientIds.has(event.clientId)) {\n    return client\n  }\n\n  if (client?.frameType === 'top-level') {\n    return client\n  }\n\n  const allClients = await self.clients.matchAll({\n    type: 'window',\n  })\n\n  return allClients\n    .filter((client) => {\n      // Get only those clients that are currently visible.\n      return client.visibilityState === 'visible'\n    })\n    .find((client) => {\n      // Find the client ID that's recorded in the\n      // set of clients that have registered the worker.\n      return activeClientIds.has(client.id)\n    })\n}\n\n/**\n * @param {FetchEvent} event\n * @param {Client | undefined} client\n * @param {string} requestId\n * @param {number} requestInterceptedAt\n * @returns {Promise<Response>}\n */\nasync function getResponse(event, client, requestId, requestInterceptedAt) {\n  // Clone the request because it might've been already used\n  // (i.e. its body has been read and sent to the client).\n  const requestClone = event.request.clone()\n\n  function passthrough() {\n    // Cast the request headers to a new Headers instance\n    // so the headers can be manipulated with.\n    const headers = new Headers(requestClone.headers)\n\n    // Remove the \"accept\" header value that marked this request as passthrough.\n    // This prevents request alteration and also keeps it compliant with the\n    // user-defined CORS policies.\n    const acceptHeader = headers.get('accept')\n    if (acceptHeader) {\n      const values = acceptHeader.split(',').map((value) => value.trim())\n      const filteredValues = values.filter(\n        (value) => value !== 'msw/passthrough',\n      )\n\n      if (filteredValues.length > 0) {\n        headers.set('accept', filteredValues.join(', '))\n      } else {\n        headers.delete('accept')\n      }\n    }\n\n    return fetch(requestClone, { headers })\n  }\n\n  // Bypass mocking when the client is not active.\n  if (!client) {\n    return passthrough()\n  }\n\n  // Bypass initial page load requests (i.e. static assets).\n  // The absence of the immediate/parent client in the map of the active clients\n  // means that MSW hasn't dispatched the \"MOCK_ACTIVATE\" event yet\n  // and is not ready to handle requests.\n  if (!activeClientIds.has(client.id)) {\n    return passthrough()\n  }\n\n  // Notify the client that a request has been intercepted.\n  const serializedRequest = await serializeRequest(event.request)\n  const clientMessage = await sendToClient(\n    client,\n    {\n      type: 'REQUEST',\n      payload: {\n        id: requestId,\n        interceptedAt: requestInterceptedAt,\n        ...serializedRequest,\n      },\n    },\n    [serializedRequest.body],\n  )\n\n  switch (clientMessage.type) {\n    case 'MOCK_RESPONSE': {\n      return respondWithMock(clientMessage.data)\n    }\n\n    case 'PASSTHROUGH': {\n      return passthrough()\n    }\n  }\n\n  return passthrough()\n}\n\n/**\n * @param {Client} client\n * @param {any} message\n * @param {Array<Transferable>} transferrables\n * @returns {Promise<any>}\n */\nfunction sendToClient(client, message, transferrables = []) {\n  return new Promise((resolve, reject) => {\n    const channel = new MessageChannel()\n\n    channel.port1.onmessage = (event) => {\n      if (event.data && event.data.error) {\n        return reject(event.data.error)\n      }\n\n      resolve(event.data)\n    }\n\n    client.postMessage(message, [\n      channel.port2,\n      ...transferrables.filter(Boolean),\n    ])\n  })\n}\n\n/**\n * @param {Response} response\n * @returns {Response}\n */\nfunction respondWithMock(response) {\n  // Setting response status code to 0 is a no-op.\n  // However, when responding with a \"Response.error()\", the produced Response\n  // instance will have status code set to 0. Since it's not possible to create\n  // a Response instance with status code 0, handle that use-case separately.\n  if (response.status === 0) {\n    return Response.error()\n  }\n\n  const mockedResponse = new Response(response.body, response)\n\n  Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, {\n    value: true,\n    enumerable: true,\n  })\n\n  return mockedResponse\n}\n\n/**\n * @param {Request} request\n */\nasync function serializeRequest(request) {\n  return {\n    url: request.url,\n    mode: request.mode,\n    method: request.method,\n    headers: Object.fromEntries(request.headers.entries()),\n    cache: request.cache,\n    credentials: request.credentials,\n    destination: request.destination,\n    integrity: request.integrity,\n    redirect: request.redirect,\n    referrer: request.referrer,\n    referrerPolicy: request.referrerPolicy,\n    body: await request.arrayBuffer(),\n    keepalive: request.keepalive,\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/App.tsx",
    "content": "import PokemonView from './features/pokemon/PokemonView';\nimport PostsView from './features/posts/PostsView';\nimport { Box, Flex, Heading, List } from '@chakra-ui/react';\nimport { Link } from '@chakra-ui/react';\nimport { Code } from '@chakra-ui/react';\nimport * as React from 'react';\nimport { DevToolsSelector } from './features/DevTools/DevToolsSelector';\n\nexport function App() {\n  return (\n    <main className=\"rtk-query-demo-app\">\n      <Heading as=\"h1\" p=\"2\">\n        RTK Query inspector monitor demo\n      </Heading>\n      <PokemonView />\n      <PostsView />\n      <DevToolsSelector />\n      <Flex p=\"2\" as=\"section\" flexWrap=\"nowrap\" flexDirection=\"column\">\n        <Heading as=\"h2\">Dock controls</Heading>\n        <Box as=\"pre\" p=\"2\" paddingX=\"4\">\n          <Code>\n            {`toggleVisibilityKey=\"ctrl-h\"\\nchangePositionKey=\"ctrl-q\"`}\n          </Code>\n        </Box>\n        <Box as=\"p\" p=\"2\" paddingX=\"4\">\n          Drag its border to resize\n        </Box>\n      </Flex>\n      <Flex p=\"2\" as=\"footer\">\n        <List.Root p=\"2\">\n          <List.Item>\n            <Link\n              className=\"link\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              href=\"https://github.com/FaberVitale/redux-devtools/tree/feat/rtk-query-monitor/packages/redux-devtools-rtk-query-monitor/demo\"\n            >\n              demo source\n            </Link>\n          </List.Item>\n          <List.Item>\n            <Link\n              className=\"link\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              href=\"https://github.com/FaberVitale/redux-devtools/tree/feat/rtk-query-monitor/packages/redux-devtools-rtk-query-monitor\"\n            >\n              @redux-devtools/rtk-query-monitor source\n            </Link>\n          </List.Item>\n          <List.Item>\n            <Link\n              className=\"link\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              href=\"https://github.com/reduxjs/redux-toolkit/tree/master/examples/query/react/polling\"\n            >\n              polling example\n            </Link>\n          </List.Item>\n          <List.Item>\n            <Link\n              className=\"link\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              href=\"https://github.com/reduxjs/redux-toolkit/tree/master/examples/query/react/mutations\"\n            >\n              mutations example\n            </Link>\n          </List.Item>\n        </List.Root>\n      </Flex>\n    </main>\n  );\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/components/ui/provider.tsx",
    "content": "'use client';\n\nimport React from 'react';\nimport { ChakraProvider, defaultSystem } from '@chakra-ui/react';\n\nexport function Provider({ children }: { children: React.ReactNode }) {\n  return <ChakraProvider value={defaultSystem}>{children}</ChakraProvider>;\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/components/ui/toaster.tsx",
    "content": "'use client';\n\nimport React from 'react';\nimport {\n  Toaster as ChakraToaster,\n  Portal,\n  Spinner,\n  Stack,\n  Toast,\n  createToaster,\n} from '@chakra-ui/react';\n\nexport const toaster = createToaster({\n  placement: 'bottom-end',\n  pauseOnPageIdle: true,\n});\n\nexport const Toaster = () => {\n  return (\n    <Portal>\n      <ChakraToaster toaster={toaster} insetInline={{ mdDown: '4' }}>\n        {(toast) => (\n          <Toast.Root width={{ md: 'sm' }}>\n            {toast.type === 'loading' ? (\n              <Spinner size=\"sm\" color=\"blue.solid\" />\n            ) : (\n              <Toast.Indicator />\n            )}\n            <Stack gap=\"1\" flex=\"1\" maxWidth=\"100%\">\n              {toast.title && <Toast.Title>{toast.title}</Toast.Title>}\n              {toast.description && (\n                <Toast.Description>{toast.description}</Toast.Description>\n              )}\n            </Stack>\n            {toast.action && (\n              <Toast.ActionTrigger>{toast.action.label}</Toast.ActionTrigger>\n            )}\n            {toast.closable && <Toast.CloseTrigger />}\n          </Toast.Root>\n        )}\n      </ChakraToaster>\n    </Portal>\n  );\n};\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/features/DevTools/DevTools.tsx",
    "content": "import * as React from 'react';\nimport { createDevTools } from '@redux-devtools/core';\nimport { DockMonitor } from '@redux-devtools/dock-monitor';\nimport { RtkQueryMonitor } from '@redux-devtools/rtk-query-monitor';\n\nconst largeScreenQuery = window.matchMedia('(min-width: 1024px)');\n\nexport default createDevTools(\n  <DockMonitor\n    toggleVisibilityKey=\"ctrl-h\"\n    changePositionKey=\"ctrl-q\"\n    changeMonitorKey=\"ctrl-m\"\n    fluid\n    defaultSize={largeScreenQuery.matches ? 0.44 : 0.55}\n  >\n    <RtkQueryMonitor />\n  </DockMonitor>,\n);\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/features/DevTools/DevToolsSelector.tsx",
    "content": "import * as React from 'react';\nimport { ButtonGroup, Button } from '@chakra-ui/react';\nimport { isExtensionEnabled, setIsExtensionEnabled } from './helpers';\nimport { Box, Heading } from '@chakra-ui/react';\n\nexport function DevToolsSelector() {\n  const handleClick = (evt: React.MouseEvent<HTMLButtonElement>) => {\n    setIsExtensionEnabled(evt.currentTarget.dataset.extension === '1');\n    window.location.reload();\n  };\n\n  const extensionEnabled = isExtensionEnabled();\n\n  return (\n    <Box as=\"section\" p=\"2\">\n      <Heading as=\"h2\">Set active devTools</Heading>\n      <ButtonGroup variant=\"outline\" gap=\"4\" p=\"4\">\n        <Button\n          aria-selected={!extensionEnabled}\n          colorScheme=\"blue\"\n          data-extension=\"0\"\n          variant={!extensionEnabled ? 'solid' : 'outline'}\n          onClick={handleClick}\n        >\n          Dock\n        </Button>\n        <Button\n          aria-selected={extensionEnabled}\n          data-extension=\"1\"\n          colorScheme=\"blue\"\n          variant={extensionEnabled ? 'solid' : 'outline'}\n          onClick={handleClick}\n        >\n          Extension\n        </Button>\n      </ButtonGroup>\n    </Box>\n  );\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/features/DevTools/config.ts",
    "content": "export const isExtensionEnabledKey = 'prefer-extension';\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/features/DevTools/helpers.ts",
    "content": "import { isExtensionEnabledKey } from './config';\n\nexport function isExtensionEnabled(): boolean {\n  let extensionEnabled = false;\n\n  try {\n    extensionEnabled =\n      window.sessionStorage.getItem(isExtensionEnabledKey) === '1';\n  } catch (err) {\n    console.error(err);\n  }\n\n  return extensionEnabled;\n}\n\nexport function setIsExtensionEnabled(active: boolean): void {\n  try {\n    window.sessionStorage.setItem(isExtensionEnabledKey, active ? '1' : '0');\n  } catch (err) {\n    console.error(err);\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/features/pokemon/Pokemon.tsx",
    "content": "import React, { useState } from 'react';\nimport { Button, createListCollection, Portal, Select } from '@chakra-ui/react';\nimport { useGetPokemonByNameQuery } from '../../services/pokemon';\nimport type { PokemonName } from '../../pokemon.data';\n\nconst intervalOptions = createListCollection({\n  items: [\n    { label: 'Off', value: '0' },\n    { label: '3s', value: '3000' },\n    { label: '5s', value: '5000' },\n    { label: '10s', value: '10000' },\n    { label: '1m', value: '60000' },\n  ],\n});\n\nexport function Pokemon({ name }: { name: PokemonName }) {\n  const [pollingInterval, setPollingInterval] = useState(60000);\n\n  const { data, error, isLoading, isFetching, refetch } =\n    useGetPokemonByNameQuery(name, {\n      pollingInterval,\n    });\n\n  return (\n    <div\n      className=\"pokemon\"\n      style={{\n        ...(isFetching ? { background: '#e6ffe8' } : {}),\n      }}\n    >\n      {error ? (\n        <>Oh no, there was an error loading {name}</>\n      ) : isLoading ? (\n        <>Loading...</>\n      ) : data ? (\n        <>\n          <h3>{data.species.name}</h3>\n          <div style={{ minWidth: 96, minHeight: 96 }}>\n            <img\n              src={data.sprites.front_shiny}\n              alt={data.species.name}\n              style={{ ...(isFetching ? { opacity: 0.3 } : {}) }}\n            />\n          </div>\n          <div>\n            <Select.Root\n              collection={intervalOptions}\n              value={[pollingInterval.toString()]}\n              onValueChange={({ value }) =>\n                setPollingInterval(Number(value[0]))\n              }\n            >\n              <Select.HiddenSelect />\n              <Select.Label>Polling interval</Select.Label>\n              <Select.Control>\n                <Select.Trigger>\n                  <Select.ValueText placeholder=\"Polling interval\" />\n                </Select.Trigger>\n                <Select.IndicatorGroup>\n                  <Select.Indicator />\n                </Select.IndicatorGroup>\n              </Select.Control>\n              <Portal>\n                <Select.Positioner>\n                  <Select.Content>\n                    {intervalOptions.items.map((intervalOption) => (\n                      <Select.Item\n                        item={intervalOption}\n                        key={intervalOption.value}\n                      >\n                        {intervalOption.label}\n                        <Select.ItemIndicator />\n                      </Select.Item>\n                    ))}\n                  </Select.Content>\n                </Select.Positioner>\n              </Portal>\n            </Select.Root>\n          </div>\n          <div>\n            <Button\n              colorScheme=\"blue\"\n              variant=\"outline\"\n              onClick={refetch}\n              disabled={isFetching}\n            >\n              {isFetching ? 'Loading' : 'Manually refetch'}\n            </Button>\n          </div>\n        </>\n      ) : (\n        'No Data'\n      )}\n    </div>\n  );\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/features/pokemon/PokemonView.tsx",
    "content": "import * as React from 'react';\nimport { Pokemon } from './Pokemon';\nimport { PokemonName, POKEMON_NAMES } from '../../pokemon.data';\nimport { Flex, Heading, Button } from '@chakra-ui/react';\n\nconst getRandomPokemonName = () =>\n  POKEMON_NAMES[Math.floor(Math.random() * POKEMON_NAMES.length)];\n\nexport default function PokemonView() {\n  const [pokemon, setPokemon] = React.useState<PokemonName[]>(['bulbasaur']);\n\n  return (\n    <Flex p=\"2\" as=\"section\" flexWrap=\"nowrap\" flexDirection=\"column\">\n      <Heading as=\"h2\">Pokemon polling demo</Heading>\n      <Flex p=\"2\" gridGap=\"0.5em\" flexDirection=\"row\" flexWrap=\"wrap\">\n        <Button\n          colorScheme=\"blue\"\n          variant=\"outline\"\n          onClick={() =>\n            setPokemon((prev) => [...prev, getRandomPokemonName()])\n          }\n        >\n          Add random pokemon\n        </Button>\n        <Button\n          colorScheme=\"blue\"\n          variant=\"outline\"\n          onClick={() => setPokemon((prev) => [...prev, 'bulbasaur'])}\n        >\n          Add bulbasaur\n        </Button>\n      </Flex>\n\n      <div className=\"pokemon-list\">\n        {pokemon.map((name, index) => (\n          <Pokemon key={index} name={name} />\n        ))}\n      </div>\n    </Flex>\n  );\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/features/posts/PostDetail.tsx",
    "content": "import React, { useState } from 'react';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport {\n  useDeletePostMutation,\n  useGetPostQuery,\n  useUpdatePostMutation,\n} from '../../services/posts';\nimport {\n  Box,\n  Button,\n  Center,\n  CloseButton,\n  Flex,\n  Heading,\n  Input,\n  Spacer,\n  Stack,\n} from '@chakra-ui/react';\nimport { toaster } from '../../components/ui/toaster';\n\nconst EditablePostName = ({\n  name: initialName,\n  onUpdate,\n  onCancel,\n  isLoading = false,\n}: {\n  name: string;\n  onUpdate: (name: string) => void;\n  onCancel: () => void;\n  isLoading?: boolean;\n}) => {\n  const [name, setName] = useState(initialName);\n\n  const handleChange = ({\n    target: { value },\n  }: React.ChangeEvent<HTMLInputElement>) => setName(value);\n\n  const handleUpdate = () => onUpdate(name);\n  const handleCancel = () => onCancel();\n\n  return (\n    <Flex>\n      <Box flex={10}>\n        <Input\n          type=\"text\"\n          onChange={handleChange}\n          value={name}\n          disabled={isLoading}\n        />\n      </Box>\n      <Spacer />\n      <Box>\n        <Stack gap={4} direction=\"row\" align=\"center\">\n          <Button onClick={handleUpdate} loading={isLoading}>\n            Update\n          </Button>\n          <CloseButton bg=\"red\" onClick={handleCancel} disabled={isLoading} />\n        </Stack>\n      </Box>\n    </Flex>\n  );\n};\n\nconst PostJsonDetail = ({ id }: { id: string }) => {\n  const { data: post } = useGetPostQuery(id);\n\n  return (\n    <Box mt={5} bg=\"#eee\">\n      <pre>{JSON.stringify(post, null, 2)}</pre>\n    </Box>\n  );\n};\n\nexport const PostDetail = () => {\n  const { id } = useParams<{ id: string }>();\n  const navigate = useNavigate();\n\n  const [isEditing, setIsEditing] = useState(false);\n\n  const { data: post, isLoading } = useGetPostQuery(id!);\n\n  const [updatePost, { isLoading: isUpdating }] = useUpdatePostMutation();\n\n  const [deletePost, { isLoading: isDeleting }] = useDeletePostMutation();\n\n  if (isLoading) {\n    return <div>Loading...</div>;\n  }\n\n  if (!post) {\n    return (\n      <Center h=\"200px\">\n        <Heading size=\"md\">\n          Post {id} is missing! Try reloading or selecting another post...\n        </Heading>\n      </Center>\n    );\n  }\n\n  return (\n    <Box p={4}>\n      {isEditing ? (\n        <EditablePostName\n          name={post.name}\n          onUpdate={async (name) => {\n            try {\n              await updatePost({ id: id!, name }).unwrap();\n            } catch {\n              toaster.create({\n                title: 'An error occurred',\n                description: \"We couldn't save your changes, try again!\",\n                type: 'error',\n                duration: 2000,\n                closable: true,\n              });\n            } finally {\n              setIsEditing(false);\n            }\n          }}\n          onCancel={() => setIsEditing(false)}\n          isLoading={isUpdating}\n        />\n      ) : (\n        <Flex>\n          <Box>\n            <Heading size=\"md\">{post.name}</Heading>\n          </Box>\n          <Spacer />\n          <Box>\n            <Stack gap={4} direction=\"row\" align=\"center\">\n              <Button\n                onClick={() => setIsEditing(true)}\n                disabled={isDeleting || isUpdating}\n              >\n                {isUpdating ? 'Updating...' : 'Edit'}\n              </Button>\n              <Button\n                onClick={() => deletePost(id!).then(() => navigate('/posts'))}\n                disabled={isDeleting}\n                colorScheme=\"red\"\n              >\n                {isDeleting ? 'Deleting...' : 'Delete'}\n              </Button>\n            </Stack>\n          </Box>\n        </Flex>\n      )}\n      <PostJsonDetail id={post.id} />\n    </Box>\n  );\n};\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/features/posts/PostsManager.tsx",
    "content": "import {\n  Box,\n  Button,\n  Center,\n  Field,\n  Flex,\n  FormatNumber,\n  Heading,\n  Input,\n  List,\n  Separator,\n  Spacer,\n  Stat,\n} from '@chakra-ui/react';\nimport { Route, Routes, useNavigate } from 'react-router-dom';\nimport { MdBook } from 'react-icons/md';\nimport React, { useState } from 'react';\nimport {\n  Post,\n  useAddPostMutation,\n  useGetPostsQuery,\n} from '../../services/posts';\nimport { PostDetail } from './PostDetail';\nimport { toaster } from '../../components/ui/toaster';\n\nconst AddPost = () => {\n  const initialValue = { name: '' };\n  const [post, setPost] = useState<Pick<Post, 'name'>>(initialValue);\n  const [addPost, { isLoading }] = useAddPostMutation();\n\n  const handleChange = ({ target }: React.ChangeEvent<HTMLInputElement>) => {\n    setPost((prev) => ({\n      ...prev,\n      [target.name]: target.value,\n    }));\n  };\n\n  const handleAddPost = async () => {\n    try {\n      await addPost(post).unwrap();\n      setPost(initialValue);\n    } catch {\n      toaster.create({\n        title: 'An error occurred',\n        description: \"We couldn't save your post, try again!\",\n        type: 'error',\n        duration: 2000,\n        closable: true,\n      });\n    }\n  };\n\n  return (\n    <Flex p={'5px 0'} flexDirection=\"row\" flexWrap=\"wrap\" maxWidth={'85%'}>\n      <Box flex={'5 0 auto'} padding=\"0 5px 0 0\">\n        <Field.Root\n          flexDirection=\"column\"\n          invalid={Boolean(post.name.length < 3 && post.name)}\n        >\n          <Field.Label htmlFor=\"name\">Post name</Field.Label>\n          <Input\n            id=\"name\"\n            name=\"name\"\n            placeholder=\"Enter post name\"\n            value={post.name}\n            onChange={handleChange}\n          />\n        </Field.Root>\n      </Box>\n      <Box>\n        <Button\n          mt={8}\n          colorScheme=\"purple\"\n          loading={isLoading}\n          onClick={handleAddPost}\n        >\n          Add Post\n        </Button>\n      </Box>\n    </Flex>\n  );\n};\n\nconst PostList = () => {\n  const { data: posts, isLoading } = useGetPostsQuery();\n  const navigate = useNavigate();\n\n  if (isLoading) {\n    return <div>Loading</div>;\n  }\n\n  if (!posts) {\n    return <div>No posts :(</div>;\n  }\n\n  return (\n    <List.Root gap={3}>\n      {posts.map(({ id, name }) => (\n        <List.Item key={id} onClick={() => navigate(`/posts/${id}`)}>\n          <List.Indicator asChild color=\"green.500\">\n            <MdBook />\n          </List.Indicator>\n          {name}\n        </List.Item>\n      ))}\n    </List.Root>\n  );\n};\n\nexport const PostsCountStat = () => {\n  const { data: posts } = useGetPostsQuery();\n\n  if (!posts) return null;\n\n  return (\n    <Stat.Root>\n      <Stat.Label>Active Posts</Stat.Label>\n      <Stat.ValueText>\n        <FormatNumber value={posts?.length} />\n      </Stat.ValueText>\n    </Stat.Root>\n  );\n};\n\nexport const PostsManager = () => {\n  return (\n    <Box>\n      <Flex bg=\"#011627\" p={4} color=\"white\">\n        <Box>\n          <Heading size=\"xl\">Manage Posts</Heading>\n        </Box>\n        <Spacer />\n        <Box>\n          <PostsCountStat />\n        </Box>\n      </Flex>\n      <Separator />\n      <AddPost />\n      <Separator />\n      <Flex wrap=\"wrap\">\n        <Box flex={1} borderRight=\"1px solid #eee\">\n          <Box p={4} borderBottom=\"1px solid #eee\">\n            <Heading size=\"sm\">Posts</Heading>\n          </Box>\n          <Box p={4}>\n            <PostList />\n          </Box>\n        </Box>\n        <Box flex={2}>\n          <Routes>\n            <Route path=\"posts/:id\" element={<PostDetail />} />\n            <Route\n              index\n              element={\n                <Center h=\"200px\">\n                  <Heading size=\"md\">Select a post to edit!</Heading>\n                </Center>\n              }\n            />\n          </Routes>\n        </Box>\n      </Flex>\n    </Box>\n  );\n};\n\nexport default PostsManager;\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/features/posts/PostsView.tsx",
    "content": "import * as React from 'react';\nimport { Route, Routes } from 'react-router-dom';\nimport { PostsManager } from '../../features/posts/PostsManager';\nimport { Box, Heading } from '@chakra-ui/react';\n\nfunction PostsView() {\n  return (\n    <Box as=\"section\" p=\"2\">\n      <Heading as=\"h2\">Posts Demo</Heading>\n      <Routes>\n        <Route path=\"/*\" element={<PostsManager />} />\n      </Routes>\n    </Box>\n  );\n}\n\nexport default PostsView;\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/index.css",
    "content": "body {\n  margin: 0;\n  font-family:\n    -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',\n    'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n  font-family:\n    source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;\n}\n\nsection {\n  display: block;\n  max-width: 65%;\n}\n\n.pokemon-list {\n  display: flex;\n  flex-flow: row wrap;\n  overflow-x: hidden;\n}\n\n.pokemon {\n  padding: 0.2em;\n  text-align: center;\n}\n\npre code {\n  white-space: pre-wrap;\n}\n\narticle {\n  padding: 0 0 0.5em;\n}\n\n.link.link {\n  color: #805ad5;\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/index.tsx",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport { Provider } from 'react-redux';\nimport { Provider as ChakraProvider } from './components/ui/provider';\nimport './index.css';\nimport { store } from './store';\nimport DevTools from './features/DevTools/DevTools';\nimport { BrowserRouter } from 'react-router-dom';\nimport { App } from './App';\nimport { worker } from './mocks/browser';\nimport { Toaster } from './components/ui/toaster';\n\nfunction renderApp() {\n  const rootElement = document.getElementById('root');\n  const root = ReactDOM.createRoot(rootElement!);\n  root.render(\n    <Provider store={store}>\n      <ChakraProvider>\n        <BrowserRouter>\n          <App />\n          <Toaster />\n          <DevTools />\n        </BrowserRouter>\n      </ChakraProvider>\n    </Provider>,\n  );\n}\n\nworker.start({ quiet: true }).then(renderApp, renderApp);\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/mocks/browser.ts",
    "content": "import { setupWorker } from 'msw/browser';\nimport { handlers } from './db';\n\nexport const worker = setupWorker(...handlers);\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/mocks/db.ts",
    "content": "import { factory, primaryKey } from '@mswjs/data';\nimport { nanoid } from '@reduxjs/toolkit';\nimport { http, HttpResponse, delay } from 'msw';\nimport { Post } from '../services/posts';\n\nconst db = factory({\n  post: {\n    id: primaryKey(String),\n    name: String,\n  },\n});\n\n[\n  'A sample post',\n  'A post about RTK Query',\n  'How to randomly throw errors, a novella',\n].forEach((name) => {\n  db.post.create({ id: nanoid(), name });\n});\n\nexport const handlers = [\n  http.post<never, Post, Post | { error: string }>(\n    '/posts',\n    async ({ request }) => {\n      const { name } = await request.json();\n\n      if (Math.random() < 0.3) {\n        await delay(300);\n        return HttpResponse.json(\n          { error: 'Oh no, there was an error, try again.' },\n          { status: 500 },\n        );\n      }\n\n      const post = db.post.create({\n        id: nanoid(),\n        name,\n      });\n\n      await delay(300);\n      return HttpResponse.json(post);\n    },\n  ),\n  http.put<{ id: string }, Post, Post | { error: string }>(\n    '/posts/:id',\n    async ({ params, request }) => {\n      const { name } = await request.json();\n\n      if (Math.random() < 0.3) {\n        await delay(300);\n        return HttpResponse.json(\n          { error: 'Oh no, there was an error, try again.' },\n          { status: 500 },\n        );\n      }\n\n      const post = db.post.update({\n        where: { id: { equals: params.id } },\n        data: { name },\n      });\n\n      await delay(300);\n      return HttpResponse.json(post);\n    },\n  ),\n  ...db.post.toHandlers('rest'),\n] as const;\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/pokemon.data.ts",
    "content": "export const POKEMON_NAMES = [\n  'bulbasaur',\n  'ivysaur',\n  'venusaur',\n  'charmander',\n  'charmeleon',\n  'charizard',\n  'squirtle',\n  'wartortle',\n  'blastoise',\n  'caterpie',\n  'metapod',\n  'butterfree',\n  'weedle',\n  'kakuna',\n  'beedrill',\n  'pidgey',\n  'pidgeotto',\n  'pidgeot',\n  'rattata',\n  'raticate',\n  'spearow',\n  'fearow',\n  'ekans',\n  'arbok',\n  'pikachu',\n  'raichu',\n  'sandshrew',\n  'sandslash',\n  'nidoran',\n  'nidorina',\n  'nidoqueen',\n  'nidoran',\n  'nidorino',\n  'nidoking',\n  'clefairy',\n  'clefable',\n  'vulpix',\n  'ninetales',\n  'jigglypuff',\n  'wigglytuff',\n  'zubat',\n  'golbat',\n  'oddish',\n  'gloom',\n  'vileplume',\n  'paras',\n  'parasect',\n  'venonat',\n  'venomoth',\n  'diglett',\n  'dugtrio',\n  'meowth',\n  'persian',\n  'psyduck',\n  'golduck',\n  'mankey',\n  'primeape',\n  'growlithe',\n  'arcanine',\n  'poliwag',\n  'poliwhirl',\n  'poliwrath',\n  'abra',\n  'kadabra',\n  'alakazam',\n  'machop',\n  'machoke',\n  'machamp',\n  'bellsprout',\n  'weepinbell',\n  'victreebel',\n  'tentacool',\n  'tentacruel',\n  'geodude',\n  'graveler',\n  'golem',\n  'ponyta',\n  'rapidash',\n  'slowpoke',\n  'slowbro',\n  'magnemite',\n  'magneton',\n  \"farfetch'd\",\n  'doduo',\n  'dodrio',\n  'seel',\n  'dewgong',\n  'grimer',\n  'muk',\n  'shellder',\n  'cloyster',\n  'gastly',\n  'haunter',\n  'gengar',\n  'onix',\n  'drowzee',\n  'hypno',\n  'krabby',\n  'kingler',\n  'voltorb',\n  'electrode',\n  'exeggcute',\n  'exeggutor',\n  'cubone',\n  'marowak',\n  'hitmonlee',\n  'hitmonchan',\n  'lickitung',\n  'koffing',\n  'weezing',\n  'rhyhorn',\n  'rhydon',\n  'chansey',\n  'tangela',\n  'kangaskhan',\n  'horsea',\n  'seadra',\n  'goldeen',\n  'seaking',\n  'staryu',\n  'starmie',\n  'mr. mime',\n  'scyther',\n  'jynx',\n  'electabuzz',\n  'magmar',\n  'pinsir',\n  'tauros',\n  'magikarp',\n  'gyarados',\n  'lapras',\n  'ditto',\n  'eevee',\n  'vaporeon',\n  'jolteon',\n  'flareon',\n  'porygon',\n  'omanyte',\n  'omastar',\n  'kabuto',\n  'kabutops',\n  'aerodactyl',\n  'snorlax',\n  'articuno',\n  'zapdos',\n  'moltres',\n  'dratini',\n  'dragonair',\n  'dragonite',\n  'mewtwo',\n  'mew',\n] as const;\n\nexport type PokemonName = (typeof POKEMON_NAMES)[number];\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/react-app-env.d.ts",
    "content": "declare module '@redux-devtools/app';\n\ndeclare module 'remote-redux-devtools';\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/services/pokemon.ts",
    "content": "import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';\nimport type { PokemonName } from '../pokemon.data';\n\nexport const pokemonApi = createApi({\n  reducerPath: 'pokemonApi',\n  baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }),\n  tagTypes: ['pokemon'],\n  endpoints: (builder) => ({\n    getPokemonByName: builder.query({\n      query: (name: PokemonName) => `pokemon/${name}`,\n      providesTags: (result, error, name: PokemonName) => [\n        { type: 'pokemon' },\n        { type: 'pokemon', id: name },\n      ],\n    }),\n  }),\n});\n\n// Export hooks for usage in functional components\nexport const { useGetPokemonByNameQuery } = pokemonApi;\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/services/posts.ts",
    "content": "import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';\n\nexport interface Post {\n  id: string;\n  name: string;\n}\n\ntype PostsResponse = Post[];\n\nexport const postsApi = createApi({\n  reducerPath: 'postsApi',\n  baseQuery: fetchBaseQuery({ baseUrl: '/' }),\n  tagTypes: ['Post'],\n  endpoints: (build) => ({\n    getPosts: build.query<PostsResponse, void>({\n      query: () => 'posts',\n      providesTags: (result) =>\n        result\n          ? [\n              ...result.map(({ id }) => ({ type: 'Post' as const, id })),\n              { type: 'Post', id: 'LIST' },\n            ]\n          : [{ type: 'Post', id: 'LIST' }],\n    }),\n    addPost: build.mutation<Post, Partial<Post>>({\n      query: (body) => ({\n        url: `posts`,\n        method: 'POST',\n        body,\n      }),\n      invalidatesTags: [{ type: 'Post', id: 'LIST' }],\n    }),\n    getPost: build.query<Post, string>({\n      query: (id) => `posts/${id}`,\n      providesTags: (result, error, id) => [{ type: 'Post', id }],\n    }),\n    updatePost: build.mutation<void, Pick<Post, 'id'> & Partial<Post>>({\n      query: ({ id, ...patch }) => ({\n        url: `posts/${id}`,\n        method: 'PUT',\n        body: patch,\n      }),\n      invalidatesTags: (result, error, { id }) => [{ type: 'Post', id }],\n    }),\n    deletePost: build.mutation<{ success: boolean; id: number }, string>({\n      query(id) {\n        return {\n          url: `posts/${id}`,\n          method: 'DELETE',\n        };\n      },\n      invalidatesTags: (result, error, id) => [{ type: 'Post', id }],\n    }),\n  }),\n});\n\nexport const {\n  useGetPostQuery,\n  useGetPostsQuery,\n  useAddPostMutation,\n  useUpdatePostMutation,\n  useDeletePostMutation,\n} = postsApi;\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/src/store.ts",
    "content": "import {\n  configureStore,\n  combineReducers,\n  EnhancedStore,\n} from '@reduxjs/toolkit';\nimport { pokemonApi } from './services/pokemon';\nimport { postsApi } from './services/posts';\nimport DevTools from './features/DevTools/DevTools';\nimport { isExtensionEnabled } from './features/DevTools/helpers';\n\nconst devTools = isExtensionEnabled();\n\nconst reducer = combineReducers({\n  [pokemonApi.reducerPath]: pokemonApi.reducer,\n  [postsApi.reducerPath]: postsApi.reducer,\n});\n\nexport const store: EnhancedStore<ReturnType<typeof reducer>> = configureStore({\n  reducer,\n  devTools,\n  // adding the api middleware enables caching, invalidation, polling and other features of `rtk-query`\n  middleware: (getDefaultMiddleware) =>\n    getDefaultMiddleware().concat([pokemonApi.middleware, postsApi.middleware]),\n  enhancers: devTools\n    ? undefined\n    : (getDefaultEnhancers) =>\n        getDefaultEnhancers().concat(DevTools.instrument()),\n});\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../tsconfig.react.base.json\",\n  \"compilerOptions\": {\n    \"resolveJsonModule\": true\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/tsconfig.webpack.json",
    "content": "{\n  \"extends\": \"../../../tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"resolveJsonModule\": true,\n    \"types\": [\"node\", \"webpack-dev-server\"]\n  },\n  \"include\": [\"webpack.config.ts\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/demo/webpack.config.ts",
    "content": "import * as path from 'path';\nimport * as webpack from 'webpack';\nimport HtmlWebpackPlugin from 'html-webpack-plugin';\nimport ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';\nimport CopyWebpackPlugin from 'copy-webpack-plugin';\nimport pkg from '@redux-devtools/rtk-query-monitor/package.json';\n\nconst config: webpack.Configuration = {\n  mode: 'development',\n  entry: './src/index.tsx',\n  devtool: 'eval-source-map',\n  devServer: {\n    static: './dist',\n  },\n  plugins: [\n    new HtmlWebpackPlugin({\n      template: './index.html',\n      package: pkg,\n    }),\n    new ForkTsCheckerWebpackPlugin(),\n    new CopyWebpackPlugin({\n      patterns: [\n        {\n          from: 'public',\n          to: '.',\n        },\n      ],\n    }),\n  ],\n  output: {\n    filename: 'bundle.js',\n    path: path.join(__dirname, 'dist'),\n    clean: true,\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.(js|ts)x?$/,\n        exclude: /node_modules/,\n        use: {\n          loader: 'babel-loader',\n          options: {\n            presets: [\n              ['@babel/preset-env', { targets: 'defaults' }],\n              '@babel/preset-react',\n              '@babel/preset-typescript',\n            ],\n            plugins: ['@babel/plugin-transform-runtime'],\n          },\n        },\n      },\n      {\n        test: /\\.css$/i,\n        use: ['style-loader', 'css-loader'],\n      },\n    ],\n  },\n  resolve: {\n    extensions: ['.js', '.jsx', '.ts', '.tsx'],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/eslint.config.mjs",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTsReact from '../../eslint.ts.react.config.base.mjs';\nimport eslintTsReactJest from '../../eslint.ts.react.jest.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTsReact(import.meta.dirname),\n  ...eslintTsReactJest(import.meta.dirname),\n  {\n    ignores: ['demo', 'jest.config.ts', 'lib'],\n  },\n  {\n    files: ['**/*.ts', '**/*.tsx'],\n    rules: {\n      'react/no-unknown-property': ['error', { ignore: ['css'] }],\n    },\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/jest.config.ts",
    "content": "import { createDefaultEsmPreset, type JestConfigWithTsJest } from 'ts-jest';\n\nconst presetConfig = createDefaultEsmPreset({\n  tsconfig: 'tsconfig.test.json',\n});\n\nconst jestConfig: JestConfigWithTsJest = {\n  ...presetConfig,\n  testEnvironment: 'jsdom',\n  moduleNameMapper: {\n    '^(\\\\.{1,2}/.*)\\\\.js$': '$1',\n    '\\\\.css$': '<rootDir>/test/__mocks__/styleMock.ts',\n  },\n};\n\nexport default jestConfig;\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/package.json",
    "content": "{\n  \"name\": \"@redux-devtools/rtk-query-monitor\",\n  \"version\": \"7.0.0\",\n  \"description\": \"rtk-query monitor for Redux DevTools\",\n  \"keywords\": [\n    \"redux\",\n    \"devtools\",\n    \"flux\",\n    \"react\",\n    \"redux-toolkit\",\n    \"rtk-query\"\n  ],\n  \"homepage\": \"https://github.com/FaberVitale/redux-devtools/tree/feat/rtk-query-monitor/packages/redux-devtools-rtk-query-monitor\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": {\n    \"name\": \"FaberVitale\",\n    \"url\": \"https://github.com/FaberVitale\"\n  },\n  \"files\": [\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": {\n    \".\": \"./lib/index.js\",\n    \"./package.json\": \"./package.json\"\n  },\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"test\": \"node --experimental-vm-modules node_modules/jest/bin/jest.js\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run type-check && pnpm run lint && pnpm run test\"\n  },\n  \"dependencies\": {\n    \"@redux-devtools/ui\": \"workspace:^\",\n    \"@types/lodash\": \"^4.17.24\",\n    \"hex-rgba\": \"^1.0.2\",\n    \"immutable\": \"^5.1.5\",\n    \"lodash.debounce\": \"^4.0.8\",\n    \"react-base16-styling\": \"workspace:^\",\n    \"react-json-tree\": \"workspace:^\"\n  },\n  \"devDependencies\": {\n    \"@emotion/react\": \"^11.14.0\",\n    \"@emotion/styled\": \"^11.14.1\",\n    \"@jest/globals\": \"^30.3.0\",\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@reduxjs/toolkit\": \"^2.11.2\",\n    \"@testing-library/dom\": \"^10.4.1\",\n    \"@testing-library/jest-dom\": \"^6.9.1\",\n    \"@testing-library/react\": \"^16.3.2\",\n    \"@types/jest\": \"^30.0.0\",\n    \"@types/hex-rgba\": \"^1.0.3\",\n    \"@types/lodash.debounce\": \"^4.0.9\",\n    \"@types/react\": \"^19.2.14\",\n    \"jest\": \"^30.3.0\",\n    \"jest-environment-jsdom\": \"^30.3.0\",\n    \"react\": \"^19.2.4\",\n    \"react-dom\": \"^19.2.4\",\n    \"react-redux\": \"^9.2.0\",\n    \"redux\": \"^5.0.1\",\n    \"rimraf\": \"^6.1.3\",\n    \"ts-jest\": \"^29.4.6\",\n    \"typescript\": \"~5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"@emotion/react\": \"^11.14.0\",\n    \"@emotion/styled\": \"^11.14.1\",\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@reduxjs/toolkit\": \"^1.0.0 || ^2.0.0\",\n    \"@types/react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react\": \"^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"redux\": \"^3.4.0 || ^4.0.0 || ^5.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/components/ArrowUpIcon.tsx",
    "content": "import React, { HTMLAttributes } from 'react';\n\nexport type ArrowUpIconProps = Omit<\n  HTMLAttributes<SVGElement>,\n  'xmlns' | 'children' | 'viewBox'\n>;\n\n/* eslint-disable max-len */\n/**\n * @see https://icons.getbootstrap.com/icons/arrow-up/\n */\nexport function ArrowUpIcon(props: ArrowUpIconProps): React.JSX.Element {\n  return (\n    <svg\n      fill=\"currentColor\"\n      {...props}\n      xmlns=\"http://www.w3.org/2000/svg\"\n      viewBox=\"0 0 16 16\"\n    >\n      <path\n        fillRule=\"evenodd\"\n        d=\"M8 15a.5.5 0 0 0 .5-.5V2.707l3.146 3.147a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 1 0 .708.708L7.5 2.707V14.5a.5.5 0 0 0 .5.5z\"\n      />\n    </svg>\n  );\n}\n/* eslint-enable max-len */\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/components/NoRtkQueryApi.tsx",
    "content": "import React from 'react';\n\nexport function NoRtkQueryApi(): React.JSX.Element {\n  return (\n    <div\n      css={(theme) => ({\n        width: '100%',\n        textAlign: 'center',\n        color: theme.TEXT_COLOR,\n        padding: '1.4em',\n        '& a': {\n          fontSize: 'inherit',\n          color: theme.TEXT_COLOR,\n          textDecoration: 'underline',\n        },\n      })}\n    >\n      No rtk-query api found.\n      <br />\n      Make sure to follow{' '}\n      <a\n        href=\"https://redux-toolkit.js.org/rtk-query/overview#basic-usage\"\n        target=\"_blank\"\n        rel=\"noreferrer noopener\"\n      >\n        the instructions\n      </a>\n      .\n    </div>\n  );\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/components/QueryForm.tsx",
    "content": "import React, { ReactNode, FormEvent, MouseEvent, ChangeEvent } from 'react';\nimport type { DebouncedFunc } from 'lodash';\nimport { css } from '@emotion/react';\nimport { Select } from '@redux-devtools/ui';\nimport { QueryFormValues } from '../types.js';\nimport { StyleUtilsContext } from '../styles/themes.js';\nimport { SelectOption } from '../types.js';\nimport debounce from 'lodash.debounce';\nimport { sortQueryOptions, QueryComparators } from '../utils/comparators.js';\nimport { QueryFilters, filterQueryOptions } from '../utils/filters.js';\nimport { SortOrderButton } from './SortOrderButton.js';\nimport { RegexIcon } from './RegexIcon.js';\n\nconst srOnlyCss = css({\n  position: 'absolute',\n  width: 1,\n  height: 1,\n  padding: 0,\n  margin: '-1px',\n  overflow: 'hidden',\n  clip: 'rect(0,0,0,0)',\n  border: 0,\n});\n\nexport interface QueryFormProps {\n  values: QueryFormValues;\n  searchQueryRegex: RegExp | null;\n  onFormValuesChange: (values: Partial<QueryFormValues>) => void;\n}\n\ninterface QueryFormState {\n  searchValue: string;\n}\n\nconst selectId = 'rtk-query-comp-select';\nconst searchId = 'rtk-query-search-query';\nconst filterSelectId = 'rtk-query-search-query-select';\nconst searchPlaceholder = 'filter query by...';\n\nconst labels = {\n  regexToggle: {\n    info: 'Use regular expression search',\n    error: 'Invalid regular expression provided',\n  },\n};\n\nexport class QueryForm extends React.PureComponent<\n  QueryFormProps,\n  QueryFormState\n> {\n  constructor(props: QueryFormProps) {\n    super(props);\n\n    this.state = {\n      searchValue: props.values.searchValue,\n    };\n  }\n\n  inputSearchRef = React.createRef<HTMLInputElement>();\n\n  handleSubmit = (evt: FormEvent<HTMLFormElement>): void => {\n    evt.preventDefault();\n  };\n\n  handleButtonGroupClick = (isAsc: boolean): void => {\n    this.props.onFormValuesChange({ isAscendingQueryComparatorOrder: isAsc });\n  };\n\n  handleSelectComparatorChange = (\n    option: SelectOption<QueryComparators> | undefined | null,\n  ): void => {\n    if (typeof option?.value === 'string') {\n      this.props.onFormValuesChange({ queryComparator: option.value });\n    }\n  };\n\n  handleSelectFilterChange = (\n    option: SelectOption<QueryFilters> | undefined | null,\n  ): void => {\n    if (typeof option?.value === 'string') {\n      this.props.onFormValuesChange({ queryFilter: option.value });\n    }\n  };\n\n  handleRegexSearchClick = (): void => {\n    this.props.onFormValuesChange({\n      isRegexSearch: !this.props.values.isRegexSearch,\n    });\n  };\n\n  restoreCaretPosition = (start: number | null, end: number | null): void => {\n    window.requestAnimationFrame(() => {\n      if (this.inputSearchRef.current) {\n        this.inputSearchRef.current.selectionStart = start;\n        this.inputSearchRef.current.selectionEnd = end;\n      }\n    });\n  };\n\n  invalidateSearchValueFromProps: DebouncedFunc<() => void> = debounce(() => {\n    this.props.onFormValuesChange({\n      searchValue: this.state.searchValue,\n    });\n  }, 150);\n\n  handleSearchChange = (evt: ChangeEvent<HTMLInputElement>): void => {\n    const searchValue = evt.target.value.trim();\n    this.setState({ searchValue });\n    this.invalidateSearchValueFromProps();\n  };\n\n  handleClearSearchClick = (evt: MouseEvent<HTMLButtonElement>): void => {\n    evt.preventDefault();\n\n    if (this.state.searchValue) {\n      this.setState({ searchValue: '' });\n      this.invalidateSearchValueFromProps();\n    }\n  };\n\n  render(): ReactNode {\n    const {\n      searchQueryRegex,\n      values: {\n        isAscendingQueryComparatorOrder: isAsc,\n        queryComparator,\n        searchValue,\n        queryFilter,\n        isRegexSearch,\n      },\n    } = this.props;\n\n    const isRegexInvalid =\n      isRegexSearch && searchValue.length > 0 && searchQueryRegex == null;\n    const regexToggleType = isRegexInvalid ? 'error' : 'info';\n    const regexToggleLabel = labels.regexToggle[regexToggleType];\n\n    return (\n      <StyleUtilsContext.Consumer>\n        {({ base16Theme }) => {\n          return (\n            <form\n              id=\"rtk-query-monitor-query-selection-form\"\n              action=\"#\"\n              onSubmit={this.handleSubmit}\n              css={{\n                display: 'flex',\n                flexFlow: 'column nowrap',\n              }}\n            >\n              <div\n                css={(theme) => ({\n                  display: 'flex',\n                  padding: 4,\n                  flex: '0 0 auto',\n                  alignItems: 'center',\n                  borderBottomWidth: '1px',\n                  borderBottomStyle: 'solid',\n\n                  borderColor: theme.LIST_BORDER_COLOR,\n                })}\n              >\n                <label htmlFor={searchId} css={srOnlyCss}>\n                  filter query\n                </label>\n                <div\n                  css={(theme) => ({\n                    maxWidth: '65%',\n                    backgroundColor: theme.BACKGROUND_COLOR,\n                    display: 'flex',\n                    alignItems: 'center',\n                    flexFlow: 'row nowrap',\n                    flex: '1 1 auto',\n                    paddingRight: 6,\n                    '& input': {\n                      outline: 'none',\n                      border: 'none',\n                      width: '100%',\n                      flex: '1 1 auto',\n                      padding: '5px 10px',\n                      fontSize: '1em',\n                      position: 'relative',\n                      fontFamily:\n                        'monaco, Consolas, \"Lucida Console\", monospace',\n\n                      backgroundColor: theme.BACKGROUND_COLOR,\n                      color: theme.TEXT_COLOR,\n\n                      '&::-webkit-input-placeholder': {\n                        color: theme.TEXT_PLACEHOLDER_COLOR,\n                      },\n\n                      '&::-moz-placeholder': {\n                        color: theme.TEXT_PLACEHOLDER_COLOR,\n                      },\n                      '&::-webkit-search-cancel-button': {\n                        WebkitAppearance: 'none',\n                      },\n                    },\n                  })}\n                >\n                  <input\n                    ref={this.inputSearchRef}\n                    type=\"search\"\n                    value={this.state.searchValue}\n                    onChange={this.handleSearchChange}\n                    placeholder={searchPlaceholder}\n                  />\n                  <button\n                    type=\"reset\"\n                    aria-label=\"clear search\"\n                    data-invisible={\n                      +(this.state.searchValue.length === 0) || undefined\n                    }\n                    onClick={this.handleClearSearchClick}\n                    css={(theme) => ({\n                      WebkitAppearance: 'none',\n                      border: 'none',\n                      outline: 'none',\n                      boxShadow: 'none',\n                      display: 'block',\n                      flex: '0 0 auto',\n                      cursor: 'pointer',\n                      background: 'transparent',\n                      position: 'relative',\n                      fontSize: 'inherit',\n                      '&[data-invisible=\"1\"]': {\n                        visibility: 'hidden !important' as 'hidden',\n                      },\n                      '&::after': {\n                        content: '\"\\u00d7\"',\n                        display: 'block',\n                        padding: 4,\n                        fontSize: '1.2em',\n                        color: theme.TEXT_PLACEHOLDER_COLOR,\n                        background: 'transparent',\n                      },\n                      '&:hover::after': {\n                        color: theme.TEXT_COLOR,\n                      },\n                    })}\n                  />\n                  <button\n                    type=\"button\"\n                    aria-label={regexToggleLabel}\n                    title={regexToggleLabel}\n                    data-type={regexToggleType}\n                    aria-pressed={isRegexSearch}\n                    onClick={this.handleRegexSearchClick}\n                    css={(theme) => ({\n                      width: '24px',\n                      height: '24px',\n                      display: 'inline-block',\n                      flex: '0 0 auto',\n                      color: theme.TEXT_PLACEHOLDER_COLOR,\n                      cursor: 'pointer',\n                      padding: 0,\n                      fontSize: '0.7em',\n                      letterSpacing: '-0.7px',\n                      outline: 'none',\n                      boxShadow: 'none',\n                      fontWeight: '700',\n                      border: 'none',\n\n                      '&:hover': {\n                        color: theme.TEXT_COLOR,\n                      },\n\n                      backgroundColor: 'transparent',\n                      '&[aria-pressed=\"true\"]': {\n                        color: theme.BACKGROUND_COLOR,\n                        backgroundColor: theme.TEXT_COLOR,\n                      },\n\n                      '&[data-type=\"error\"]': {\n                        color: theme.TEXT_COLOR,\n                        backgroundColor: theme.TOGGLE_BUTTON_ERROR,\n                      },\n                    })}\n                  >\n                    <RegexIcon />\n                  </button>\n                </div>\n                <label htmlFor={selectId} css={srOnlyCss}>\n                  filter by\n                </label>\n                <Select<SelectOption<QueryFilters>>\n                  id={filterSelectId}\n                  isSearchable={false}\n                  options={filterQueryOptions}\n                  theme={base16Theme as any}\n                  value={filterQueryOptions.find(\n                    (opt) => opt?.value === queryFilter,\n                  )}\n                  onChange={this.handleSelectFilterChange}\n                />\n              </div>\n              <div\n                css={{\n                  display: 'flex',\n                  padding: '0.4em',\n                  '& label': {\n                    display: 'flex',\n                    flex: '0 0 auto',\n                    whiteSpace: 'nowrap',\n                    alignItems: 'center',\n                    paddingRight: '0.4em',\n                  },\n\n                  '& > :last-child': {\n                    flex: '0 0 auto',\n                    marginLeft: '0.4em',\n                  },\n                }}\n              >\n                <label htmlFor={selectId}>Sort by</label>\n                <Select<SelectOption<QueryComparators>>\n                  id={selectId}\n                  isSearchable={false}\n                  theme={base16Theme as any}\n                  value={sortQueryOptions.find(\n                    (opt) => opt?.value === queryComparator,\n                  )}\n                  options={sortQueryOptions}\n                  onChange={this.handleSelectComparatorChange}\n                />\n                <SortOrderButton\n                  id={'rtk-query-sort-order-button'}\n                  isAsc={isAsc}\n                  onChange={this.handleButtonGroupClick}\n                />\n              </div>\n            </form>\n          );\n        }}\n      </StyleUtilsContext.Consumer>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/components/QueryList.tsx",
    "content": "import React, { PureComponent, ReactNode } from 'react';\nimport type { Interpolation, Theme } from '@emotion/react';\nimport { RtkResourceInfo, RtkQueryMonitorState } from '../types.js';\nimport { isQuerySelected } from '../utils/rtk-query.js';\n\nconst queryStatusCss: Interpolation<Theme> = (theme) => ({\n  display: 'inline-flex',\n  alignItems: 'center',\n  justifyContent: 'center',\n  height: 22,\n  padding: '0 6px',\n  borderRadius: '3px',\n  fontSize: '0.7em',\n  lineHeight: '1em',\n  flexShrink: 0,\n  fontWeight: 700,\n  backgroundColor: theme.ACTION_TIME_BACK_COLOR,\n  color: theme.ACTION_TIME_COLOR,\n});\n\nexport interface QueryListProps {\n  resInfos: RtkResourceInfo[];\n  selectedQueryKey: RtkQueryMonitorState['selectedQueryKey'];\n  onSelectQuery: (query: RtkResourceInfo) => void;\n}\n\nexport class QueryList extends PureComponent<QueryListProps> {\n  static isItemSelected(\n    selectedQueryKey: QueryListProps['selectedQueryKey'],\n    queryInfo: RtkResourceInfo,\n  ): boolean {\n    return (\n      !!selectedQueryKey &&\n      selectedQueryKey.queryKey === queryInfo.queryKey &&\n      selectedQueryKey.reducerPath === queryInfo.reducerPath\n    );\n  }\n\n  static formatQuery(resInfo: RtkResourceInfo): string {\n    const key =\n      resInfo.type === 'query'\n        ? resInfo.queryKey\n        : `${resInfo.state.endpointName ?? ''} ${resInfo.queryKey}`;\n\n    return key;\n  }\n\n  render(): ReactNode {\n    const { resInfos, selectedQueryKey, onSelectQuery } = this.props;\n\n    return (\n      <ul css={{ listStyle: 'none', margin: '0', padding: '0' }}>\n        {resInfos.map((resInfo) => {\n          const isSelected = isQuerySelected(selectedQueryKey, resInfo);\n\n          return (\n            <li\n              key={resInfo.queryKey}\n              onClick={() => onSelectQuery(resInfo)}\n              css={[\n                (theme) => ({\n                  borderBottomWidth: '1px',\n                  borderBottomStyle: 'solid',\n                  display: 'flex',\n                  justifyContent: 'space-between',\n                  padding: '5px 10px',\n                  cursor: 'pointer',\n                  userSelect: 'none',\n                  '&:last-child': {\n                    borderBottomWidth: 0,\n                  },\n                  overflow: 'hidden',\n                  maxHeight: 47,\n                  borderBottomColor: theme.BORDER_COLOR,\n                }),\n                isSelected &&\n                  ((theme) => ({\n                    backgroundColor: theme.SELECTED_BACKGROUND_COLOR,\n                  })),\n              ]}\n            >\n              <p\n                css={{\n                  display: '-webkit-box',\n                  WebkitBoxOrient: 'vertical',\n                  WebkitLineClamp: 2,\n                  whiteSpace: 'normal',\n                  overflow: 'hidden',\n                  width: '100%',\n                  maxWidth: 'calc(100% - 70px)',\n                  wordBreak: 'break-all',\n                  margin: 0,\n                }}\n              >\n                {QueryList.formatQuery(resInfo)}\n              </p>\n              <div\n                css={{\n                  display: 'flex',\n                  width: 'auto',\n                  justifyContent: 'center',\n                  alignItems: 'center',\n                  margin: 0,\n                  flex: '0 0 auto',\n                  overflow: 'hidden',\n                }}\n              >\n                <strong css={[queryStatusCss, { marginRight: 4 }]}>\n                  {resInfo.type === 'query' ? 'Q' : 'M'}\n                </strong>\n                <p css={queryStatusCss}>{resInfo.state.status}</p>\n              </div>\n            </li>\n          );\n        })}\n      </ul>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/components/QueryPreviewActions.tsx",
    "content": "import { createSelector, Selector } from '@reduxjs/toolkit';\nimport React, { ReactNode, PureComponent } from 'react';\nimport { Action, AnyAction } from 'redux';\nimport type { KeyPath, ShouldExpandNodeInitially } from 'react-json-tree';\nimport { QueryPreviewTabs } from '../types.js';\nimport { renderTabPanelButtonId, renderTabPanelId } from '../utils/a11y.js';\nimport { emptyRecord, identity } from '../utils/object.js';\nimport { TreeView, TreeViewProps } from './TreeView.js';\n\nexport interface QueryPreviewActionsProps {\n  isWideLayout: boolean;\n  actionsOfQuery: AnyAction[];\n}\n\nconst keySep = ' - ';\n\nconst rootProps: TreeViewProps['rootProps'] = {\n  'aria-labelledby': renderTabPanelButtonId(QueryPreviewTabs.actions),\n  id: renderTabPanelId(QueryPreviewTabs.actions),\n  role: 'tabpanel',\n};\n\nexport class QueryPreviewActions extends PureComponent<QueryPreviewActionsProps> {\n  selectFormattedActions: Selector<\n    AnyAction[],\n    Record<string, AnyAction>,\n    never\n  > = createSelector<\n    [(actions: AnyAction[]) => AnyAction[]],\n    Record<string, AnyAction>\n  >(identity, (actions) => {\n    const output: Record<string, AnyAction> = {};\n\n    if (actions.length === 0) {\n      return emptyRecord;\n    }\n\n    for (let i = 0, len = actions.length; i < len; i++) {\n      const action = actions[i];\n      const key = `${i}${keySep}${(action as Action<string>)?.type ?? ''}`;\n      output[key] = action;\n    }\n\n    return output;\n  });\n\n  isLastActionNode = (keyPath: KeyPath, layer: number): boolean => {\n    if (layer >= 1) {\n      const len = this.props.actionsOfQuery.length;\n      const actionKey = keyPath[keyPath.length - 1];\n\n      if (typeof actionKey === 'string') {\n        const index = Number(actionKey.split(keySep)[0]);\n\n        return len > 0 && len - index < 2;\n      }\n    }\n\n    return false;\n  };\n\n  shouldExpandNodeInitially: ShouldExpandNodeInitially = (\n    keyPath,\n    value,\n    layer,\n  ) => {\n    if (layer === 1) {\n      return this.isLastActionNode(keyPath, layer);\n    }\n\n    if (layer === 2) {\n      return (\n        this.isLastActionNode(keyPath, layer) &&\n        (keyPath[0] === 'meta' || keyPath[0] === 'error')\n      );\n    }\n\n    return layer <= 1;\n  };\n\n  render(): ReactNode {\n    const { isWideLayout, actionsOfQuery } = this.props;\n\n    return (\n      <TreeView\n        rootProps={rootProps}\n        data={this.selectFormattedActions(actionsOfQuery)}\n        isWideLayout={isWideLayout}\n        shouldExpandNodeInitially={this.shouldExpandNodeInitially}\n      />\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/components/QueryPreviewApi.tsx",
    "content": "import React, { ReactNode, PureComponent } from 'react';\nimport type { ShouldExpandNodeInitially } from 'react-json-tree';\nimport { ApiStats, QueryPreviewTabs, RtkQueryApiState } from '../types.js';\nimport { TreeView, TreeViewProps } from './TreeView.js';\nimport { renderTabPanelId, renderTabPanelButtonId } from '../utils/a11y.js';\n\nexport interface QueryPreviewApiProps {\n  apiStats: ApiStats | null;\n  apiState: RtkQueryApiState | null;\n  isWideLayout: boolean;\n}\n\nconst rootProps: TreeViewProps['rootProps'] = {\n  'aria-labelledby': renderTabPanelButtonId(QueryPreviewTabs.apiConfig),\n  id: renderTabPanelId(QueryPreviewTabs.apiConfig),\n  role: 'tabpanel',\n};\n\nexport class QueryPreviewApi extends PureComponent<QueryPreviewApiProps> {\n  shouldExpandApiStateNode: ShouldExpandNodeInitially = (\n    keyPath,\n    value,\n    layer,\n  ) => {\n    const lastKey = keyPath[keyPath.length - 1];\n\n    return layer <= 1 && lastKey !== 'config';\n  };\n\n  render(): ReactNode {\n    const { apiStats, isWideLayout, apiState } = this.props;\n\n    if (!apiState) {\n      return null;\n    }\n\n    const hasMutations = Object.keys(apiState.mutations).length > 0;\n    const hasQueries = Object.keys(apiState.queries).length > 0;\n\n    return (\n      <article\n        {...rootProps}\n        css={(theme) => ({\n          display: 'block',\n          overflowY: 'auto',\n          padding: '0.5em 0',\n          color: theme.TAB_CONTENT_COLOR,\n          '& h2': {\n            color: theme.ULIST_STRONG_COLOR,\n            padding: '0.5em 1em',\n            fontWeight: 700,\n          },\n          '& h3': {\n            color: theme.ULIST_STRONG_COLOR,\n          },\n        })}\n      >\n        <h2>{apiState.config.reducerPath}</h2>\n        <TreeView\n          before={<h3>State</h3>}\n          data={apiState}\n          shouldExpandNodeInitially={this.shouldExpandApiStateNode}\n          isWideLayout={isWideLayout}\n        />\n        {apiStats && (\n          <>\n            <TreeView\n              before={<h3>Tally</h3>}\n              data={apiStats.tally}\n              isWideLayout={isWideLayout}\n            />\n            {hasQueries && (\n              <TreeView\n                before={<h3>Queries Timings</h3>}\n                data={apiStats.timings.queries}\n                isWideLayout={isWideLayout}\n              />\n            )}\n            {hasMutations && (\n              <TreeView\n                before={<h3>Mutations Timings</h3>}\n                data={apiStats.timings.mutations}\n                isWideLayout={isWideLayout}\n              />\n            )}\n          </>\n        )}\n      </article>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/components/QueryPreviewData.tsx",
    "content": "import React, { ReactNode, PureComponent } from 'react';\nimport type { ShouldExpandNodeInitially } from 'react-json-tree';\nimport { QueryPreviewTabs, RtkResourceInfo } from '../types.js';\nimport { renderTabPanelButtonId, renderTabPanelId } from '../utils/a11y.js';\nimport { TreeView, TreeViewProps } from './TreeView.js';\n\nexport interface QueryPreviewDataProps {\n  data: RtkResourceInfo['state']['data'];\n  isWideLayout: boolean;\n}\n\nconst rootProps: TreeViewProps['rootProps'] = {\n  'aria-labelledby': renderTabPanelButtonId(QueryPreviewTabs.data),\n  id: renderTabPanelId(QueryPreviewTabs.data),\n  role: 'tabpanel',\n};\n\nexport class QueryPreviewData extends PureComponent<QueryPreviewDataProps> {\n  shouldExpandNodeInitially: ShouldExpandNodeInitially = (\n    keyPath,\n    value,\n    layer,\n  ) => {\n    return layer <= 1;\n  };\n\n  render(): ReactNode {\n    const { data, isWideLayout } = this.props;\n\n    return (\n      <TreeView\n        rootProps={rootProps}\n        data={data}\n        isWideLayout={isWideLayout}\n        shouldExpandNodeInitially={this.shouldExpandNodeInitially}\n      />\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/components/QueryPreviewHeader.tsx",
    "content": "import React, { ReactNode } from 'react';\nimport { QueryPreviewTabs, TabOption } from '../types.js';\nimport { renderTabPanelButtonId } from '../utils/a11y.js';\nimport { emptyArray } from '../utils/object.js';\n\nexport interface QueryPreviewHeaderProps {\n  tabs: ReadonlyArray<\n    TabOption<QueryPreviewTabs, unknown, 'query' | 'mutation'>\n  >;\n  onTabChange: (tab: QueryPreviewTabs) => void;\n  selectedTab: QueryPreviewTabs;\n  renderTabLabel?: (tab: QueryPreviewHeaderProps['tabs'][number]) => ReactNode;\n}\n\nexport class QueryPreviewHeader extends React.Component<QueryPreviewHeaderProps> {\n  handleTabClick = (tab: QueryPreviewHeaderProps['tabs'][number]): void => {\n    if (this.props.selectedTab !== tab.value) {\n      this.props.onTabChange(tab.value);\n    }\n  };\n\n  render(): ReactNode {\n    const { tabs, selectedTab, renderTabLabel } = this.props;\n\n    return (\n      <div\n        css={(theme) => ({\n          flex: '0 0 30px',\n          padding: '5px 4px',\n          alignItems: 'center',\n          borderBottomWidth: '1px',\n          borderBottomStyle: 'solid',\n\n          backgroundColor: theme.HEADER_BACKGROUND_COLOR,\n          borderBottomColor: theme.HEADER_BORDER_COLOR,\n        })}\n      >\n        <div\n          css={{\n            display: 'flex',\n            width: '100%',\n            justifyContent: 'flex-end',\n            overflow: 'hidden',\n            '& > *': {\n              flex: '0 1 auto',\n            },\n          }}\n        >\n          {tabs.map((tab) => (\n            <button\n              type=\"button\"\n              id={renderTabPanelButtonId(tab.value)}\n              aria-selected={tab.value === selectedTab}\n              role={'tab'}\n              onClick={() => this.handleTabClick(tab)}\n              key={tab.value}\n              css={[\n                (theme) => ({\n                  cursor: 'pointer',\n                  position: 'relative',\n                  height: '33px',\n                  padding: '0 8px',\n                  display: 'inline-flex',\n                  alignItems: 'center',\n                  boxShadow: 'none',\n                  outline: 'none',\n                  color: theme.TEXT_COLOR,\n                  borderStyle: 'solid',\n                  borderWidth: '1px',\n                  borderLeftWidth: 0,\n\n                  '&:first-of-type': {\n                    borderLeftWidth: '1px',\n                    borderTopLeftRadius: '3px',\n                    borderBottomLeftRadius: '3px',\n                  },\n\n                  '&:last-of-type': {\n                    borderTopRightRadius: '3px',\n                    borderBottomRightRadius: '3px',\n                  },\n\n                  backgroundColor: theme.TAB_BACK_COLOR,\n\n                  '&:hover': {\n                    backgroundColor: theme.TAB_BACK_HOVER_COLOR,\n                  },\n\n                  borderColor: theme.TAB_BORDER_COLOR,\n\n                  '& > *': {\n                    display: '-webkit-box',\n                    boxOrient: 'vertical',\n                    WebkitLineClamp: 1,\n                    overflow: 'hidden',\n                    wordBreak: 'break-all',\n                    WebkitBoxPack: 'end',\n                    paddingBottom: 0,\n                  },\n                }),\n                tab.value === selectedTab &&\n                  ((theme) => ({\n                    backgroundColor: theme.TAB_BACK_SELECTED_COLOR,\n                  })),\n              ]}\n            >\n              <span>{renderTabLabel ? renderTabLabel(tab) : tab.label}</span>\n            </button>\n          ))}\n        </div>\n      </div>\n    );\n  }\n\n  static defaultProps = {\n    tabs: emptyArray,\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/components/QueryPreviewInfo.tsx",
    "content": "import { createSelector, Selector } from '@reduxjs/toolkit';\nimport { QueryStatus } from '@reduxjs/toolkit/query';\nimport React, { ReactNode, PureComponent } from 'react';\nimport type { ShouldExpandNodeInitially } from 'react-json-tree';\nimport { QueryPreviewTabs, RtkResourceInfo, RTKStatusFlags } from '../types.js';\nimport { renderTabPanelButtonId, renderTabPanelId } from '../utils/a11y.js';\nimport { formatMs } from '../utils/formatters.js';\nimport { identity } from '../utils/object.js';\nimport { getQueryStatusFlags } from '../utils/rtk-query.js';\nimport { TreeView, TreeViewProps } from './TreeView.js';\n\ntype QueryTimings = {\n  startedAt: string;\n  loadedAt: string;\n  duration: string;\n};\n\ntype FormattedQuery = {\n  key: string;\n  reducerPath: string;\n  timings: QueryTimings;\n  statusFlags: RTKStatusFlags;\n} & (\n  | { mutation: RtkResourceInfo['state'] }\n  | { query: RtkResourceInfo['state'] }\n);\n\nconst rootProps: TreeViewProps['rootProps'] = {\n  'aria-labelledby': renderTabPanelButtonId(QueryPreviewTabs.queryinfo),\n  id: renderTabPanelId(QueryPreviewTabs.queryinfo),\n  role: 'tabpanel',\n};\n\nexport interface QueryPreviewInfoProps {\n  resInfo: RtkResourceInfo;\n  isWideLayout: boolean;\n}\nexport class QueryPreviewInfo extends PureComponent<QueryPreviewInfoProps> {\n  shouldExpandNodeInitially: ShouldExpandNodeInitially = (\n    keyPath,\n    value,\n    layer,\n  ) => {\n    const lastKey = keyPath[keyPath.length - 1];\n\n    return layer <= 1 && lastKey !== 'query' && lastKey !== 'mutation';\n  };\n\n  selectFormattedQuery: Selector<RtkResourceInfo, FormattedQuery> =\n    createSelector<\n      [(identity: RtkResourceInfo) => RtkResourceInfo],\n      FormattedQuery\n    >(identity, (resInfo: RtkResourceInfo): FormattedQuery => {\n      const { state, queryKey, reducerPath } = resInfo;\n\n      const startedAt = state.startedTimeStamp\n        ? new Date(state.startedTimeStamp).toISOString()\n        : '-';\n\n      const loadedAt = state.fulfilledTimeStamp\n        ? new Date(state.fulfilledTimeStamp).toISOString()\n        : '-';\n\n      const statusFlags = getQueryStatusFlags(state);\n\n      const timings = {\n        startedAt,\n        loadedAt,\n        duration: '-',\n      };\n\n      if (\n        state.fulfilledTimeStamp &&\n        state.startedTimeStamp &&\n        state.status !== QueryStatus.pending &&\n        state.startedTimeStamp <= state.fulfilledTimeStamp\n      ) {\n        timings.duration = formatMs(\n          state.fulfilledTimeStamp - state.startedTimeStamp,\n        );\n      }\n\n      if (resInfo.type === 'query') {\n        return {\n          key: queryKey,\n          reducerPath,\n          query: resInfo.state,\n          statusFlags,\n          timings,\n        };\n      }\n\n      return {\n        key: queryKey,\n        reducerPath,\n        mutation: resInfo.state,\n        statusFlags,\n        timings,\n      };\n    });\n\n  render(): ReactNode {\n    const { resInfo, isWideLayout } = this.props;\n    const formattedQuery = this.selectFormattedQuery(resInfo);\n\n    return (\n      <TreeView\n        rootProps={rootProps}\n        data={formattedQuery}\n        isWideLayout={isWideLayout}\n        shouldExpandNodeInitially={this.shouldExpandNodeInitially}\n      />\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/components/QueryPreviewSubscriptions.tsx",
    "content": "import React, { ReactNode, PureComponent } from 'react';\nimport { QueryPreviewTabs, RtkQueryApiState } from '../types.js';\nimport { renderTabPanelButtonId, renderTabPanelId } from '../utils/a11y.js';\nimport { TreeView, TreeViewProps } from './TreeView.js';\n\nconst rootProps: TreeViewProps['rootProps'] = {\n  'aria-labelledby': renderTabPanelButtonId(\n    QueryPreviewTabs.querySubscriptions,\n  ),\n  id: renderTabPanelId(QueryPreviewTabs.querySubscriptions),\n  role: 'tabpanel',\n};\n\nexport interface QueryPreviewSubscriptionsProps {\n  subscriptions: RtkQueryApiState['subscriptions'][keyof RtkQueryApiState['subscriptions']];\n  isWideLayout: boolean;\n}\n\nexport class QueryPreviewSubscriptions extends PureComponent<QueryPreviewSubscriptionsProps> {\n  render(): ReactNode {\n    const { subscriptions } = this.props;\n\n    return (\n      <TreeView\n        rootProps={rootProps}\n        data={subscriptions}\n        isWideLayout={this.props.isWideLayout}\n      />\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/components/QueryPreviewTags.tsx",
    "content": "import React, { ReactNode, PureComponent } from 'react';\nimport { QueryPreviewTabs, RtkQueryTag } from '../types.js';\nimport { renderTabPanelButtonId, renderTabPanelId } from '../utils/a11y.js';\nimport { TreeView, TreeViewProps } from './TreeView.js';\n\ninterface QueryPreviewTagsState {\n  data: { tags: RtkQueryTag[] };\n}\n\nconst rootProps: TreeViewProps['rootProps'] = {\n  'aria-labelledby': renderTabPanelButtonId(QueryPreviewTabs.queryTags),\n  id: renderTabPanelId(QueryPreviewTabs.queryTags),\n  role: 'tabpanel',\n};\n\nexport interface QueryPreviewTagsProps {\n  tags: RtkQueryTag[];\n  isWideLayout: boolean;\n}\n\nexport class QueryPreviewTags extends PureComponent<\n  QueryPreviewTagsProps,\n  QueryPreviewTagsState\n> {\n  constructor(props: QueryPreviewTagsProps) {\n    super(props);\n\n    this.state = {\n      data: { tags: props.tags },\n    };\n  }\n\n  render(): ReactNode {\n    const { isWideLayout, tags } = this.props;\n\n    return (\n      <TreeView rootProps={rootProps} data={tags} isWideLayout={isWideLayout} />\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/components/RegexIcon.tsx",
    "content": "import * as React from 'react';\n\nexport type RegexIconProps = Omit<\n  React.HTMLAttributes<SVGElement>,\n  'viewBox' | 'children'\n>;\n\n// `OOjs_UI_icon_regular-expression.svg` (MIT License)\n// from https://commons.wikimedia.org/wiki/File:OOjs_UI_icon_regular-expression.svg\nexport function RegexIcon(\n  props: React.HTMLAttributes<SVGElement>,\n): React.JSX.Element {\n  return (\n    <svg fill=\"currentColor\" {...props} viewBox=\"0 0 24 24\">\n      <g>\n        <path d=\"M3 12.045c0-.99.15-1.915.45-2.777A6.886 6.886 0 0 1 4.764 7H6.23a7.923 7.923 0 0 0-1.25 2.374 8.563 8.563 0 0 0 .007 5.314c.29.85.7 1.622 1.23 2.312h-1.45a6.53 6.53 0 0 1-1.314-2.223 8.126 8.126 0 0 1-.45-2.732\" />\n        <path id=\"dot\" d=\"M10 16a1 1 0 1 1-2 0 1 1 0 0 1 2 0z\" />\n        <path d=\"M14.25 7.013l-.24 2.156 2.187-.61.193 1.47-1.992.14 1.307 1.74-1.33.71-.914-1.833-.8 1.822-1.38-.698 1.296-1.74-1.98-.152.23-1.464 2.14.61-.24-2.158h1.534\" />\n        <path d=\"M21 12.045c0 .982-.152 1.896-.457 2.744A6.51 6.51 0 0 1 19.236 17h-1.453a8.017 8.017 0 0 0 1.225-2.31c.29-.855.434-1.74.434-2.66 0-.91-.14-1.797-.422-2.66a7.913 7.913 0 0 0-1.248-2.374h1.465a6.764 6.764 0 0 1 1.313 2.28c.3.86.45 1.782.45 2.764\" />\n      </g>\n    </svg>\n  );\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/components/SortOrderButton.tsx",
    "content": "import React, { CSSProperties } from 'react';\nimport { ArrowUpIcon } from './ArrowUpIcon.js';\n\nexport interface SortOrderButtonProps {\n  readonly isAsc?: boolean;\n  readonly onChange: (isAsc: boolean) => void;\n  id?: string;\n}\n\nexport function SortOrderButton({\n  isAsc,\n  onChange,\n  id,\n}: SortOrderButtonProps): React.JSX.Element {\n  const handleButtonClick = (): void => {\n    if (!isAsc) {\n      onChange(true);\n    } else onChange(false);\n  };\n\n  const buttonLabel = isAsc ? 'asc' : 'desc';\n\n  const arrowStyles: CSSProperties = {\n    width: '1em',\n    height: '1em',\n    transform: !isAsc ? 'scaleY(-1)' : undefined,\n  };\n\n  return (\n    <button\n      type=\"button\"\n      id={id}\n      onClick={handleButtonClick}\n      aria-pressed={isAsc}\n      css={(theme) => ({\n        display: 'flex',\n        justifyContent: 'space-between',\n        alignItems: 'center',\n        flexFlow: 'row nowrap',\n        cursor: 'pointer',\n        position: 'relative',\n        padding: '0 8px',\n        color: theme.TEXT_COLOR,\n        borderStyle: 'solid',\n        borderWidth: '1px',\n        borderRadius: '3px',\n        backgroundColor: theme.TAB_BACK_COLOR,\n        borderColor: theme.TAB_BORDER_COLOR,\n        height: 30,\n        fontSize: 12,\n        width: 64,\n\n        '&:active': {\n          backgroundColor: theme.TAB_BACK_SELECTED_COLOR,\n        },\n      })}\n    >\n      <ArrowUpIcon style={arrowStyles} />\n      {buttonLabel}\n    </button>\n  );\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/components/TreeView.tsx",
    "content": "import { createSelector, Selector } from '@reduxjs/toolkit';\nimport React, { ComponentProps, ReactNode } from 'react';\nimport { JSONTree } from 'react-json-tree';\nimport { Base16Theme } from 'react-base16-styling';\nimport { getJsonTreeTheme, StyleUtilsContext } from '../styles/themes.js';\nimport { getItemString, labelRenderer } from '../styles/tree.js';\nimport { identity } from '../utils/object.js';\n\nexport interface TreeViewProps extends Partial<\n  Pick<\n    ComponentProps<typeof JSONTree>,\n    'keyPath' | 'shouldExpandNodeInitially' | 'hideRoot'\n  >\n> {\n  data: unknown;\n  isWideLayout: boolean;\n  before?: ReactNode;\n  after?: ReactNode;\n  children?: ReactNode;\n  rootProps?: Partial<\n    Omit<React.HTMLAttributes<HTMLDivElement>, 'className' | 'style'>\n  >;\n}\n\nexport class TreeView extends React.PureComponent<TreeViewProps> {\n  static defaultProps = {\n    hideRoot: true,\n    shouldExpandNodeInitially: (\n      keyPath: (string | number)[],\n      value: unknown,\n      layer: number,\n    ): boolean => {\n      return layer < 2;\n    },\n  };\n\n  readonly selectTheme: Selector<\n    Base16Theme,\n    ReturnType<typeof getJsonTreeTheme>,\n    never\n  > = createSelector<\n    [(base16Theme: Base16Theme) => Base16Theme],\n    ReturnType<typeof getJsonTreeTheme>\n  >(identity, getJsonTreeTheme);\n\n  constructor(props: TreeViewProps) {\n    super(props);\n  }\n\n  render(): ReactNode {\n    const {\n      data,\n      before,\n      after,\n      children,\n      keyPath,\n      shouldExpandNodeInitially,\n      hideRoot,\n      rootProps,\n    } = this.props;\n\n    return (\n      <StyleUtilsContext.Consumer>\n        {({ invertTheme, base16Theme }) => {\n          return (\n            <div\n              {...rootProps}\n              css={{\n                overflowX: 'auto',\n                overflowY: 'auto',\n                padding: '0.5em 1em',\n              }}\n            >\n              {before}\n              <JSONTree\n                keyPath={keyPath}\n                shouldExpandNodeInitially={shouldExpandNodeInitially}\n                data={data}\n                labelRenderer={labelRenderer}\n                theme={this.selectTheme(base16Theme)}\n                invertTheme={invertTheme}\n                getItemString={getItemString}\n                hideRoot={hideRoot}\n              />\n              {after}\n              {children}\n            </div>\n          );\n        }}\n      </StyleUtilsContext.Consumer>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/components/UList.tsx",
    "content": "import * as React from 'react';\n\nexport type UListProps = React.HTMLAttributes<HTMLUListElement>;\n\nexport function UList(props: UListProps): React.JSX.Element {\n  return (\n    <ul\n      {...props}\n      css={(theme) => ({\n        listStyle: 'none',\n        padding: '0 0 0 1em',\n        color: theme.ULIST_COLOR,\n        '& > li': {\n          listStyle: 'none',\n        },\n        '& > li::before': {\n          content: '\"\\\\2022\"',\n          display: 'inline-block',\n          paddingRight: '0.5em',\n          color: theme.ULIST_DISC_COLOR,\n          fontSize: '0.8em',\n        },\n\n        '& strong': {\n          color: theme.ULIST_STRONG_COLOR,\n        },\n      })}\n    />\n  );\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/containers/QueryPreview.tsx",
    "content": "import React, { ReactNode } from 'react';\nimport type { Interpolation, Theme } from '@emotion/react';\nimport {\n  QueryPreviewTabs,\n  RtkResourceInfo,\n  SelectorsSource,\n  TabOption,\n} from '../types.js';\nimport { QueryPreviewHeader } from '../components/QueryPreviewHeader.js';\nimport {\n  QueryPreviewInfo,\n  QueryPreviewInfoProps,\n} from '../components/QueryPreviewInfo.js';\nimport {\n  QueryPreviewApi,\n  QueryPreviewApiProps,\n} from '../components/QueryPreviewApi.js';\nimport {\n  QueryPreviewSubscriptions,\n  QueryPreviewSubscriptionsProps,\n} from '../components/QueryPreviewSubscriptions.js';\nimport {\n  QueryPreviewTags,\n  QueryPreviewTagsProps,\n} from '../components/QueryPreviewTags.js';\nimport { NoRtkQueryApi } from '../components/NoRtkQueryApi.js';\nimport { InspectorSelectors } from '../selectors.js';\nimport { mapProps } from './mapProps.js';\nimport {\n  QueryPreviewActions,\n  QueryPreviewActionsProps,\n} from '../components/QueryPreviewActions.js';\nimport { isTabVisible } from '../utils/tabs.js';\nimport {\n  QueryPreviewData,\n  QueryPreviewDataProps,\n} from '../components/QueryPreviewData.js';\n\nconst queryPreviewCss: Interpolation<Theme> = (theme) => ({\n  flex: '1 1 50%',\n  overflowX: 'hidden',\n  oveflowY: 'auto',\n  display: 'flex',\n  flexDirection: 'column',\n  overflowY: 'hidden',\n  '& pre': {\n    border: 'inherit',\n    borderRadius: '3px',\n    lineHeight: 'inherit',\n    color: 'inherit',\n  },\n\n  backgroundColor: theme.BACKGROUND_COLOR,\n});\n\nexport interface QueryPreviewProps<S = unknown> {\n  readonly selectedTab: QueryPreviewTabs;\n  readonly hasNoApis: boolean;\n  readonly onTabChange: (tab: QueryPreviewTabs) => void;\n  readonly resInfo: RtkResourceInfo | null;\n  readonly isWideLayout: boolean;\n  readonly selectorsSource: SelectorsSource<S>;\n  readonly selectors: InspectorSelectors<S>;\n}\n\n/**\n * Tab content is not rendered if there's no selected query.\n */\ntype QueryPreviewTabProps = Omit<QueryPreviewProps<unknown>, 'resInfo'> & {\n  resInfo: RtkResourceInfo;\n};\n\nconst MappedQueryPreviewTags = mapProps<\n  QueryPreviewTabProps,\n  QueryPreviewTagsProps\n>(({ selectors, selectorsSource, isWideLayout, resInfo }) => ({\n  resInfo,\n  tags: selectors.selectCurrentQueryTags(selectorsSource),\n  isWideLayout,\n}))(QueryPreviewTags);\n\nconst MappedQueryPreviewInfo = mapProps<\n  QueryPreviewTabProps,\n  QueryPreviewInfoProps\n>(({ resInfo, isWideLayout }) => ({ resInfo, isWideLayout }))(QueryPreviewInfo);\n\nconst MappedQueryPreviewData = mapProps<\n  QueryPreviewTabProps,\n  QueryPreviewDataProps\n>(({ resInfo, isWideLayout }) => ({\n  data: resInfo?.state?.data,\n  isWideLayout,\n}))(QueryPreviewData);\n\nconst MappedQuerySubscriptipns = mapProps<\n  QueryPreviewTabProps,\n  QueryPreviewSubscriptionsProps\n>(({ selectors, selectorsSource, isWideLayout }) => ({\n  isWideLayout,\n  subscriptions: selectors.selectSubscriptionsOfCurrentQuery(selectorsSource),\n}))(QueryPreviewSubscriptions);\n\nconst MappedApiPreview = mapProps<QueryPreviewTabProps, QueryPreviewApiProps>(\n  ({ isWideLayout, selectors, selectorsSource }) => ({\n    isWideLayout,\n    apiState: selectors.selectApiOfCurrentQuery(selectorsSource),\n    apiStats: selectors.selectApiStatsOfCurrentQuery(selectorsSource),\n  }),\n)(QueryPreviewApi);\n\nconst MappedQueryPreviewActions = mapProps<\n  QueryPreviewTabProps,\n  QueryPreviewActionsProps\n>(({ isWideLayout, selectorsSource, selectors }) => ({\n  isWideLayout,\n  actionsOfQuery: selectors.selectActionsOfCurrentQuery(selectorsSource),\n}))(QueryPreviewActions);\n\nconst tabs: ReadonlyArray<\n  TabOption<QueryPreviewTabs, QueryPreviewTabProps, RtkResourceInfo['type']>\n> = [\n  {\n    label: 'Data',\n    value: QueryPreviewTabs.data,\n    component: MappedQueryPreviewData,\n    visible: {\n      query: true,\n      mutation: true,\n      default: true,\n    },\n  },\n  {\n    label: 'Query',\n    value: QueryPreviewTabs.queryinfo,\n    component: MappedQueryPreviewInfo,\n    visible: {\n      query: true,\n      mutation: true,\n      default: true,\n    },\n  },\n  {\n    label: 'Actions',\n    value: QueryPreviewTabs.actions,\n    component: MappedQueryPreviewActions,\n    visible: {\n      query: true,\n      mutation: true,\n      default: true,\n    },\n  },\n  {\n    label: 'Tags',\n    value: QueryPreviewTabs.queryTags,\n    component: MappedQueryPreviewTags,\n    visible: {\n      query: true,\n      mutation: false,\n      default: true,\n    },\n  },\n  {\n    label: 'Subs',\n    value: QueryPreviewTabs.querySubscriptions,\n    component: MappedQuerySubscriptipns,\n    visible: {\n      query: true,\n      mutation: false,\n      default: true,\n    },\n  },\n  {\n    label: 'Api',\n    value: QueryPreviewTabs.apiConfig,\n    component: MappedApiPreview,\n  },\n];\n\nexport class QueryPreview<S> extends React.PureComponent<QueryPreviewProps<S>> {\n  renderLabelWithCounter = (label: string, counter: number): string => {\n    let counterAsString = counter.toFixed(0);\n\n    if (counterAsString.length > 3) {\n      counterAsString = counterAsString.slice(0, 2) + '...';\n    }\n\n    return `${label}(${counterAsString})`;\n  };\n\n  renderTabLabel = (\n    tab: TabOption<QueryPreviewTabs, unknown, 'query' | 'mutation'>,\n  ): ReactNode => {\n    const { selectors, selectorsSource, resInfo } = this.props;\n    const tabCount = selectors.selectTabCounters(selectorsSource)[tab.value];\n\n    let tabLabel = tab.label;\n\n    if (tabLabel === 'query' && resInfo?.type === 'mutation') {\n      tabLabel = resInfo.type;\n    }\n\n    if (tabCount > 0) {\n      return this.renderLabelWithCounter(tabLabel, tabCount);\n    }\n\n    return tabLabel;\n  };\n\n  render(): ReactNode {\n    const { resInfo, selectedTab, onTabChange, hasNoApis } = this.props;\n\n    const { component: TabComponent } =\n      tabs.find((tab) => tab.value === selectedTab) || tabs[0];\n\n    if (!resInfo) {\n      return (\n        <div css={queryPreviewCss}>\n          <QueryPreviewHeader\n            selectedTab={selectedTab}\n            onTabChange={onTabChange}\n            tabs={\n              tabs.filter((tab) =>\n                isTabVisible(tab, 'default'),\n              ) as ReadonlyArray<\n                TabOption<QueryPreviewTabs, unknown, RtkResourceInfo['type']>\n              >\n            }\n            renderTabLabel={this.renderTabLabel}\n          />\n          {hasNoApis && <NoRtkQueryApi />}\n        </div>\n      );\n    }\n\n    return (\n      <div css={queryPreviewCss}>\n        <QueryPreviewHeader\n          selectedTab={selectedTab}\n          onTabChange={onTabChange}\n          tabs={\n            tabs.filter((tab) =>\n              isTabVisible(tab, resInfo.type),\n            ) as ReadonlyArray<\n              TabOption<QueryPreviewTabs, unknown, RtkResourceInfo['type']>\n            >\n          }\n          renderTabLabel={this.renderTabLabel}\n        />\n        <TabComponent {...(this.props as QueryPreviewTabProps)} />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/containers/RtkQueryInspector.tsx",
    "content": "import React, { PureComponent, createRef, ReactNode } from 'react';\nimport type { Dispatch, Action } from '@reduxjs/toolkit';\nimport type { LiftedAction, LiftedState } from '@redux-devtools/core';\nimport {\n  QueryFormValues,\n  QueryPreviewTabs,\n  RtkQueryMonitorState,\n  SelectorsSource,\n  RtkResourceInfo,\n} from '../types.js';\nimport {\n  createInspectorSelectors,\n  computeSelectorSource,\n} from '../selectors.js';\nimport {\n  changeQueryFormValues,\n  selectedPreviewTab,\n  selectQueryKey,\n} from '../reducers.js';\nimport { QueryList } from '../components/QueryList.js';\nimport { QueryForm } from '../components/QueryForm.js';\nimport { QueryPreview } from './QueryPreview.js';\n\ntype ForwardedMonitorProps<S, A extends Action<string>> = Pick<\n  LiftedState<S, A, RtkQueryMonitorState>,\n  'monitorState' | 'currentStateIndex' | 'computedStates' | 'actionsById'\n>;\n\nexport interface RtkQueryInspectorProps<\n  S,\n  A extends Action<string>,\n> extends ForwardedMonitorProps<S, A> {\n  dispatch: Dispatch<LiftedAction<S, A, RtkQueryMonitorState>>;\n}\n\ntype RtkQueryInspectorState<S> = {\n  selectorsSource: SelectorsSource<S>;\n  isWideLayout: boolean;\n};\n\nclass RtkQueryInspector<S, A extends Action<string>> extends PureComponent<\n  RtkQueryInspectorProps<S, A>,\n  RtkQueryInspectorState<S>\n> {\n  inspectorRef = createRef<HTMLDivElement>();\n\n  isWideIntervalRef: ReturnType<typeof setInterval> | null = null;\n\n  constructor(props: RtkQueryInspectorProps<S, A>) {\n    super(props);\n\n    this.state = {\n      isWideLayout: true,\n      selectorsSource: computeSelectorSource(props, null),\n    };\n  }\n\n  static wideLayout = 600;\n\n  static getDerivedStateFromProps(\n    props: RtkQueryInspectorProps<unknown, Action<string>>,\n    state: RtkQueryInspectorState<unknown>,\n  ): null | Partial<RtkQueryInspectorState<unknown>> {\n    const selectorsSource = computeSelectorSource<unknown, Action<string>>(\n      props,\n      state.selectorsSource,\n    );\n\n    if (selectorsSource !== state.selectorsSource) {\n      return {\n        selectorsSource,\n      };\n    }\n\n    return null;\n  }\n\n  selectors = createInspectorSelectors<S>();\n\n  updateSizeMode = (): void => {\n    if (this.inspectorRef.current) {\n      const isWideLayout =\n        this.inspectorRef.current.offsetWidth >= RtkQueryInspector.wideLayout;\n\n      if (isWideLayout !== this.state.isWideLayout) {\n        this.setState({ isWideLayout });\n      }\n    }\n  };\n\n  componentDidMount(): void {\n    this.updateSizeMode();\n\n    this.isWideIntervalRef = setInterval(this.updateSizeMode, 300);\n  }\n\n  componentWillUnmount(): void {\n    if (this.isWideIntervalRef) {\n      clearTimeout(this.isWideIntervalRef);\n    }\n  }\n\n  handleQueryFormValuesChange = (values: Partial<QueryFormValues>): void => {\n    this.props.dispatch(\n      changeQueryFormValues(values) as unknown as LiftedAction<\n        S,\n        A,\n        RtkQueryMonitorState\n      >,\n    );\n  };\n\n  handleSelectQuery = (queryInfo: RtkResourceInfo): void => {\n    this.props.dispatch(\n      selectQueryKey(queryInfo) as unknown as LiftedAction<\n        S,\n        A,\n        RtkQueryMonitorState\n      >,\n    );\n  };\n\n  handleTabChange = (tab: QueryPreviewTabs): void => {\n    this.props.dispatch(\n      selectedPreviewTab(tab) as unknown as LiftedAction<\n        S,\n        A,\n        RtkQueryMonitorState\n      >,\n    );\n  };\n\n  render(): ReactNode {\n    const { selectorsSource, isWideLayout } = this.state;\n    const allVisibleRtkResourceInfos =\n      this.selectors.selectAllVisbileQueries(selectorsSource);\n\n    const currentResInfo =\n      this.selectors.selectCurrentQueryInfo(selectorsSource);\n\n    const apiStates = this.selectors.selectApiStates(selectorsSource);\n\n    const hasNoApi = apiStates == null;\n\n    const searchQueryRegex =\n      this.selectors.selectSearchQueryRegex(selectorsSource);\n\n    return (\n      <div\n        ref={this.inspectorRef}\n        data-wide-layout={+this.state.isWideLayout}\n        css={(theme) => ({\n          display: 'flex',\n          flexFlow: 'column nowrap',\n          overflow: 'hidden',\n          width: '100%',\n          height: '100%',\n          fontFamily: 'monaco, Consolas, \"Lucida Console\", monospace',\n          fontSize: '12px',\n          WebkitFontSmoothing: 'antialiased',\n          lineHeight: '1.5em',\n\n          backgroundColor: theme.BACKGROUND_COLOR,\n          color: theme.TEXT_COLOR,\n\n          '&[data-wide-layout=\"1\"]': {\n            flexFlow: 'row nowrap',\n          },\n        })}\n      >\n        <div\n          css={(theme) => ({\n            display: 'flex',\n            flex: '0 0 auto',\n            height: '50%',\n            width: '100%',\n            borderColor: theme.TAB_BORDER_COLOR,\n\n            '&[data-wide-layout=\"0\"]': {\n              borderBottomWidth: 1,\n              borderStyle: 'solid',\n            },\n\n            '&[data-wide-layout=\"1\"]': {\n              height: '100%',\n              width: '44%',\n              borderRightWidth: 1,\n              borderStyle: 'solid',\n            },\n            flexFlow: 'column nowrap',\n            '& > form': {\n              flex: '0 0 auto',\n              borderBottomWidth: '1px',\n              borderBottomStyle: 'solid',\n              borderColor: theme.LIST_BORDER_COLOR,\n            },\n            '& > ul': {\n              flex: '1 1 auto',\n              overflowX: 'hidden',\n              overflowY: 'auto',\n              maxHeight: 'calc(100% - 70px)',\n            },\n          })}\n          data-wide-layout={+this.state.isWideLayout}\n        >\n          <QueryForm\n            searchQueryRegex={searchQueryRegex}\n            values={selectorsSource.monitorState.queryForm.values}\n            onFormValuesChange={this.handleQueryFormValuesChange}\n          />\n          <QueryList\n            onSelectQuery={this.handleSelectQuery}\n            resInfos={allVisibleRtkResourceInfos}\n            selectedQueryKey={selectorsSource.monitorState.selectedQueryKey}\n          />\n        </div>\n        <QueryPreview<S>\n          selectorsSource={this.state.selectorsSource}\n          selectors={this.selectors}\n          resInfo={currentResInfo}\n          selectedTab={selectorsSource.monitorState.selectedPreviewTab}\n          onTabChange={this.handleTabChange}\n          isWideLayout={isWideLayout}\n          hasNoApis={hasNoApi}\n        />\n      </div>\n    );\n  }\n}\n\nexport default RtkQueryInspector;\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/containers/RtkQueryMonitor.tsx",
    "content": "import React, { Component } from 'react';\nimport { Action, AnyAction } from 'redux';\nimport { ThemeProvider } from '@emotion/react';\nimport RtkQueryInspector from './RtkQueryInspector.js';\nimport { reducer } from '../reducers.js';\nimport {\n  ExternalProps,\n  RtkQueryMonitorProps,\n  RtkQueryMonitorState,\n} from '../types.js';\nimport {\n  createRtkQueryMonitorThemeFromBase16Theme,\n  resolveBase16Theme,\n  StyleUtilsContext,\n} from '../styles/themes.js';\n\ninterface DefaultProps {\n  theme: string;\n  invertTheme: boolean;\n}\n\nclass RtkQueryMonitor<S, A extends Action<string>> extends Component<\n  RtkQueryMonitorProps<S, A>\n> {\n  static update = reducer;\n\n  static defaultProps: DefaultProps = {\n    theme: 'nicinabox',\n    invertTheme: false,\n  };\n\n  render() {\n    const {\n      currentStateIndex,\n      computedStates,\n      monitorState,\n      dispatch,\n      actionsById,\n      theme,\n      invertTheme,\n    } = this.props;\n\n    const base16Theme = resolveBase16Theme(theme);\n    const styleUtils = { base16Theme, invertTheme };\n    const rtkQueryMonitorTheme = createRtkQueryMonitorThemeFromBase16Theme(\n      base16Theme,\n      invertTheme,\n    );\n\n    return (\n      <StyleUtilsContext.Provider value={styleUtils}>\n        <ThemeProvider theme={rtkQueryMonitorTheme}>\n          <RtkQueryInspector<S, AnyAction>\n            computedStates={computedStates}\n            currentStateIndex={currentStateIndex}\n            monitorState={monitorState}\n            dispatch={dispatch}\n            actionsById={actionsById}\n          />\n        </ThemeProvider>\n      </StyleUtilsContext.Provider>\n    );\n  }\n}\n\nexport default RtkQueryMonitor as unknown as React.ComponentType<\n  ExternalProps<unknown, Action<string>>\n> & {\n  update(\n    monitorProps: ExternalProps<unknown, Action<string>>,\n    state: RtkQueryMonitorState | undefined,\n    action: Action,\n  ): RtkQueryMonitorState;\n  defaultProps: DefaultProps;\n};\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/containers/mapProps.tsx",
    "content": "import React, { ComponentType, ReactNode, Component } from 'react';\n\ninterface Mapper<In, Out> {\n  (inProps: In): Out;\n}\n\ninterface MapPropsOutput<In, Out> {\n  (comp: ComponentType<Out>): ComponentType<In>;\n}\n\nexport function mapProps<In, Out>(\n  mapper: Mapper<In, Out>,\n): MapPropsOutput<In, Out> {\n  return function mapPropsHoc(Comp) {\n    class MapPropsHoc extends Component<In> {\n      render(): ReactNode {\n        const mappedProps = mapper(this.props);\n\n        // TODO Not really sure why this is needed, but it is\n        return <Comp {...(mappedProps as any)} />;\n      }\n\n      static displayName = `mapProps(${\n        Comp.displayName || Comp.name || 'Component'\n      })`;\n    }\n\n    return MapPropsHoc;\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/index.ts",
    "content": "export { default as RtkQueryMonitor } from './containers/RtkQueryMonitor.js';\nexport type { ExternalProps } from './types.js';\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/monitor-config.ts",
    "content": "export const DATA_TYPE_KEY = Symbol.for('__serializedType__');\n\n/**\n * @see https://github.com/reduxjs/redux-toolkit/blob/b718e01d323d3ab4b913e5d88c9b90aa790bb975/src/query/core/buildSlice.ts#L259\n */\nexport const missingTagId = '__internal_without_id';\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/reducers.ts",
    "content": "import { Action, AnyAction } from 'redux';\nimport { createSlice, PayloadAction } from '@reduxjs/toolkit';\nimport {\n  QueryInfo,\n  RtkQueryMonitorState,\n  QueryFormValues,\n  RtkQueryMonitorProps,\n  QueryPreviewTabs,\n} from './types.js';\nimport { QueryComparators } from './utils/comparators.js';\nimport { QueryFilters } from './utils/filters.js';\n\nconst initialState: RtkQueryMonitorState = {\n  queryForm: {\n    values: {\n      queryComparator: QueryComparators.fulfilledTimeStamp,\n      isAscendingQueryComparatorOrder: false,\n      searchValue: '',\n      isRegexSearch: false,\n      queryFilter: QueryFilters.queryKey,\n    },\n  },\n  selectedPreviewTab: QueryPreviewTabs.queryinfo,\n  selectedQueryKey: null,\n};\n\nconst monitorSlice = createSlice({\n  /**\n   * `@@` prefix is mandatory.\n   * @see lifedAction @ `packages/redux-devtools-app/src/actions/index.ts`\n   */\n  name: '@@rtk-query-monitor',\n  initialState,\n  reducers: {\n    changeQueryFormValues(\n      state,\n      action: PayloadAction<Partial<QueryFormValues>>,\n    ) {\n      state.queryForm.values = { ...state.queryForm.values, ...action.payload };\n    },\n    selectQueryKey(\n      state,\n      action: PayloadAction<Pick<QueryInfo, 'reducerPath' | 'queryKey'>>,\n    ) {\n      state.selectedQueryKey = {\n        queryKey: action.payload.queryKey,\n        reducerPath: action.payload.reducerPath,\n      };\n    },\n    selectedPreviewTab(state, action: PayloadAction<QueryPreviewTabs>) {\n      state.selectedPreviewTab = action.payload;\n    },\n  },\n});\n\nexport function reducer<S, A extends Action<string>>(\n  props: RtkQueryMonitorProps<S, A>,\n  state: RtkQueryMonitorState | undefined,\n  action: AnyAction,\n): RtkQueryMonitorState {\n  return monitorSlice.reducer(state, action);\n}\n\nexport const { selectQueryKey, changeQueryFormValues, selectedPreviewTab } =\n  monitorSlice.actions;\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/selectors.ts",
    "content": "import { Action, createSelector, Selector } from '@reduxjs/toolkit';\nimport { RtkQueryInspectorProps } from './containers/RtkQueryInspector.js';\nimport {\n  ApiStats,\n  QueryInfo,\n  RtkQueryApiState,\n  RtkQueryTag,\n  SelectorsSource,\n  RtkQueryProvidedTagsState,\n  QueryPreviewTabs,\n  RtkResourceInfo,\n  RtkQuery262ProvidedState,\n} from './types.js';\nimport { Comparator, queryComparators } from './utils/comparators.js';\nimport { FilterList, queryListFilters } from './utils/filters.js';\nimport { emptyRecord } from './utils/object.js';\nimport { escapeRegExpSpecialCharacter } from './utils/regexp.js';\nimport {\n  getApiStatesOf,\n  extractAllApiQueries,\n  flipComparator,\n  getQueryTagsOf,\n  generateApiStatsOfCurrentQuery,\n  getActionsOfCurrentQuery,\n  extractAllApiMutations,\n} from './utils/rtk-query.js';\n\ntype InspectorSelector<S, Output> = Selector<SelectorsSource<S>, Output>;\n\nexport function computeSelectorSource<S, A extends Action<string>>(\n  props: RtkQueryInspectorProps<S, A>,\n  previous: SelectorsSource<S> | null = null,\n): SelectorsSource<S> {\n  const { computedStates, currentStateIndex, monitorState, actionsById } =\n    props;\n\n  const userState =\n    computedStates.length > 0 ? computedStates[currentStateIndex].state : null;\n\n  if (\n    !previous ||\n    previous.userState !== userState ||\n    previous.monitorState !== monitorState ||\n    previous.actionsById !== actionsById\n  ) {\n    return {\n      userState,\n      monitorState,\n      currentStateIndex,\n      actionsById,\n    };\n  }\n\n  return previous;\n}\n\nexport interface InspectorSelectors<S> {\n  readonly selectQueryComparator: InspectorSelector<S, Comparator<QueryInfo>>;\n  readonly selectApiStates: InspectorSelector<\n    S,\n    ReturnType<typeof getApiStatesOf>\n  >;\n  readonly selectAllQueries: InspectorSelector<\n    S,\n    ReturnType<typeof extractAllApiQueries>\n  >;\n  readonly selectAllVisbileQueries: InspectorSelector<S, RtkResourceInfo[]>;\n  readonly selectCurrentQueryInfo: InspectorSelector<S, RtkResourceInfo | null>;\n  readonly selectSearchQueryRegex: InspectorSelector<S, RegExp | null>;\n  readonly selectCurrentQueryTags: InspectorSelector<S, RtkQueryTag[]>;\n  readonly selectApiStatsOfCurrentQuery: InspectorSelector<S, ApiStats | null>;\n  readonly selectApiOfCurrentQuery: InspectorSelector<\n    S,\n    RtkQueryApiState | null\n  >;\n  readonly selectTabCounters: InspectorSelector<\n    S,\n    Record<QueryPreviewTabs, number>\n  >;\n  readonly selectSubscriptionsOfCurrentQuery: InspectorSelector<\n    S,\n    RtkQueryApiState['subscriptions'][string]\n  >;\n  readonly selectActionsOfCurrentQuery: InspectorSelector<\n    S,\n    ReturnType<typeof getActionsOfCurrentQuery>\n  >;\n}\n\nexport function createInspectorSelectors<S>(): InspectorSelectors<S> {\n  const selectQueryComparator = ({\n    monitorState,\n  }: SelectorsSource<S>): Comparator<RtkResourceInfo> => {\n    return queryComparators[monitorState.queryForm.values.queryComparator];\n  };\n\n  const selectQueryListFilter = ({\n    monitorState,\n  }: SelectorsSource<S>): FilterList<RtkResourceInfo> => {\n    return queryListFilters[monitorState.queryForm.values.queryFilter];\n  };\n\n  const selectActionsById = ({ actionsById }: SelectorsSource<S>) =>\n    actionsById;\n\n  const selectApiStates = createSelector(\n    ({ userState }: SelectorsSource<S>) => userState,\n    getApiStatesOf,\n  );\n  const selectAllQueries = createSelector(\n    selectApiStates,\n    extractAllApiQueries,\n  );\n\n  const selectAllMutations = createSelector(\n    selectApiStates,\n    extractAllApiMutations,\n  );\n\n  const selectSearchQueryRegex = createSelector(\n    ({ monitorState }: SelectorsSource<S>) =>\n      monitorState.queryForm.values.searchValue,\n    ({ monitorState }: SelectorsSource<S>) =>\n      monitorState.queryForm.values.isRegexSearch,\n    (searchValue, isRegexSearch) => {\n      if (searchValue) {\n        try {\n          const regexPattern = isRegexSearch\n            ? searchValue\n            : escapeRegExpSpecialCharacter(searchValue);\n\n          return new RegExp(regexPattern, 'i');\n        } catch (err) {\n          // We notify that the search regex provided is not valid\n        }\n      }\n\n      return null;\n    },\n  );\n\n  const selectComparatorOrder = ({ monitorState }: SelectorsSource<S>) =>\n    monitorState.queryForm.values.isAscendingQueryComparatorOrder;\n\n  const selectAllVisbileQueries = createSelector(\n    [\n      selectQueryComparator,\n      selectQueryListFilter,\n      selectAllQueries,\n      selectAllMutations,\n      selectComparatorOrder,\n      selectSearchQueryRegex,\n    ],\n    (\n      comparator,\n      queryListFilter,\n      queryList,\n      mutationsList,\n      isAscending,\n      searchRegex,\n    ) => {\n      const filteredList = queryListFilter(\n        searchRegex,\n        (queryList as RtkResourceInfo[]).concat(mutationsList),\n      );\n\n      const computedComparator = isAscending\n        ? comparator\n        : flipComparator(comparator);\n\n      return filteredList.slice().sort(computedComparator);\n    },\n  );\n\n  const selectCurrentQueryInfo = createSelector(\n    selectAllQueries,\n    selectAllMutations,\n    ({ monitorState }: SelectorsSource<S>) => monitorState.selectedQueryKey,\n    (allQueries, allMutations, selectedQueryKey) => {\n      if (!selectedQueryKey) {\n        return null;\n      }\n\n      let currentQueryInfo: null | RtkResourceInfo =\n        allQueries.find(\n          (query) =>\n            query.queryKey === selectedQueryKey.queryKey &&\n            selectedQueryKey.reducerPath === query.reducerPath,\n        ) || null;\n\n      if (!currentQueryInfo) {\n        currentQueryInfo =\n          allMutations.find(\n            (mutation) =>\n              mutation.queryKey === selectedQueryKey.queryKey &&\n              selectedQueryKey.reducerPath === mutation.reducerPath,\n          ) || null;\n      }\n\n      return currentQueryInfo;\n    },\n  );\n\n  const selectApiOfCurrentQuery: InspectorSelector<\n    S,\n    null | RtkQueryApiState\n  > = (selectorsSource: SelectorsSource<S>) => {\n    const apiStates = selectApiStates(selectorsSource);\n    const currentQueryInfo = selectCurrentQueryInfo(selectorsSource);\n\n    if (!apiStates || !currentQueryInfo) {\n      return null;\n    }\n\n    return apiStates[currentQueryInfo.reducerPath] ?? null;\n  };\n\n  const selectProvidedOfCurrentQuery: InspectorSelector<\n    S,\n    null | RtkQueryProvidedTagsState | RtkQuery262ProvidedState\n  > = (selectorsSource: SelectorsSource<S>) => {\n    return selectApiOfCurrentQuery(selectorsSource)?.provided ?? null;\n  };\n\n  const selectSubscriptionsOfCurrentQuery = createSelector(\n    [selectApiOfCurrentQuery, selectCurrentQueryInfo],\n    (apiState, queryInfo) => {\n      if (!queryInfo || !apiState) {\n        return emptyRecord;\n      }\n\n      return apiState.subscriptions[queryInfo.queryKey];\n    },\n  );\n\n  const selectCurrentQueryTags = createSelector(\n    [selectCurrentQueryInfo, selectProvidedOfCurrentQuery],\n    getQueryTagsOf,\n  );\n\n  const selectApiStatsOfCurrentQuery = createSelector(\n    selectApiOfCurrentQuery,\n    (selectorsSource: SelectorsSource<S>) => selectorsSource.actionsById,\n    (selectorsSource: SelectorsSource<S>) => selectorsSource.currentStateIndex,\n    generateApiStatsOfCurrentQuery,\n  );\n\n  const selectActionsOfCurrentQuery = createSelector(\n    selectCurrentQueryInfo,\n    selectActionsById,\n    getActionsOfCurrentQuery,\n  );\n\n  const selectTabCounters = createSelector(\n    [\n      selectSubscriptionsOfCurrentQuery,\n      selectActionsOfCurrentQuery,\n      selectCurrentQueryTags,\n    ],\n    (subscriptions, actions, tags) => {\n      return {\n        [QueryPreviewTabs.data]: 0,\n        [QueryPreviewTabs.queryTags]: tags.length,\n        [QueryPreviewTabs.querySubscriptions]: Object.keys(subscriptions ?? {})\n          .length,\n        [QueryPreviewTabs.apiConfig]: 0,\n        [QueryPreviewTabs.queryinfo]: 0,\n        [QueryPreviewTabs.actions]: actions.length,\n      };\n    },\n  );\n\n  return {\n    selectQueryComparator,\n    selectApiStates,\n    selectAllQueries,\n    selectAllVisbileQueries,\n    selectSearchQueryRegex,\n    selectCurrentQueryInfo,\n    selectCurrentQueryTags,\n    selectApiStatsOfCurrentQuery,\n    selectSubscriptionsOfCurrentQuery,\n    selectApiOfCurrentQuery,\n    selectTabCounters,\n    selectActionsOfCurrentQuery,\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/styles/themes.ts",
    "content": "import {\n  base16Themes,\n  getBase16Theme,\n  invertBase16Theme,\n} from 'react-base16-styling';\nimport type { Base16Theme, StylingConfig } from 'react-base16-styling';\nimport rgba from 'hex-rgba';\nimport { createContext } from 'react';\nimport { StyleUtils } from '../types.js';\n\nexport function resolveBase16Theme(\n  theme: keyof typeof base16Themes | Base16Theme,\n) {\n  return getBase16Theme(theme, base16Themes) ?? base16Themes.nicinabox;\n}\n\n/**\n * @internal\n */\ndeclare module '@emotion/react' {\n  export interface Theme {\n    TEXT_COLOR: string;\n    TEXT_PLACEHOLDER_COLOR: string;\n    BACKGROUND_COLOR: string;\n    SELECTED_BACKGROUND_COLOR: string;\n    SKIPPED_BACKGROUND_COLOR: string;\n    HEADER_BACKGROUND_COLOR: string;\n    HEADER_BORDER_COLOR: string;\n    BORDER_COLOR: string;\n    LIST_BORDER_COLOR: string;\n    ACTION_TIME_BACK_COLOR: string;\n    ACTION_TIME_COLOR: string;\n    PIN_COLOR: string;\n    ITEM_HINT_COLOR: string;\n    TAB_BACK_SELECTED_COLOR: string;\n    TAB_BACK_COLOR: string;\n    TAB_BACK_HOVER_COLOR: string;\n    TAB_BORDER_COLOR: string;\n    DIFF_ADD_COLOR: string;\n    DIFF_REMOVE_COLOR: string;\n    DIFF_ARROW_COLOR: string;\n    LINK_COLOR: string;\n    LINK_HOVER_COLOR: string;\n    ERROR_COLOR: string;\n    ULIST_DISC_COLOR: string;\n    ULIST_COLOR: string;\n    ULIST_STRONG_COLOR: string;\n    TAB_CONTENT_COLOR: string;\n    TOGGLE_BUTTON_BACKGROUND: string;\n    TOGGLE_BUTTON_SELECTED_BACKGROUND: string;\n    TOGGLE_BUTTON_ERROR: string;\n  }\n}\n\nexport const colorMap = (theme: Base16Theme) =>\n  ({\n    TEXT_COLOR: theme.base06,\n    TEXT_PLACEHOLDER_COLOR: rgba(theme.base06, 60),\n    BACKGROUND_COLOR: theme.base00,\n    SELECTED_BACKGROUND_COLOR: rgba(theme.base03, 20),\n    SKIPPED_BACKGROUND_COLOR: rgba(theme.base03, 10),\n    HEADER_BACKGROUND_COLOR: rgba(theme.base03, 30),\n    HEADER_BORDER_COLOR: rgba(theme.base03, 20),\n    BORDER_COLOR: rgba(theme.base03, 50),\n    LIST_BORDER_COLOR: rgba(theme.base03, 50),\n    ACTION_TIME_BACK_COLOR: rgba(theme.base03, 20),\n    ACTION_TIME_COLOR: theme.base04,\n    PIN_COLOR: theme.base04,\n    ITEM_HINT_COLOR: rgba(theme.base0F, 90),\n    TAB_BACK_SELECTED_COLOR: rgba(theme.base03, 20),\n    TAB_BACK_COLOR: rgba(theme.base00, 70),\n    TAB_BACK_HOVER_COLOR: rgba(theme.base03, 40),\n    TAB_BORDER_COLOR: rgba(theme.base03, 50),\n    DIFF_ADD_COLOR: rgba(theme.base0B, 40),\n    DIFF_REMOVE_COLOR: rgba(theme.base08, 40),\n    DIFF_ARROW_COLOR: theme.base0E,\n    LINK_COLOR: rgba(theme.base0E, 90),\n    LINK_HOVER_COLOR: theme.base0E,\n    ERROR_COLOR: theme.base08,\n    ULIST_DISC_COLOR: theme.base0D,\n    ULIST_COLOR: rgba(theme.base06, 60),\n    ULIST_STRONG_COLOR: theme.base0B,\n    TAB_CONTENT_COLOR: rgba(theme.base06, 60),\n    TOGGLE_BUTTON_BACKGROUND: rgba(theme.base00, 70),\n    TOGGLE_BUTTON_SELECTED_BACKGROUND: theme.base04,\n    TOGGLE_BUTTON_ERROR: rgba(theme.base08, 40),\n  }) as const;\n\nexport function createRtkQueryMonitorThemeFromBase16Theme(\n  base16Theme: Base16Theme,\n  invertTheme: boolean,\n) {\n  const finalBase16Theme = invertTheme\n    ? invertBase16Theme(base16Theme)\n    : base16Theme;\n  return colorMap(finalBase16Theme);\n}\n\nexport const StyleUtilsContext = createContext<StyleUtils>({\n  base16Theme: base16Themes.nicinabox,\n  invertTheme: false,\n});\n\nexport function getJsonTreeTheme(base16Theme: Base16Theme): StylingConfig {\n  return {\n    extend: base16Theme,\n    nestedNode: ({ style }, keyPath, nodeType, expanded) => ({\n      style: {\n        ...style,\n        whiteSpace: expanded ? 'inherit' : 'nowrap',\n      },\n    }),\n    nestedNodeItemString: ({ style }, keyPath, nodeType, expanded) => ({\n      style: {\n        ...style,\n        display: expanded ? 'none' : 'inline',\n      },\n    }),\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/styles/tree.tsx",
    "content": "import React from 'react';\nimport type { GetItemString, LabelRenderer } from 'react-json-tree';\nimport { isCollection, isIndexed, isKeyed } from 'immutable';\nimport isIterable from '../utils/isIterable.js';\nimport { DATA_TYPE_KEY } from '../monitor-config.js';\n\nconst IS_IMMUTABLE_KEY = '@@__IS_IMMUTABLE__@@';\n\nfunction isImmutable(value: unknown) {\n  return isKeyed(value) || isIndexed(value) || isCollection(value);\n}\n\nfunction getShortTypeString(val: unknown, diff: boolean | undefined) {\n  if (diff && Array.isArray(val)) {\n    val = val[val.length === 2 ? 1 : 0];\n  }\n\n  if (isIterable(val) && !isImmutable(val)) {\n    return '(…)';\n  } else if (Array.isArray(val)) {\n    return val.length > 0 ? '[…]' : '[]';\n  } else if (val === null) {\n    return 'null';\n  } else if (val === undefined) {\n    return 'undef';\n  } else if (typeof val === 'object') {\n    return Object.keys(val as Record<string, unknown>).length > 0\n      ? '{…}'\n      : '{}';\n  } else if (typeof val === 'function') {\n    return 'fn';\n  } else if (typeof val === 'string') {\n    return `\"${val.substr(0, 10) + (val.length > 10 ? '…' : '')}\"`;\n  } else if (typeof val === 'symbol') {\n    return 'symbol';\n  } else {\n    return val;\n  }\n}\n\nfunction getText(\n  type: string,\n  data: any,\n  previewContent: boolean,\n  isDiff: boolean | undefined,\n) {\n  if (type === 'Object') {\n    const keys = Object.keys(data as object);\n    if (!previewContent) return keys.length ? '{…}' : '{}';\n\n    const str = keys\n      .slice(0, 3)\n      .map(\n        (key) => `${key}: ${getShortTypeString(data[key], isDiff) as string}`,\n      )\n      .concat(keys.length > 3 ? ['…'] : [])\n      .join(', ');\n\n    return `{ ${str} }`;\n  } else if (type === 'Array') {\n    if (!previewContent) return data.length ? '[…]' : '[]';\n\n    const str = data\n      .slice(0, 4)\n      .map((val: any) => getShortTypeString(val, isDiff))\n      .concat(data.length > 4 ? ['…'] : [])\n      .join(', ');\n\n    return `[${str as string}]`;\n  } else {\n    return type;\n  }\n}\n\nexport const getItemString: GetItemString = (type: string, data: any) => (\n  <span>\n    {data[IS_IMMUTABLE_KEY] ? 'Immutable' : ''}\n    {DATA_TYPE_KEY && data[DATA_TYPE_KEY]\n      ? `${data[DATA_TYPE_KEY] as string} `\n      : ''}\n    {getText(type, data, false, undefined)}\n  </span>\n);\n\nexport const labelRenderer: LabelRenderer = ([key], nodeType, expanded) => (\n  <span>\n    <span css={(theme) => ({ color: theme.TEXT_PLACEHOLDER_COLOR })}>\n      {key}\n    </span>\n    {!expanded && ': '}\n  </span>\n);\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/types.ts",
    "content": "import type { LiftedAction, LiftedState } from '@redux-devtools/core';\nimport type {\n  createApi,\n  QueryCacheKey,\n  QueryStatus,\n} from '@reduxjs/toolkit/query';\nimport type { Action, AnyAction, Dispatch } from '@reduxjs/toolkit';\nimport type { ComponentType } from 'react';\nimport { base16Themes } from 'react-base16-styling';\nimport type { Base16Theme } from 'react-base16-styling';\nimport type { QueryComparators } from './utils/comparators.js';\nimport type { QueryFilters } from './utils/filters.js';\n\nexport enum QueryPreviewTabs {\n  data,\n  queryinfo,\n  apiConfig,\n  querySubscriptions,\n  queryTags,\n  actions,\n}\n\nexport interface QueryFormValues {\n  queryComparator: QueryComparators;\n  isAscendingQueryComparatorOrder: boolean;\n  searchValue: string;\n  isRegexSearch: boolean;\n  queryFilter: QueryFilters;\n}\nexport interface RtkQueryMonitorState {\n  readonly queryForm: {\n    values: QueryFormValues;\n  };\n  readonly selectedQueryKey: Pick<QueryInfo, 'reducerPath' | 'queryKey'> | null;\n  readonly selectedPreviewTab: QueryPreviewTabs;\n}\n\nexport interface RtkQueryMonitorProps<\n  S,\n  A extends Action<string>,\n> extends LiftedState<S, A, RtkQueryMonitorState> {\n  dispatch: Dispatch<Action | LiftedAction<S, A, RtkQueryMonitorState>>;\n  theme: keyof typeof base16Themes | Base16Theme;\n  invertTheme: boolean;\n}\n\nexport type RtkQueryApiState = ReturnType<\n  ReturnType<typeof createApi>['reducer']\n>;\n\nexport type RtkQueryState = NonNullable<\n  RtkQueryApiState['queries'][keyof RtkQueryApiState]\n>;\n\nexport type RtkMutationState = NonNullable<\n  RtkQueryApiState['mutations'][keyof RtkQueryApiState]\n>;\n\nexport type RtkQueryApiConfig = RtkQueryApiState['config'];\n\nexport type FullTagDescription<TagType> = {\n  type: TagType;\n  id?: number | string;\n};\n\n// This is the actual tags structure, and was the entire `api.provided`\n// field up through 2.6.1\nexport type RtkQueryProvidedTagsState = {\n  [x: string]: {\n    [id: string]: QueryCacheKey[];\n    [id: number]: QueryCacheKey[];\n  };\n};\n\n// As of 2.6.2, the `api.provided` field is split into `tags` and `keys` fields,\n// with the old data nested in `tags`.\nexport type RtkQuery262ProvidedState = {\n  keys: Record<QueryCacheKey, FullTagDescription<any>[]>;\n  tags: RtkQueryProvidedTagsState;\n};\n\nexport function isRtkQuery262Provided(\n  provided: Record<string, unknown>,\n): provided is RtkQuery262ProvidedState {\n  return (\n    'tags' in provided &&\n    'keys' in provided &&\n    typeof provided.tags === 'object' &&\n    typeof provided.keys === 'object'\n  );\n}\n\nexport interface ExternalProps<S, A extends Action<string>> {\n  dispatch: Dispatch<Action | LiftedAction<S, A, RtkQueryMonitorState>>;\n  theme: keyof typeof base16Themes | Base16Theme;\n  hideMainButtons?: boolean;\n  invertTheme: boolean;\n}\n\nexport interface QueryInfo {\n  type: 'query';\n  state: RtkQueryState;\n  queryKey: string;\n  reducerPath: string;\n}\n\nexport interface MutationInfo {\n  type: 'mutation';\n  state: RtkMutationState;\n  queryKey: string;\n  reducerPath: string;\n}\n\nexport type RtkResourceInfo = QueryInfo | MutationInfo;\n\nexport interface ApiInfo {\n  reducerPath: string;\n  apiState: RtkQueryApiState;\n}\n\nexport interface SelectOption<\n  T = string,\n  VisConfig extends string = 'default',\n> {\n  label: string;\n  value: T;\n  visible?: Record<VisConfig | 'default', boolean> | boolean;\n}\n\nexport interface SelectorsSource<S> {\n  userState: S | null;\n  monitorState: RtkQueryMonitorState;\n  currentStateIndex: number;\n  actionsById: LiftedState<unknown, AnyAction, unknown>['actionsById'];\n}\n\nexport interface StyleUtils {\n  readonly base16Theme: Base16Theme;\n  readonly invertTheme: boolean;\n}\n\nexport type RTKQuerySubscribers = NonNullable<\n  RtkQueryApiState['subscriptions'][keyof RtkQueryApiState['subscriptions']]\n>;\n\nexport interface RtkQueryTag {\n  type: string;\n  id?: number | string;\n}\n\ninterface Tally {\n  count: number;\n}\n\nexport type QueryTally = {\n  [key in QueryStatus]?: number;\n} & Tally;\n\nexport interface RtkRequestTiming {\n  requestId: string;\n  queryKey: string;\n  endpointName: string;\n  startedAt: string;\n  completedAt: string;\n  duration: string;\n}\n\nexport interface QueryTimings {\n  readonly oldest: RtkRequestTiming | null;\n  readonly latest: RtkRequestTiming | null;\n  readonly slowest: RtkRequestTiming | null;\n  readonly fastest: RtkRequestTiming | null;\n  readonly average: string;\n  readonly median: string;\n}\n\nexport interface ApiTimings {\n  readonly queries: QueryTimings;\n  readonly mutations: QueryTimings;\n}\n\nexport interface ApiStats {\n  readonly timings: ApiTimings;\n  readonly tally: Readonly<{\n    subscriptions: number;\n    cachedQueries: QueryTally;\n    tagTypes: number;\n    cachedMutations: QueryTally;\n  }>;\n}\n\nexport interface TabOption<\n  S,\n  P,\n  V extends string = 'default',\n> extends SelectOption<S, V> {\n  component: ComponentType<P>;\n}\n\n/**\n * It is Omit<RequestStatusFlags, 'status'> & { isFetching: boolean; }\n */\nexport interface RTKStatusFlags {\n  readonly isUninitialized: boolean;\n  readonly isFetching: boolean;\n  readonly isSuccess: boolean;\n  readonly isError: boolean;\n}\n\nexport type RtkRequest = {\n  status: QueryStatus;\n  queryKey: string;\n  requestId: string;\n  endpointName: string;\n  startedTimeStamp?: number;\n  fulfilledTimeStamp?: number;\n};\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/utils/a11y.ts",
    "content": "import { QueryPreviewTabs } from '../types.js';\n\nexport function renderTabPanelId(value: QueryPreviewTabs): string {\n  return `rtk-query-monitor-tab-panel-${value}`;\n}\n\nexport function renderTabPanelButtonId(value: QueryPreviewTabs): string {\n  return renderTabPanelId(value) + '-button';\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/utils/comparators.ts",
    "content": "import { QueryStatus } from '@reduxjs/toolkit/query';\nimport { RtkResourceInfo, SelectOption } from '../types.js';\n\nexport interface Comparator<T> {\n  (a: T, b: T): number;\n}\n\nexport enum QueryComparators {\n  fulfilledTimeStamp = 'timestamp',\n  queryKey = 'key',\n  status = 'status',\n  endpointName = 'endpointName',\n  apiReducerPath = 'apiReducerPath',\n}\n\nexport const sortQueryOptions: SelectOption<QueryComparators>[] = [\n  { label: 'last updated', value: QueryComparators.fulfilledTimeStamp },\n  { label: 'query key', value: QueryComparators.queryKey },\n  { label: 'status', value: QueryComparators.status },\n  { label: 'endpoint', value: QueryComparators.endpointName },\n  { label: 'reducerPath', value: QueryComparators.apiReducerPath },\n];\n\nfunction sortQueryByFulfilled(\n  thisQueryInfo: RtkResourceInfo,\n  thatQueryInfo: RtkResourceInfo,\n): number {\n  const thisFulfilled = thisQueryInfo.state.fulfilledTimeStamp ?? -1;\n  const thatFulfilled = thatQueryInfo.state.fulfilledTimeStamp ?? -1;\n\n  return thisFulfilled - thatFulfilled;\n}\n\nconst mapStatusToFactor = {\n  [QueryStatus.uninitialized]: 1,\n  [QueryStatus.pending]: 2,\n  [QueryStatus.rejected]: 3,\n  [QueryStatus.fulfilled]: 4,\n};\n\nfunction sortQueryByStatus(\n  thisQueryInfo: RtkResourceInfo,\n  thatQueryInfo: RtkResourceInfo,\n): number {\n  const thisTerm = mapStatusToFactor[thisQueryInfo.state.status] || -1;\n  const thatTerm = mapStatusToFactor[thatQueryInfo.state.status] || -1;\n\n  return thisTerm - thatTerm;\n}\n\nexport function compareJSONPrimitive<\n  T extends string | number | boolean | null,\n>(a: T, b: T): number {\n  if (a === b) {\n    return 0;\n  }\n\n  if (a == null) return -1;\n  if (b == null) return 1;\n\n  return a > b ? 1 : -1;\n}\n\nfunction sortByQueryKey(\n  thisQueryInfo: RtkResourceInfo,\n  thatQueryInfo: RtkResourceInfo,\n): number {\n  return compareJSONPrimitive(thisQueryInfo.queryKey, thatQueryInfo.queryKey);\n}\n\nfunction sortQueryByEndpointName(\n  thisQueryInfo: RtkResourceInfo,\n  thatQueryInfo: RtkResourceInfo,\n): number {\n  const thisEndpointName = thisQueryInfo.state.endpointName ?? '';\n  const thatEndpointName = thatQueryInfo.state.endpointName ?? '';\n\n  return compareJSONPrimitive(thisEndpointName, thatEndpointName);\n}\n\nfunction sortByApiReducerPath(\n  thisQueryInfo: RtkResourceInfo,\n  thatQueryInfo: RtkResourceInfo,\n): number {\n  return compareJSONPrimitive(\n    thisQueryInfo.reducerPath,\n    thatQueryInfo.reducerPath,\n  );\n}\n\nexport const queryComparators: Readonly<\n  Record<QueryComparators, Comparator<RtkResourceInfo>>\n> = {\n  [QueryComparators.fulfilledTimeStamp]: sortQueryByFulfilled,\n  [QueryComparators.status]: sortQueryByStatus,\n  [QueryComparators.endpointName]: sortQueryByEndpointName,\n  [QueryComparators.queryKey]: sortByQueryKey,\n  [QueryComparators.apiReducerPath]: sortByApiReducerPath,\n};\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/utils/filters.ts",
    "content": "import { RtkResourceInfo, SelectOption } from '../types.js';\n\nexport interface FilterList<T> {\n  (regex: RegExp | null, list: T[]): T[];\n}\n\nexport enum QueryFilters {\n  queryKey = 'query key',\n  reducerPath = 'reducerPath',\n  endpointName = 'endpoint',\n  status = 'status',\n}\n\nfunction filterByQueryKey(\n  regex: RegExp | null,\n  list: RtkResourceInfo[],\n): RtkResourceInfo[] {\n  if (!regex) {\n    return list;\n  }\n\n  return list.filter((RtkResourceInfo) => regex.test(RtkResourceInfo.queryKey));\n}\n\nfunction filterByReducerPath(\n  regex: RegExp | null,\n  list: RtkResourceInfo[],\n): RtkResourceInfo[] {\n  if (!regex) {\n    return list;\n  }\n\n  return list.filter((RtkResourceInfo) =>\n    regex.test(RtkResourceInfo.reducerPath),\n  );\n}\n\nfunction filterByEndpointName(\n  regex: RegExp | null,\n  list: RtkResourceInfo[],\n): RtkResourceInfo[] {\n  if (!regex) {\n    return list;\n  }\n\n  return list.filter((RtkResourceInfo) =>\n    regex.test(RtkResourceInfo.state.endpointName ?? 'undefined'),\n  );\n}\n\nfunction filterByStatus(\n  regex: RegExp | null,\n  list: RtkResourceInfo[],\n): RtkResourceInfo[] {\n  if (!regex) {\n    return list;\n  }\n\n  return list.filter((RtkResourceInfo) =>\n    regex.test(RtkResourceInfo.state.status),\n  );\n}\n\nexport const filterQueryOptions: SelectOption<QueryFilters>[] = [\n  { label: 'query key', value: QueryFilters.queryKey },\n  { label: 'reducerPath', value: QueryFilters.reducerPath },\n  { label: 'status', value: QueryFilters.status },\n  { label: 'endpoint', value: QueryFilters.endpointName },\n];\n\nexport const queryListFilters: Readonly<\n  Record<QueryFilters, FilterList<RtkResourceInfo>>\n> = {\n  [QueryFilters.queryKey]: filterByQueryKey,\n  [QueryFilters.endpointName]: filterByEndpointName,\n  [QueryFilters.reducerPath]: filterByReducerPath,\n  [QueryFilters.status]: filterByStatus,\n};\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/utils/formatters.ts",
    "content": "export function formatMs(milliseconds: number): string {\n  if (!Number.isFinite(milliseconds)) {\n    return 'NaN';\n  }\n\n  const absInput = Math.abs(Math.round(milliseconds));\n  let millis = (absInput % 1000).toString();\n\n  if (millis.length < 3) {\n    if (millis.length === 2) {\n      millis = '0' + millis;\n    } else {\n      millis = '00' + millis;\n    }\n  }\n\n  const seconds = Math.floor(absInput / 1_000) % 60;\n  const minutes = Math.floor(absInput / 60_000);\n\n  let output = `${seconds}.${millis}s`;\n\n  if (minutes > 0) {\n    output = `${minutes}m${output}`;\n  }\n\n  if (milliseconds < 0) {\n    output = `-${output}`;\n  }\n\n  return output;\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/utils/isIterable.ts",
    "content": "export default function isIterable(obj: unknown): boolean {\n  return (\n    obj !== null &&\n    typeof obj === 'object' &&\n    !Array.isArray(obj) &&\n    typeof (obj as Record<string | typeof Symbol.iterator, unknown>)[\n      window.Symbol.iterator\n    ] === 'function'\n  );\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/utils/object.ts",
    "content": "import { freeze } from '@reduxjs/toolkit';\n\nexport const emptyArray = freeze([]);\n\nexport const emptyRecord = freeze({});\n\nexport function identity<T>(val: T): T {\n  return val;\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/utils/regexp.ts",
    "content": "// https://stackoverflow.com/a/9310752\nexport function escapeRegExpSpecialCharacter(text: string): string {\n  return text.replace(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g, '\\\\$&');\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/utils/rtk-query.ts",
    "content": "import { Action, AnyAction, isAllOf, isPlainObject } from '@reduxjs/toolkit';\nimport { QueryCacheKey, QueryStatus } from '@reduxjs/toolkit/query';\nimport {\n  QueryInfo,\n  RtkQueryMonitorState,\n  RtkQueryApiState,\n  RTKQuerySubscribers,\n  RtkQueryTag,\n  RTKStatusFlags,\n  RtkQueryState,\n  MutationInfo,\n  ApiStats,\n  QueryTally,\n  RtkQueryProvidedTagsState,\n  RtkQuery262ProvidedState,\n  ApiTimings,\n  QueryTimings,\n  SelectorsSource,\n  RtkMutationState,\n  RtkResourceInfo,\n  RtkRequest,\n  RtkRequestTiming,\n  isRtkQuery262Provided,\n} from '../types.js';\nimport { missingTagId } from '../monitor-config.js';\nimport { Comparator, compareJSONPrimitive } from './comparators.js';\nimport { emptyArray } from './object.js';\nimport { formatMs } from './formatters.js';\nimport * as statistics from './statistics.js';\n\nconst rtkqueryApiStateKeys: ReadonlyArray<keyof RtkQueryApiState> = [\n  'queries',\n  'mutations',\n  'config',\n  'provided',\n  'subscriptions',\n];\n\n/**\n * Type guard used to select apis from the user store state.\n * @param val\n * @returns {boolean}\n */\nexport function isApiSlice(val: unknown): val is RtkQueryApiState {\n  if (!isPlainObject(val)) {\n    return false;\n  }\n\n  for (let i = 0, len = rtkqueryApiStateKeys.length; i < len; i++) {\n    if (\n      !isPlainObject((val as Record<string, unknown>)[rtkqueryApiStateKeys[i]])\n    ) {\n      return false;\n    }\n  }\n\n  return true;\n}\n\n/**\n * Indexes api states by their `reducerPath`.\n *\n * Returns `null` if there are no api slice or `reduxStoreState`\n * is not an object.\n *\n * @param reduxStoreState\n * @returns\n */\nexport function getApiStatesOf(\n  reduxStoreState: unknown,\n): null | Readonly<Record<string, RtkQueryApiState>> {\n  if (!isPlainObject(reduxStoreState)) {\n    return null;\n  }\n\n  const output: null | Record<string, RtkQueryApiState> = {};\n  const keys = Object.keys(reduxStoreState);\n\n  for (let i = 0, len = keys.length; i < len; i++) {\n    const key = keys[i];\n    const value = (reduxStoreState as Record<string, unknown>)[key];\n\n    if (isApiSlice(value)) {\n      output[key] = value;\n    }\n  }\n\n  if (Object.keys(output).length === 0) {\n    return null;\n  }\n\n  return output;\n}\n\nexport function extractAllApiQueries(\n  apiStatesByReducerPath: null | Readonly<Record<string, RtkQueryApiState>>,\n): ReadonlyArray<QueryInfo> {\n  if (!apiStatesByReducerPath) {\n    return emptyArray;\n  }\n\n  const reducerPaths = Object.keys(apiStatesByReducerPath);\n\n  const output: QueryInfo[] = [];\n\n  for (let i = 0, len = reducerPaths.length; i < len; i++) {\n    const reducerPath = reducerPaths[i];\n    const api = apiStatesByReducerPath[reducerPath];\n    const queryKeys = Object.keys(api.queries);\n\n    for (let j = 0, qKeysLen = queryKeys.length; j < qKeysLen; j++) {\n      const queryKey = queryKeys[j];\n      const state = api.queries[queryKey];\n\n      if (state) {\n        output.push({\n          type: 'query',\n          reducerPath,\n          queryKey,\n          state,\n        });\n      }\n    }\n  }\n\n  return output;\n}\n\nexport function extractAllApiMutations(\n  apiStatesByReducerPath: null | Readonly<Record<string, RtkQueryApiState>>,\n): ReadonlyArray<MutationInfo> {\n  if (!apiStatesByReducerPath) {\n    return emptyArray;\n  }\n\n  const reducerPaths = Object.keys(apiStatesByReducerPath);\n  const output: MutationInfo[] = [];\n\n  for (let i = 0, len = reducerPaths.length; i < len; i++) {\n    const reducerPath = reducerPaths[i];\n    const api = apiStatesByReducerPath[reducerPath];\n    const mutationKeys = Object.keys(api.mutations);\n\n    for (let j = 0, mKeysLen = mutationKeys.length; j < mKeysLen; j++) {\n      const queryKey = mutationKeys[j];\n      const state = api.mutations[queryKey];\n\n      if (state) {\n        output.push({\n          type: 'mutation',\n          reducerPath,\n          queryKey,\n          state,\n        });\n      }\n    }\n  }\n\n  return output;\n}\n\nfunction computeQueryTallyOf(\n  queryState: RtkQueryApiState['queries'] | RtkQueryApiState['mutations'],\n): QueryTally {\n  const queries = Object.values(queryState);\n\n  const output: QueryTally = {\n    count: 0,\n  };\n\n  for (let i = 0, len = queries.length; i < len; i++) {\n    const query = queries[i];\n\n    if (query) {\n      output.count++;\n\n      if (!output[query.status]) {\n        output[query.status] = 1;\n      } else {\n        (output[query.status] as number)++;\n      }\n    }\n  }\n\n  return output;\n}\n\nfunction tallySubscriptions(\n  subsState: RtkQueryApiState['subscriptions'],\n): number {\n  const subsOfQueries = Object.values(subsState);\n\n  let output = 0;\n\n  for (let i = 0, len = subsOfQueries.length; i < len; i++) {\n    const subsOfQuery = subsOfQueries[i];\n\n    if (subsOfQuery) {\n      output += Object.keys(subsOfQuery).length;\n    }\n  }\n\n  return output;\n}\n\nfunction computeRtkQueryRequests(\n  type: 'queries' | 'mutations',\n  api: RtkQueryApiState,\n  sortedActions: AnyAction[],\n  currentStateIndex: SelectorsSource<unknown>['currentStateIndex'],\n): Readonly<Record<string, RtkRequest>> {\n  const requestById: Record<string, RtkRequest> = {};\n\n  const matcher =\n    type === 'queries'\n      ? matchesExecuteQuery(api.config.reducerPath)\n      : matchesExecuteMutation(api.config.reducerPath);\n\n  for (\n    let i = 0, len = sortedActions.length;\n    i < len && i <= currentStateIndex;\n    i++\n  ) {\n    const action = sortedActions[i];\n\n    if (matcher(action)) {\n      let requestRecord: RtkRequest | undefined =\n        requestById[action.meta.requestId];\n\n      if (!requestRecord) {\n        const queryCacheKey: string | undefined = (\n          action.meta as Record<string, any>\n        )?.arg?.queryCacheKey;\n\n        const queryKey =\n          typeof queryCacheKey === 'string'\n            ? queryCacheKey\n            : action.meta.requestId;\n\n        const endpointName: string =\n          (action.meta as any)?.arg?.endpointName ?? '-';\n\n        requestById[action.meta.requestId] = requestRecord = {\n          queryKey,\n          requestId: action.meta.requestId,\n          endpointName,\n          status: action.meta.requestStatus,\n        };\n      }\n\n      requestRecord.status = action.meta.requestStatus;\n\n      if (\n        action.meta.requestStatus === QueryStatus.pending &&\n        typeof (action.meta as any).startedTimeStamp === 'number'\n      ) {\n        requestRecord.startedTimeStamp = (action.meta as any).startedTimeStamp;\n      }\n\n      if (\n        action.meta.requestStatus === QueryStatus.fulfilled &&\n        typeof (action.meta as any).fulfilledTimeStamp === 'number'\n      ) {\n        requestRecord.fulfilledTimeStamp = (\n          action.meta as any\n        ).fulfilledTimeStamp;\n      }\n    }\n  }\n\n  const requestIds = Object.keys(requestById);\n\n  // Patch queries that have pending actions that are committed\n  for (let i = 0, len = requestIds.length; i < len; i++) {\n    const requestId = requestIds[i];\n    const request = requestById[requestId];\n\n    if (\n      typeof request.startedTimeStamp === 'undefined' &&\n      typeof request.fulfilledTimeStamp === 'number'\n    ) {\n      const startedTimeStampFromCache =\n        api[type][request.queryKey]?.startedTimeStamp;\n\n      if (typeof startedTimeStampFromCache === 'number') {\n        request.startedTimeStamp = startedTimeStampFromCache;\n      }\n    }\n  }\n\n  // Add queries that have pending and fulfilled actions committed\n  const queryCacheEntries = Object.entries(api[type] ?? {});\n\n  for (let i = 0, len = queryCacheEntries.length; i < len; i++) {\n    const [queryCacheKey, queryCache] = queryCacheEntries[i];\n    const requestId: string =\n      type === 'queries'\n        ? ((queryCache as (typeof api)['queries'][string])?.requestId ?? '')\n        : queryCacheKey;\n    if (\n      queryCache &&\n      !Object.prototype.hasOwnProperty.call(requestById, requestId)\n    ) {\n      const startedTimeStamp = queryCache?.startedTimeStamp;\n      const fulfilledTimeStamp = queryCache?.fulfilledTimeStamp;\n\n      if (\n        typeof startedTimeStamp === 'number' &&\n        typeof fulfilledTimeStamp === 'number'\n      ) {\n        requestById[requestId] = {\n          queryKey: queryCacheKey,\n          requestId,\n          endpointName: queryCache.endpointName ?? '',\n          startedTimeStamp,\n          fulfilledTimeStamp,\n          status: queryCache.status,\n        };\n      }\n    }\n  }\n\n  return requestById;\n}\n\nfunction formatRtkRequest(\n  rtkRequest: RtkRequest | null,\n): RtkRequestTiming | null {\n  if (!rtkRequest) {\n    return null;\n  }\n\n  const fulfilledTimeStamp = rtkRequest.fulfilledTimeStamp;\n  const startedTimeStamp = rtkRequest.startedTimeStamp;\n\n  const output: RtkRequestTiming = {\n    queryKey: rtkRequest.queryKey,\n    requestId: rtkRequest.requestId,\n    endpointName: rtkRequest.endpointName,\n    startedAt: '-',\n    completedAt: '-',\n    duration: '-',\n  };\n\n  if (\n    typeof fulfilledTimeStamp === 'number' &&\n    typeof startedTimeStamp === 'number'\n  ) {\n    output.startedAt = new Date(startedTimeStamp).toISOString();\n    output.completedAt = new Date(fulfilledTimeStamp).toISOString();\n    output.duration = formatMs(fulfilledTimeStamp - startedTimeStamp);\n  }\n\n  return output;\n}\n\nfunction computeQueryApiTimings(\n  requestById: Readonly<Record<string, RtkRequest>>,\n): QueryTimings {\n  const requests = Object.values(requestById);\n\n  let latestRequest: RtkRequest | null = null;\n  let oldestRequest: null | RtkRequest = null;\n  let slowestRequest: RtkRequest | null = null;\n  let fastestRequest: RtkRequest | null = null;\n  let slowestDuration = 0;\n  let fastestDuration = Number.MAX_SAFE_INTEGER;\n\n  const pendingDurations: number[] = [];\n\n  for (let i = 0, len = requests.length; i < len; i++) {\n    const request = requests[i];\n    const { fulfilledTimeStamp, startedTimeStamp } = request;\n\n    if (typeof fulfilledTimeStamp === 'number') {\n      const latestFulfilledTimeStamp = latestRequest?.fulfilledTimeStamp || 0;\n      const oldestFulfilledTimeStamp =\n        oldestRequest?.fulfilledTimeStamp || Number.MAX_SAFE_INTEGER;\n\n      if (fulfilledTimeStamp > latestFulfilledTimeStamp) {\n        latestRequest = request;\n      }\n\n      if (fulfilledTimeStamp < oldestFulfilledTimeStamp) {\n        oldestRequest = request;\n      }\n\n      if (\n        typeof startedTimeStamp === 'number' &&\n        startedTimeStamp <= fulfilledTimeStamp\n      ) {\n        const pendingDuration = fulfilledTimeStamp - startedTimeStamp;\n        pendingDurations.push(pendingDuration);\n\n        if (pendingDuration > slowestDuration) {\n          slowestDuration = pendingDuration;\n          slowestRequest = request;\n        }\n\n        if (pendingDuration < fastestDuration) {\n          fastestDuration = pendingDuration;\n          fastestRequest = request;\n        }\n      }\n    }\n  }\n\n  const average =\n    pendingDurations.length > 0\n      ? formatMs(statistics.mean(pendingDurations))\n      : '-';\n\n  const median =\n    pendingDurations.length > 0\n      ? formatMs(statistics.median(pendingDurations))\n      : '-';\n\n  return {\n    latest: formatRtkRequest(latestRequest),\n    oldest: formatRtkRequest(oldestRequest),\n    slowest: formatRtkRequest(slowestRequest),\n    fastest: formatRtkRequest(fastestRequest),\n    average,\n    median,\n  };\n}\n\nfunction computeApiTimings(\n  api: RtkQueryApiState,\n  actionsById: SelectorsSource<unknown>['actionsById'],\n  currentStateIndex: SelectorsSource<unknown>['currentStateIndex'],\n): ApiTimings {\n  const sortedActions = Object.entries(actionsById)\n    .sort((thisAction, thatAction) =>\n      compareJSONPrimitive(Number(thisAction[0]), Number(thatAction[0])),\n    )\n    .map((entry) => entry[1].action);\n\n  const queryRequestsById = computeRtkQueryRequests(\n    'queries',\n    api,\n    sortedActions,\n    currentStateIndex,\n  );\n\n  const mutationRequestsById = computeRtkQueryRequests(\n    'mutations',\n    api,\n    sortedActions,\n    currentStateIndex,\n  );\n\n  return {\n    queries: computeQueryApiTimings(queryRequestsById),\n    mutations: computeQueryApiTimings(mutationRequestsById),\n  };\n}\n\nexport function generateApiStatsOfCurrentQuery(\n  api: RtkQueryApiState | null,\n  actionsById: SelectorsSource<unknown>['actionsById'],\n  currentStateIndex: SelectorsSource<unknown>['currentStateIndex'],\n): ApiStats | null {\n  if (!api) {\n    return null;\n  }\n\n  return {\n    timings: computeApiTimings(api, actionsById, currentStateIndex),\n    tally: {\n      cachedQueries: computeQueryTallyOf(api.queries),\n      cachedMutations: computeQueryTallyOf(api.mutations),\n      tagTypes: Object.keys(api.provided).length,\n      subscriptions: tallySubscriptions(api.subscriptions),\n    },\n  };\n}\n\nexport function flipComparator<T>(comparator: Comparator<T>): Comparator<T> {\n  return function flipped(a: T, b: T) {\n    return comparator(b, a);\n  };\n}\n\nexport function isQuerySelected(\n  selectedQueryKey: RtkQueryMonitorState['selectedQueryKey'],\n  queryInfo: RtkResourceInfo,\n): boolean {\n  return (\n    !!selectedQueryKey &&\n    selectedQueryKey.queryKey === queryInfo.queryKey &&\n    selectedQueryKey.reducerPath === queryInfo.reducerPath\n  );\n}\n\nexport function getApiStateOf(\n  queryInfo: RtkResourceInfo | null,\n  apiStates: ReturnType<typeof getApiStatesOf>,\n): RtkQueryApiState | null {\n  if (!apiStates || !queryInfo) {\n    return null;\n  }\n\n  return apiStates[queryInfo.reducerPath] ?? null;\n}\n\nexport function getQuerySubscriptionsOf(\n  queryInfo: QueryInfo | null,\n  apiStates: ReturnType<typeof getApiStatesOf>,\n): RTKQuerySubscribers | null {\n  if (!apiStates || !queryInfo) {\n    return null;\n  }\n\n  return (\n    apiStates[queryInfo.reducerPath]?.subscriptions?.[queryInfo.queryKey] ??\n    null\n  );\n}\n\nexport function getProvidedOf(\n  queryInfo: QueryInfo | null,\n  apiStates: ReturnType<typeof getApiStatesOf>,\n): RtkQueryApiState['provided'] | null {\n  if (!apiStates || !queryInfo) {\n    return null;\n  }\n\n  return apiStates[queryInfo.reducerPath]?.provided ?? null;\n}\n\nexport function getQueryTagsOf(\n  resInfo: RtkResourceInfo | null,\n  provided: RtkQueryProvidedTagsState | RtkQuery262ProvidedState | null,\n): RtkQueryTag[] {\n  if (!resInfo || resInfo.type === 'mutation' || !provided) {\n    return emptyArray;\n  }\n\n  // Handle `api.provided` schema change with RTK Query tag handling.\n  // Originally, `api.provided` was a `Record<string, Record<string, string[]>>`,\n  // directly containing the tag names.\n  // With https://github.com/reduxjs/redux-toolkit/pull/4910 , that changes to\n  // change the top level to be `{tags, keys}`, with `tags` containing the tag names.\n  // Handle the newer structure by extracting the right field if it exists.\n  const actualProvided: RtkQueryProvidedTagsState = isRtkQuery262Provided(\n    provided,\n  )\n    ? provided.tags\n    : provided;\n\n  const tagTypes = Object.keys(actualProvided);\n\n  if (tagTypes.length < 1) {\n    return emptyArray;\n  }\n\n  const output: RtkQueryTag[] = [];\n\n  for (const [type, tagIds] of Object.entries(actualProvided)) {\n    if (tagIds) {\n      for (const [id, queryKeys] of Object.entries(tagIds)) {\n        if (queryKeys.includes(resInfo.queryKey as QueryCacheKey)) {\n          const tag: RtkQueryTag = { type };\n\n          if (id !== missingTagId) {\n            tag.id = id;\n          }\n\n          output.push(tag);\n        }\n      }\n    }\n  }\n\n  return output;\n}\n\n/**\n * Computes query status flags.\n * @param status\n * @see https://redux-toolkit.js.org/rtk-query/usage/queries#frequently-used-query-hook-return-values\n * @see https://github.com/reduxjs/redux-toolkit/blob/b718e01d323d3ab4b913e5d88c9b90aa790bb975/src/query/core/apiState.ts#L63\n */\nexport function getQueryStatusFlags({\n  status,\n  data,\n}: RtkQueryState | RtkMutationState): RTKStatusFlags {\n  return {\n    isUninitialized: status === QueryStatus.uninitialized,\n    isFetching: status === QueryStatus.pending,\n    isSuccess: status === QueryStatus.fulfilled && !!data,\n    isError: status === QueryStatus.rejected,\n  };\n}\n\n/**\n * endpoint matcher\n * @param endpointName\n * @see https://github.com/reduxjs/redux-toolkit/blob/b718e01d323d3ab4b913e5d88c9b90aa790bb975/src/query/core/buildThunks.ts#L415\n */\nexport function matchesEndpoint(endpointName: unknown) {\n  return (action: any): action is Action =>\n    endpointName != null && action?.meta?.arg?.endpointName === endpointName;\n}\n\nfunction matchesQueryKey(queryKey: string) {\n  return (action: any): action is Action =>\n    action?.meta?.arg?.queryCacheKey === queryKey;\n}\n\nfunction macthesRequestId(requestId: string) {\n  return (action: any): action is Action =>\n    action?.meta?.requestId === requestId;\n}\n\nfunction matchesReducerPath(reducerPath: string) {\n  return (action: any): action is Action<string> =>\n    typeof action?.type === 'string' && action.type.startsWith(reducerPath);\n}\n\nfunction matchesExecuteQuery(reducerPath: string) {\n  return (\n    action: any,\n  ): action is Action<string> & {\n    meta: { requestId: string; requestStatus: QueryStatus };\n  } => {\n    return (\n      typeof action?.type === 'string' &&\n      action.type.startsWith(`${reducerPath}/executeQuery`) &&\n      typeof action.meta?.requestId === 'string' &&\n      typeof action.meta?.requestStatus === 'string'\n    );\n  };\n}\n\nfunction matchesExecuteMutation(reducerPath: string) {\n  return (\n    action: any,\n  ): action is Action<string> & {\n    meta: { requestId: string; requestStatus: QueryStatus };\n  } =>\n    typeof action?.type === 'string' &&\n    action.type.startsWith(`${reducerPath}/executeMutation`) &&\n    typeof action.meta?.requestId === 'string' &&\n    typeof action.meta?.requestStatus === 'string';\n}\n\nexport function getActionsOfCurrentQuery(\n  currentQuery: RtkResourceInfo | null,\n  actionById: SelectorsSource<unknown>['actionsById'],\n): Action[] {\n  if (!currentQuery) {\n    return emptyArray;\n  }\n\n  let matcher: ReturnType<typeof macthesRequestId>;\n\n  if (currentQuery.type === 'mutation') {\n    matcher = isAllOf(\n      matchesReducerPath(currentQuery.reducerPath),\n      macthesRequestId(currentQuery.queryKey),\n    );\n  } else {\n    matcher = isAllOf(\n      matchesReducerPath(currentQuery.reducerPath),\n      matchesQueryKey(currentQuery.queryKey),\n    );\n  }\n\n  const output: AnyAction[] = [];\n\n  for (const [, liftedAction] of Object.entries(actionById)) {\n    if (matcher(liftedAction?.action)) {\n      output.push(liftedAction.action);\n    }\n  }\n\n  return output.length === 0 ? emptyArray : output;\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/utils/statistics.ts",
    "content": "/**\n * An implementation of `Kahan-Babuska algorithm`\n * that reduces numerical floating point errors.\n * @param {number[]} nums\n * @returns {number}\n * @see https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.582.288&rep=rep1&type=pdf\n */\nfunction sum(nums: number[]): number {\n  if (nums.length === 0) {\n    return 0;\n  }\n\n  let t;\n  let correction = 0;\n  let output = nums[0];\n\n  for (let i = 1, len = nums.length; i < len; i++) {\n    t = output + nums[i];\n\n    if (Math.abs(output) >= Math.abs(nums[i])) {\n      correction += output - t + nums[i];\n    } else {\n      correction += nums[i] - t + output;\n    }\n\n    output = t;\n  }\n\n  return output + correction;\n}\n\n/**\n * Returns mean, also known as average, of numerical sequences.\n * @param nums\n * @returns\n */\nexport function mean(nums: number[]): number {\n  if (nums.length === 0) {\n    return NaN;\n  }\n\n  return +(sum(nums) / nums.length).toFixed(6);\n}\n\n/**\n * Returns median value of a numeric sequence.\n * @param nums\n * @returns\n */\nexport function median(nums: number[]): number {\n  const len = nums.length;\n\n  if (len === 0) {\n    return NaN;\n  }\n\n  if (len === 1) {\n    return nums[0];\n  }\n\n  const sorted = nums.slice().sort();\n\n  if (len % 2 === 1) {\n    return sorted[(len + 1) / 2 - 1];\n  }\n\n  return +(0.5 * (sorted[len / 2 - 1] + sorted[len / 2])).toFixed(6);\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/src/utils/tabs.ts",
    "content": "import { TabOption } from '../types.js';\n\nexport function isTabVisible<St, Props, Vis extends string>(\n  tab: TabOption<St, Props, Vis>,\n  visKey: Vis | 'default',\n): boolean {\n  if (typeof tab.visible === 'boolean') {\n    return tab.visible;\n  }\n\n  if (typeof tab.visible === 'object' && tab.visible) {\n    return !!tab.visible[visKey];\n  }\n\n  return true;\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/test/__mocks__/styleMock.ts",
    "content": "export default {};\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/test/devtools.mocks.tsx",
    "content": "import * as React from 'react';\nimport { createDevTools } from '@redux-devtools/core';\nimport { RtkQueryMonitor } from '../src/index.js';\n\nconst MonitorAsAny = RtkQueryMonitor as any;\n\nexport const ReduxDevTools = createDevTools(<MonitorAsAny />);\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/test/integration.spec.tsx",
    "content": "import { jest } from '@jest/globals';\nimport * as React from 'react';\nimport { Provider } from 'react-redux';\nimport { render, screen, fireEvent, waitFor } from '@testing-library/react';\nimport { ReduxDevTools } from './devtools.mocks.js';\nimport { BaseQueryJestMockFunction, setupStore } from './rtk-query.mocks.js';\n\nfunction Providers({\n  store,\n  children,\n}: {\n  store: ReturnType<typeof setupStore>['store'];\n  children?: React.ComponentProps<typeof Provider>['children'];\n}) {\n  const AnyProvider = Provider as any;\n\n  return (\n    <div id=\"app-root\">\n      <AnyProvider store={store}>\n        {children}\n        <ReduxDevTools />\n      </AnyProvider>\n    </div>\n  );\n}\n\ndescribe('rtk-query-monitor standalone integration', () => {\n  // Hushes symbol.observable warning\n  // @see https://github.com/reduxjs/redux-devtools/issues/1002\n  jest.spyOn(console, 'warn');\n  // eslint-disable-next-line @typescript-eslint/no-empty-function\n  (console.warn as jest.Mock<void>).mockImplementation(() => {});\n\n  const dataPanelDomId = '#rtk-query-monitor-tab-panel-0';\n\n  const childrenTextContent = 'Renders children';\n  const fetchBaseQueryMock: BaseQueryJestMockFunction<Record<string, unknown>> =\n    jest.fn((...fetchArgs) =>\n      Promise.resolve({\n        data: {\n          name: fetchArgs[0],\n        },\n      }),\n    );\n  const { store, pokemonApi } = setupStore(fetchBaseQueryMock, ReduxDevTools);\n\n  beforeAll(() => {\n    // let's populate api\n    (store.dispatch as any)(\n      pokemonApi.endpoints.getPokemonByName.initiate('bulbasaur'),\n    );\n  });\n\n  beforeEach(() => {\n    fetchBaseQueryMock.mockClear();\n  });\n\n  afterAll(() => {\n    (console.warn as jest.Mock<void>).mockRestore();\n  });\n\n  it('renders on a standalone app without crashing', () => {\n    const { container } = render(\n      <Providers store={store}>\n        <div data-testid=\"children\">{childrenTextContent}</div>\n      </Providers>,\n    );\n\n    expect(screen.getByTestId('children').textContent).toBe(\n      childrenTextContent,\n    );\n\n    expect(\n      screen\n        .getByRole('tab', { name: /actions/i })\n        ?.textContent?.toLowerCase()\n        .trim(),\n    ).toBe('actions');\n    expect(\n      screen\n        .getByRole('tab', { name: /data/i })\n        ?.textContent?.toLowerCase()\n        .trim(),\n    ).toBe('data');\n    expect(\n      screen\n        .getByRole('tab', { name: /api/i })\n        ?.textContent?.toLowerCase()\n        .trim(),\n    ).toBe('api');\n    expect(\n      container.querySelector(\n        'form[id=\"rtk-query-monitor-query-selection-form\"]',\n      ),\n    ).toBeDefined();\n  });\n\n  it('displays query data tab content', async () => {\n    // `Promise.resolve()` hushes `@typescript-eslint/await-thenable`\n    await Promise.resolve(\n      store.dispatch(pokemonApi.util.getRunningQueriesThunk() as any),\n    );\n\n    const { container } = render(\n      <Providers store={store}>\n        <div data-testid=\"children\">{childrenTextContent}</div>\n      </Providers>,\n    );\n\n    // We need to select the query & the correct tab\n    fireEvent.click(screen.getByRole('tab', { name: /data/i }));\n    fireEvent.click(screen.getByText(/bulbasaur/i));\n\n    await waitFor(() =>\n      expect(container.querySelector(dataPanelDomId)).not.toBeNull(),\n    );\n\n    expect(container.querySelector(dataPanelDomId)?.textContent).toMatch(\n      /name\\W+pokemon\\/bulbasaur/i,\n    );\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/test/rtk-query.mocks.ts",
    "content": "import {\n  combineReducers,\n  configureStore,\n  EnhancedStore,\n} from '@reduxjs/toolkit';\nimport { createApi } from '@reduxjs/toolkit/query/react';\nimport type { BaseQueryFn, FetchArgs } from '@reduxjs/toolkit/query';\nimport type { ReduxDevTools } from './devtools.mocks.js';\n\nexport type MockBaseQuery<\n  Result,\n  Args = string | FetchArgs,\n  Meta = { status?: number },\n> = BaseQueryFn<Args, Result, unknown, Meta>;\n\nexport type BaseQueryJestMockFunction<Result> = jest.Mock<\n  ReturnType<MockBaseQuery<Result>>,\n  Parameters<MockBaseQuery<Result>>\n>;\n\nexport function createMockBaseQuery<Result>(\n  jestMockFn: BaseQueryJestMockFunction<Result>,\n): MockBaseQuery<Result> {\n  return async function mockBaseQuery(param, api, extra) {\n    try {\n      const output = await jestMockFn(param, api, extra);\n\n      return output;\n    } catch (error) {\n      return {\n        error,\n      };\n    }\n  };\n}\n\nexport function createPokemonApi(\n  jestMockFn: BaseQueryJestMockFunction<Record<string, any>>,\n) {\n  return createApi({\n    reducerPath: 'pokemonApi',\n    keepUnusedDataFor: 9999,\n    baseQuery: createMockBaseQuery(jestMockFn),\n    tagTypes: ['pokemon'],\n    endpoints: (builder) => ({\n      getPokemonByName: builder.query<Record<string, any>, string>({\n        query: (name: string) => `pokemon/${name}`,\n        providesTags: (result, error, name: string) => [\n          { type: 'pokemon' },\n          { type: 'pokemon', id: name },\n        ],\n      }),\n    }),\n  });\n}\n\nexport function setupStore(\n  jestMockFn: BaseQueryJestMockFunction<Record<string, any>>,\n  devTools: typeof ReduxDevTools,\n) {\n  const pokemonApi = createPokemonApi(jestMockFn);\n\n  const reducer = combineReducers({\n    [pokemonApi.reducerPath]: pokemonApi.reducer,\n  });\n\n  const store: EnhancedStore<ReturnType<typeof reducer>> = configureStore({\n    reducer,\n    devTools: false,\n    // adding the api middleware enables caching, invalidation, polling and other features of `rtk-query`\n    middleware: (getDefaultMiddleware) =>\n      getDefaultMiddleware().concat(pokemonApi.middleware),\n    enhancers: (getDefaultEnhancers) =>\n      getDefaultEnhancers().concat(devTools.instrument()),\n  });\n\n  return {\n    jestMockFn,\n    devTools,\n    store,\n    reducer,\n    pokemonApi,\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\",\n    \"resolveJsonModule\": true,\n    \"jsx\": \"react-jsx\",\n    \"jsxImportSource\": \"@emotion/react\",\n    \"stripInternal\": true\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-rtk-query-monitor/tsconfig.test.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"jest\"],\n    \"jsx\": \"react-jsx\",\n    \"jsxImportSource\": \"@emotion/react\"\n  },\n  \"include\": [\"src\", \"test\"],\n  \"exclude\": [\"dist\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-serialize/CHANGELOG.md",
    "content": "# Change Log\n\n## 1.0.0\n\n### Major Changes\n\n- 6481386: Convert remaining packages to ESM\n\n## 0.4.2\n\n### Patch Changes\n\n- 7f5bddbd: Widen peer dependencies\n\n## 0.4.0\n\n- Adds ESM build (https://github.com/reduxjs/redux-devtools/pull/997) and switches the default export to a named export in order to ensure that the CommonJS output and the ESM output are [interchangeable](https://rollupjs.org/guide/en/#outputexports):\n\n```diff\n- import Serialize from '@redux-devtools/serialize';\n+ import { immutable } from '@redux-devtools/serialize';\n```\n\n## 0.3.0 (2021-03-06)\n\n### Features\n\n- **redux-devtools-serialize:** convert to TypeScript ([#621](https://github.com/reduxjs/redux-devtools/issues/621)) ([d586f19](https://github.com/reduxjs/redux-devtools/commit/d586f1955a3648883107f8c981ee17eeb4c013a3))\n\n## 0.2.0 (2020-09-07)\n\n### Features\n\n- **redux-devtools-serialize:** convert to TypeScript ([#621](https://github.com/reduxjs/redux-devtools/issues/621)) ([d586f19](https://github.com/reduxjs/redux-devtools/commit/d586f1955a3648883107f8c981ee17eeb4c013a3))\n\n## 0.1.9 (2020-08-14)\n\n**Note:** Version bump only for package remotedev-serialize\n"
  },
  {
    "path": "packages/redux-devtools-serialize/README.md",
    "content": "# Serialize ImmutableJS data\n\n### Installation\n\n```\nyarn add @redux-devtools/serialize\n```\n\n### Usage with ImmutableJS data structures\n\nJust pass the Immutable library to our class:\n\n```js\nimport Immutable from 'immutable';\nimport { immutable } from '@redux-devtools/serialize';\nconst { stringify, parse } = immutable(Immutable);\n\nconst data = Immutable.fromJS({ foo: 'bar', baz: { qux: 42 } });\nconst serialized = stringify(data);\nconsole.log(serialized);\n// {\"data\":{\"foo\":\"bar\",\"baz\":{\"data\":{\"qux\":42},\"__serializedType__\":\"ImmutableMap\"}},\"__serializedType__\":\"ImmutableMap\"}\nconst parsed = parse(serialized);\nconsole.log(Immutable.is(parsed, data));\n// true\n```\n\nSee [the tests](https://github.com/reduxjs/remote-devtools/blob/master/packages/remotedev-serialize/test/immutable.spec.js) for more examples of usage.\n\n### Usage with ImmutableJS Record classes\n\nTo parse a Record class back, you need to specify a reference to it:\n\n```js\nimport Immutable from 'immutable';\nimport { immutable } from '@redux-devtools/serialize';\n\nconst ABRecord = Immutable.Record({ a: 1, b: 2 });\nconst { stringify, parse } = immutable(Immutable, [ABRecord]);\n\nconst myRecord = new ABRecord({ b: 3 });\nconst serialized = stringify(myRecord);\nconsole.log(serialized);\n// {\"data\":{\"a\":1,\"b\":3},\"__serializedType__\":\"ImmutableRecord\",\"__serializedRef__\":0}\nconst parsed = parse(serialized);\nconsole.log(Immutable.is(parsed, myRecord));\n// true\n```\n\n### Passing custom serialization functions\n\nYou can pass custom replacer and reviver functions to Serialize:\n\n```js\nimport Immutable from 'immutable';\nimport { immutable } from '@redux-devtools/serialize';\n\nfunction customReplacer(key, value, defaultReplacer) {\n  if (value === 1) {\n    return { data: 'one', __serializedType__: 'number' };\n  }\n  return defaultReplacer(key, value);\n}\n\nfunction customReviver(key, value, defaultReviver) {\n  if (\n    typeof value === 'object' &&\n    value.__serializedType__ === 'number' &&\n    value.data === 'one'\n  ) {\n    return 1;\n  }\n  return defaultReviver(key, value);\n}\n\nconst { stringify, parse } = immutable(\n  Immutable,\n  null,\n  customReplacer,\n  customReviver,\n);\n\nconst map = Immutable.Map({ a: 1, b: 2 });\nconst serialized = stringify(map);\nconsole.log(serialized);\n// {\"data\":{\"a\":{\"data\":\"one\",\"__serializedType__\":\"number\"},\"b\":2},\"__serializedType__\":\"ImmutableMap\"}\nconst parsed = parse(serialized);\nconsole.log(Immutable.is(parsed, map));\n// true\n```\n\n### Supported\n\n#### ImutableJS\n\n- [x] Record\n- [x] Range\n- [x] Repeat\n- [x] Map\n- [x] OrderedMap\n- [x] List\n- [x] Set\n- [x] OrderedSet\n- [x] Seq\n- [x] Stack\n\n#### ES6\n\n- [x] Symbol\n- [x] Map\n- [x] Set\n- [ ] Typed Array\n\n### License\n\nMIT\n"
  },
  {
    "path": "packages/redux-devtools-serialize/eslint.config.mjs",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTs from '../../eslint.ts.config.base.mjs';\nimport eslintTsJest from '../../eslint.ts.jest.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTs(import.meta.dirname),\n  ...eslintTsJest(import.meta.dirname),\n  {\n    ignores: ['jest.config.ts', 'lib'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-serialize/jest.config.ts",
    "content": "import { createDefaultEsmPreset, type JestConfigWithTsJest } from 'ts-jest';\n\nconst presetConfig = createDefaultEsmPreset({\n  tsconfig: 'tsconfig.test.json',\n});\n\nconst jestConfig: JestConfigWithTsJest = {\n  ...presetConfig,\n  moduleNameMapper: {\n    '^(\\\\.{1,2}/.*)\\\\.js$': '$1',\n  },\n};\n\nexport default jestConfig;\n"
  },
  {
    "path": "packages/redux-devtools-serialize/package.json",
    "content": "{\n  \"name\": \"@redux-devtools/serialize\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Serialize unserializable data and parse it back.\",\n  \"keywords\": [\n    \"redux\",\n    \"devtools\"\n  ],\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-serialize\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)\",\n  \"files\": [\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": \"./lib/index.js\",\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"test\": \"node --experimental-vm-modules node_modules/jest/bin/jest.js\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run type-check && pnpm run lint && pnpm run test\"\n  },\n  \"dependencies\": {\n    \"jsan\": \"^3.1.14\"\n  },\n  \"devDependencies\": {\n    \"@types/jest\": \"^30.0.0\",\n    \"@types/jsan\": \"^3.1.5\",\n    \"immutable\": \"^5.1.5\",\n    \"jest\": \"^30.3.0\",\n    \"rimraf\": \"^6.1.3\",\n    \"ts-jest\": \"^29.4.6\",\n    \"typescript\": \"~5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"immutable\": \"^5.1.5\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-serialize/src/constants/options.ts",
    "content": "// jsan stringify options\n\nexport default {\n  refs: false, // references can't be resolved on the original Immutable structure\n  date: true,\n  function: true,\n  regex: true,\n  undefined: true,\n  error: true,\n  symbol: true,\n  map: true,\n  set: true,\n  nan: true,\n  infinity: true,\n};\n"
  },
  {
    "path": "packages/redux-devtools-serialize/src/helpers/index.ts",
    "content": "export interface SerializedData {\n  data: unknown;\n  __serializedType__: string;\n  __serializedRef__?: number;\n}\n\nexport function mark(data: unknown, type: string): SerializedData;\nexport function mark<K extends string>(\n  data: { [key in K]: () => unknown },\n  type: string,\n  transformMethod?: K | false,\n): SerializedData;\nexport function mark<K extends string>(\n  data: any,\n  type: string,\n  transformMethod?: 'toString' | false,\n): SerializedData;\nexport function mark<K extends string>(\n  data: { [key in K]: () => unknown } | unknown,\n  type: string,\n  transformMethod?: K | false,\n): SerializedData {\n  return {\n    data: transformMethod\n      ? (data as { [key in K]: () => unknown })[transformMethod]()\n      : data,\n    __serializedType__: type,\n  };\n}\n\nexport function extract(data: unknown, type: string): SerializedData {\n  return {\n    data: Object.assign({}, data),\n    __serializedType__: type,\n  };\n}\n\nexport function refer(data: unknown, type: string): SerializedData;\nexport function refer<K extends string>(\n  data: { [key in K]: () => unknown },\n  type: string,\n  transformMethod?: K | false,\n  refs?: (new (data: any) => unknown)[] | null,\n): SerializedData;\nexport function refer<K extends string>(\n  data: any,\n  type: string,\n  transformMethod?: 'toString' | false,\n  refs?: (new (data: any) => unknown)[] | null,\n): SerializedData;\nexport function refer<K extends string>(\n  data: { [key in K]: () => unknown } | unknown,\n  type: string,\n  transformMethod?: K | false,\n  refs?: (new (data: any) => unknown)[] | null,\n): SerializedData {\n  const r = mark(data as { [key in K]: () => unknown }, type, transformMethod);\n  if (!refs) return r;\n  for (let i = 0; i < refs.length; i++) {\n    const ref = refs[i];\n    if (typeof ref === 'function' && data instanceof ref) {\n      r.__serializedRef__ = i;\n      return r;\n    }\n  }\n  return r;\n}\n"
  },
  {
    "path": "packages/redux-devtools-serialize/src/immutable/index.ts",
    "content": "import jsan from 'jsan';\nimport type Immutable from 'immutable';\nimport serialize from './serialize.js';\nimport options from '../constants/options.js';\n\nexport default function (\n  immutable: typeof Immutable,\n  refs?: (new (data: any) => unknown)[] | null,\n  customReplacer?: (\n    key: string,\n    value: unknown,\n    defaultReplacer: (key: string, value: unknown) => unknown,\n  ) => unknown,\n  customReviver?: (\n    key: string,\n    value: unknown,\n    defaultReviver: (key: string, value: unknown) => unknown,\n  ) => unknown,\n) {\n  return {\n    stringify: function (this: void, data: unknown) {\n      return jsan.stringify(\n        data,\n        serialize(immutable, refs, customReplacer, customReviver).replacer,\n        undefined,\n        options,\n      );\n    },\n    parse: function (this: void, data: string) {\n      return jsan.parse(\n        data,\n        serialize(immutable, refs, customReplacer, customReviver).reviver,\n      );\n    },\n    serialize: serialize,\n  };\n}\nexport { default as serialize } from './serialize.js';\n"
  },
  {
    "path": "packages/redux-devtools-serialize/src/immutable/serialize.ts",
    "content": "import type Immutable from 'immutable';\nimport { Record } from 'immutable';\nimport { mark, extract, refer } from '../helpers/index.js';\nimport options from '../constants/options.js';\nimport { SerializedImmutableData } from '../types.js';\n\nexport default function serialize(\n  immutable: typeof Immutable,\n  refs?: (new (data: any) => unknown)[] | null,\n  customReplacer?: (\n    key: string,\n    value: unknown,\n    defaultReplacer: (key: string, value: unknown) => unknown,\n  ) => unknown,\n  customReviver?: (\n    key: string,\n    value: unknown,\n    defaultReviver: (key: string, value: unknown) => unknown,\n  ) => unknown,\n) {\n  function replacer(key: string, value: unknown) {\n    if (value instanceof immutable.Record)\n      return refer(value as Record<any>, 'ImmutableRecord', 'toObject', refs);\n    if (value instanceof immutable.Range)\n      return extract(value, 'ImmutableRange');\n    if (value instanceof immutable.Repeat)\n      return extract(value, 'ImmutableRepeat');\n    if (immutable.OrderedMap.isOrderedMap(value))\n      return mark(value, 'ImmutableOrderedMap', 'toObject');\n    if (immutable.Map.isMap(value))\n      return mark(value, 'ImmutableMap', 'toObject');\n    if (immutable.List.isList(value))\n      return mark(value, 'ImmutableList', 'toArray');\n    if (immutable.OrderedSet.isOrderedSet(value))\n      return mark(value, 'ImmutableOrderedSet', 'toArray');\n    if (immutable.Set.isSet(value))\n      return mark(value, 'ImmutableSet', 'toArray');\n    if (immutable.Seq.isSeq(value))\n      return mark(value, 'ImmutableSeq', 'toArray');\n    if (immutable.Stack.isStack(value))\n      return mark(value, 'ImmutableStack', 'toArray');\n    return value;\n  }\n\n  function reviver(key: string, value: unknown) {\n    if (\n      typeof value === 'object' &&\n      value !== null &&\n      '__serializedType__' in value\n    ) {\n      const immutableValue = value as SerializedImmutableData;\n      switch (immutableValue.__serializedType__) {\n        case 'ImmutableMap':\n          return immutable.Map(immutableValue.data);\n        case 'ImmutableOrderedMap':\n          return immutable.OrderedMap(immutableValue.data);\n        case 'ImmutableList':\n          return immutable.List(immutableValue.data);\n        case 'ImmutableRange':\n          return immutable.Range(\n            immutableValue.data._start!,\n            immutableValue.data._end!,\n            immutableValue.data._step,\n          );\n        case 'ImmutableRepeat':\n          return immutable.Repeat(\n            immutableValue.data._value,\n            immutableValue.data.size,\n          );\n        case 'ImmutableSet':\n          return immutable.Set(immutableValue.data);\n        case 'ImmutableOrderedSet':\n          return immutable.OrderedSet(immutableValue.data);\n        case 'ImmutableSeq':\n          return immutable.Seq(immutableValue.data);\n        case 'ImmutableStack':\n          return immutable.Stack(immutableValue.data);\n        case 'ImmutableRecord':\n          return refs && refs[immutableValue.__serializedRef__!]\n            ? new refs[immutableValue.__serializedRef__!](immutableValue.data)\n            : immutable.Map(immutableValue.data);\n        default:\n          return (immutableValue as { data: unknown }).data;\n      }\n    }\n    return value;\n  }\n\n  return {\n    replacer: customReplacer\n      ? function (key: string, value: unknown) {\n          return customReplacer(key, value, replacer);\n        }\n      : replacer,\n    reviver: customReviver\n      ? function (key: string, value: unknown) {\n          return customReviver(key, value, reviver);\n        }\n      : reviver,\n    options: options,\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-serialize/src/index.ts",
    "content": "export {\n  default as immutable,\n  serialize as immutableSerialize,\n} from './immutable/index.js';\n"
  },
  {
    "path": "packages/redux-devtools-serialize/src/types.ts",
    "content": "interface SerializedImmutableMap {\n  data: Record<string, unknown>;\n  __serializedType__: 'ImmutableMap';\n}\n\ninterface SerializedImmutableOrderedMap {\n  data: Record<string, unknown>;\n  __serializedType__: 'ImmutableOrderedMap';\n}\n\ninterface SerializedImmutableList {\n  data: unknown[];\n  __serializedType__: 'ImmutableList';\n}\n\ninterface SerializedImmutableRangeData {\n  _start: number | undefined;\n  _end: number | undefined;\n  _step: number | undefined;\n}\ninterface SerializedImmutableRange {\n  data: SerializedImmutableRangeData;\n  __serializedType__: 'ImmutableRange';\n}\n\ninterface SerializedImmutableRepeatData {\n  _value: unknown;\n  size: number | undefined;\n}\ninterface SerializedImmutableRepeat {\n  data: SerializedImmutableRepeatData;\n  __serializedType__: 'ImmutableRepeat';\n}\n\ninterface SerializedImmutableSet {\n  data: unknown[];\n  __serializedType__: 'ImmutableSet';\n}\n\ninterface SerializedImmutableOrderedSet {\n  data: unknown[];\n  __serializedType__: 'ImmutableOrderedSet';\n}\n\ninterface SerializedImmutableSeq {\n  data: unknown[];\n  __serializedType__: 'ImmutableSeq';\n}\n\ninterface SerializedImmutableStack {\n  data: unknown[];\n  __serializedType__: 'ImmutableStack';\n}\n\ninterface SerializedImmutableRecord {\n  data: Record<string, unknown>;\n  __serializedType__: 'ImmutableRecord';\n  __serializedRef__?: number;\n}\n\nexport type SerializedImmutableData =\n  | SerializedImmutableMap\n  | SerializedImmutableOrderedMap\n  | SerializedImmutableList\n  | SerializedImmutableRange\n  | SerializedImmutableRepeat\n  | SerializedImmutableSet\n  | SerializedImmutableOrderedSet\n  | SerializedImmutableSeq\n  | SerializedImmutableStack\n  | SerializedImmutableRecord;\n"
  },
  {
    "path": "packages/redux-devtools-serialize/test/__snapshots__/helpers.spec.ts.snap",
    "content": "// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing\n\nexports[`Helpers extract 1`] = `\n{\n  \"__serializedType__\": \"testType\",\n  \"data\": {\n    \"testData\": \"test\",\n  },\n}\n`;\n\nexports[`Helpers mark 1`] = `\n{\n  \"__serializedType__\": \"testType\",\n  \"data\": {\n    \"testData\": \"test\",\n  },\n}\n`;\n\nexports[`Helpers mark 2`] = `\n{\n  \"__serializedType__\": \"testType\",\n  \"data\": \"[object Object]\",\n}\n`;\n\nexports[`Helpers refer 1`] = `\n{\n  \"__serializedType__\": \"testType\",\n  \"data\": {\n    \"testData\": \"test\",\n  },\n}\n`;\n"
  },
  {
    "path": "packages/redux-devtools-serialize/test/__snapshots__/immutable.spec.ts.snap",
    "content": "// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing\n\nexports[`Immutable Nested stringify 1`] = `\"{\"data\":[{\"data\":{\"map\":{\"data\":{\"seq\":{\"data\":[1,2,3,4,5,6,7,8],\"__serializedType__\":\"ImmutableSeq\"},\"stack\":{\"data\":[\"a\",\"b\",\"c\"],\"__serializedType__\":\"ImmutableStack\"}},\"__serializedType__\":\"ImmutableOrderedMap\"},\"repeat\":{\"data\":{\"_value\":\"hi\",\"size\":100},\"__serializedType__\":\"ImmutableRepeat\"}},\"__serializedType__\":\"ImmutableRecord\",\"__serializedRef__\":0},{\"data\":[10,9,8,7,6,5,4,3,2,1],\"__serializedType__\":\"ImmutableOrderedSet\"},{\"data\":{\"_start\":0,\"_end\":7,\"_step\":1,\"size\":7},\"__serializedType__\":\"ImmutableRange\"}],\"__serializedType__\":\"ImmutableSet\"}\"`;\n\nexports[`Immutable Record stringify 1`] = `\"{\"data\":{\"a\":1,\"b\":3},\"__serializedType__\":\"ImmutableRecord\",\"__serializedRef__\":0}\"`;\n\nexports[`Immutable Stringify list 1`] = `\"{\"data\":[1,2,3,4,5,6,7,8,9,10],\"__serializedType__\":\"ImmutableList\"}\"`;\n\nexports[`Immutable Stringify map 1`] = `\"{\"data\":{\"a\":1,\"b\":2,\"c\":3,\"d\":4},\"__serializedType__\":\"ImmutableMap\"}\"`;\n\nexports[`Immutable Stringify orderedMap 1`] = `\"{\"data\":{\"b\":2,\"a\":1,\"c\":3,\"d\":4},\"__serializedType__\":\"ImmutableOrderedMap\"}\"`;\n\nexports[`Immutable Stringify orderedSet 1`] = `\"{\"data\":[10,9,8,7,6,5,4,3,2,1],\"__serializedType__\":\"ImmutableOrderedSet\"}\"`;\n\nexports[`Immutable Stringify range 1`] = `\"{\"data\":{\"_start\":0,\"_end\":7,\"_step\":1,\"size\":7},\"__serializedType__\":\"ImmutableRange\"}\"`;\n\nexports[`Immutable Stringify repeat 1`] = `\"{\"data\":{\"_value\":\"hi\",\"size\":100},\"__serializedType__\":\"ImmutableRepeat\"}\"`;\n\nexports[`Immutable Stringify seq 1`] = `\"{\"data\":[1,2,3,4,5,6,7,8],\"__serializedType__\":\"ImmutableSeq\"}\"`;\n\nexports[`Immutable Stringify set 1`] = `\"{\"data\":[1,2,3,4,5,6,7,8,9,10],\"__serializedType__\":\"ImmutableSet\"}\"`;\n\nexports[`Immutable Stringify stack 1`] = `\"{\"data\":[\"a\",\"b\",\"c\"],\"__serializedType__\":\"ImmutableStack\"}\"`;\n"
  },
  {
    "path": "packages/redux-devtools-serialize/test/helpers.spec.ts",
    "content": "import { mark, extract, refer } from '../src/helpers/index.js';\n\ndescribe('Helpers', function () {\n  it('mark', function () {\n    expect(mark({ testData: 'test' }, 'testType')).toMatchSnapshot();\n    expect(\n      mark({ testData: 'test' }, 'testType', 'toString'),\n    ).toMatchSnapshot();\n  });\n\n  it('extract', function () {\n    expect(extract({ testData: 'test' }, 'testType')).toMatchSnapshot();\n  });\n\n  it('refer', function () {\n    const TestClass = function (data: unknown) {\n      return data;\n    };\n    const testInstance = new (TestClass as any)({\n      testData: 'test',\n    }) as unknown;\n    expect(\n      refer(testInstance, 'testType', false, [TestClass as any]),\n    ).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-serialize/test/immutable.spec.ts",
    "content": "import * as Immutable from 'immutable';\nimport { Map, OrderedMap } from 'immutable';\nimport Serialize from '../src/immutable/index.js';\nimport { SerializedData } from '../src/helpers/index.js';\n\nconst serialize = Serialize(Immutable);\nconst stringify = serialize.stringify;\nconst parse = serialize.parse;\n\nconst data = {\n  map: Immutable.Map({ a: 1, b: 2, c: 3, d: 4 }),\n  orderedMap: Immutable.OrderedMap({ b: 2, a: 1, c: 3, d: 4 }),\n  list: Immutable.List([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),\n  range: Immutable.Range(0, 7),\n  repeat: Immutable.Repeat('hi', 100),\n  set: Immutable.Set([10, 9, 8, 7, 6, 5, 4, 3, 2, 1]),\n  orderedSet: Immutable.OrderedSet([10, 9, 8, 7, 6, 5, 4, 3, 2, 1]),\n  seq: Immutable.Seq([1, 2, 3, 4, 5, 6, 7, 8]),\n  stack: Immutable.Stack.of('a', 'b', 'c'),\n};\n\ndescribe('Immutable', function () {\n  const stringified: { [key: string]: string } = {};\n  describe('Stringify', function () {\n    Object.keys(data).forEach(function (key) {\n      // eslint-disable-next-line jest/valid-title\n      it(key, function () {\n        stringified[key] = stringify(data[key as keyof typeof data]);\n        expect(stringified[key]).toMatchSnapshot();\n      });\n    });\n  });\n\n  describe('Parse', function () {\n    Object.keys(data).forEach(function (key) {\n      // eslint-disable-next-line jest/valid-title\n      it(key, function () {\n        expect(parse(stringified[key])).toEqual(data[key as keyof typeof data]);\n      });\n    });\n  });\n\n  describe('Record', function () {\n    const ABRecord = Immutable.Record({ a: 1, b: 2 });\n    const myRecord = new ABRecord({ b: 3 });\n\n    const serialize = Serialize(Immutable, [ABRecord]);\n    const stringify = serialize.stringify;\n    const parse = serialize.parse;\n    let stringifiedRecord: string;\n\n    it('stringify', function () {\n      stringifiedRecord = stringify(myRecord);\n      expect(stringifiedRecord).toMatchSnapshot();\n    });\n\n    it('parse', function () {\n      expect(parse(stringifiedRecord)).toEqual(myRecord);\n    });\n  });\n\n  describe('Nested', function () {\n    const ABRecord = Immutable.Record({\n      map: Immutable.OrderedMap({ seq: data.seq, stack: data.stack }),\n      repeat: data.repeat,\n    });\n    const nestedData = Immutable.Set([ABRecord(), data.orderedSet, data.range]);\n\n    const serialize = Serialize(Immutable, [ABRecord]);\n    const stringify = serialize.stringify;\n    const parse = serialize.parse;\n    let stringifiedNested: string;\n\n    it('stringify', function () {\n      stringifiedNested = stringify(nestedData);\n      expect(stringifiedNested).toMatchSnapshot();\n    });\n\n    it('parse', function () {\n      expect(parse(stringifiedNested)).toEqual(nestedData);\n    });\n  });\n  describe('With references', function () {\n    it('serializes and deserializes', function () {\n      const sharedValue: unknown[] = [];\n      const record = Immutable.Record({\n        prop: sharedValue,\n      });\n\n      const refs = [record];\n\n      const obj = Immutable.Map({\n        fst: new record(),\n        scnd: new record(),\n      });\n\n      const serialize = Serialize(Immutable, refs);\n      const serialized = serialize.stringify(obj);\n      const parsed = JSON.parse(serialized);\n\n      const fstProp = parsed.data.fst.data.prop;\n      const scndProp = parsed.data.scnd.data.prop;\n\n      expect(fstProp).toEqual(scndProp);\n      expect(Array.isArray(obj.get('fst').get('prop'))).toBe(true);\n    });\n  });\n\n  describe('Custom replacer and reviver functions', function () {\n    const customOneRepresentation = 'one';\n\n    function customReplacer(\n      key: string,\n      value: unknown,\n      defaultReplacer: (key: string, value: unknown) => unknown,\n    ) {\n      if (value === 1) {\n        return { data: customOneRepresentation, __serializedType__: 'number' };\n      }\n      return defaultReplacer(key, value);\n    }\n\n    function customReviver(\n      key: string,\n      value: unknown,\n      defaultReviver: (key: string, value: unknown) => unknown,\n    ) {\n      if (\n        typeof value === 'object' &&\n        (value as SerializedData).__serializedType__ === 'number' &&\n        (value as SerializedData).data === customOneRepresentation\n      ) {\n        return 1;\n      }\n      return defaultReviver(key, value);\n    }\n\n    const serializeCustom = Serialize(\n      Immutable,\n      null,\n      customReplacer,\n      customReviver,\n    );\n\n    Object.keys(data).forEach(function (key) {\n      const stringified = serializeCustom.stringify(\n        data[key as keyof typeof data],\n      );\n      // eslint-disable-next-line jest/valid-title\n      it(key, function () {\n        const deserialized = serializeCustom.parse(stringified);\n        expect(deserialized).toEqual(data[key as keyof typeof data]);\n        if (key === 'map' || key === 'orderedMap') {\n          const deserializedDefault = parse(stringified);\n          // eslint-disable-next-line jest/no-conditional-expect\n          expect(\n            (\n              deserializedDefault as\n                | Map<unknown, unknown>\n                | OrderedMap<unknown, unknown>\n            ).get('a'),\n          ).toEqual(customOneRepresentation);\n        }\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-serialize/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-serialize/tsconfig.test.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"jest\"]\n  },\n  \"include\": [\"src\", \"test\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/CHANGELOG.md",
    "content": "# Change Log\n\n## 7.0.0\n\n### Major Changes\n\n- 12849a4: Convert monitors to ESM\n\n### Patch Changes\n\n- Updated dependencies [d61d31a]\n- Updated dependencies [804e729]\n- Updated dependencies [804d6bd]\n  - @redux-devtools/ui@3.0.0\n  - @redux-devtools/core@5.0.0\n\n## 6.0.0\n\n### Major Changes\n\n- 6163276: Replace styled-components with Emotion\n\n### Patch Changes\n\n- Updated dependencies [6163276]\n  - @redux-devtools/ui@2.0.0\n\n## 5.1.1\n\n### Patch Changes\n\n- Updated dependencies [91f21b2]\n  - @redux-devtools/core@4.1.1\n\n## 5.1.0\n\n### Minor Changes\n\n- 6830118: Add React 19 to peer deps\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - @redux-devtools/ui@1.4.0\n  - @redux-devtools/core@4.1.0\n\n## 5.0.1\n\n### Patch Changes\n\n- Updated dependencies [bbb1a40]\n  - react-base16-styling@0.10.0\n  - @redux-devtools/ui@1.3.2\n\n## 5.0.0\n\n### Major Changes\n\n- 5cfe3e5: Update min required React version to 16.8.4\n\n### Patch Changes\n\n- Updated dependencies [decc035]\n  - @redux-devtools/core@4.0.0\n\n## 4.1.0\n\n### Minor Changes\n\n- 6fc18ed7: Add new Redux version to peer dependencies\n\n### Patch Changes\n\n- 7f5bddbd: Widen peer dependencies\n- Updated dependencies [7f5bddbd]\n  - @redux-devtools/ui@1.3.1\n\n## 4.0.2\n\n### Patch Changes\n\n- 42531c50: Bump versions\n- Updated dependencies [42531c50]\n  - @redux-devtools/core@3.13.3\n\n## 4.0.1\n\n### Patch Changes\n\n- a55ba302: Fix peer dependencies on @redux-devtools/core\n- Updated dependencies [a55ba302]\n  - @redux-devtools/core@3.13.1\n\n## 4.0.0\n\n### Minor Changes\n\n- 8a7eae4: Add React 18 to peerDependencies range\n\n### Patch Changes\n\n- Updated dependencies [8a7eae4]\n  - @redux-devtools/ui@1.3.0\n  - @redux-devtools/core@3.13.0\n\n## 3.1.2\n\n### Patch Changes\n\n- Updated dependencies [4891bf6]\n  - @redux-devtools/core@3.12.0\n\n## 3.0.0\n\n- Adds ESM build (https://github.com/reduxjs/redux-devtools/pull/997) and switches the default export to a named export in order to ensure that the CommonJS output and the ESM output are [interchangeable](https://rollupjs.org/guide/en/#outputexports):\n\n```diff\n- import SliderMonitor from '@redux-devtools/slider-monitor';\n+ import { SliderMonitor } from '@redux-devtools/slider-monitor';\n```\n\n## [2.0.0-8](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/slider-monitor@2.0.0-7...@redux-devtools/slider-monitor@2.0.0-8) (2021-06-11)\n\n**Note:** Version bump only for package @redux-devtools/slider-monitor\n\n## [2.0.0-7](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/slider-monitor@2.0.0-6...@redux-devtools/slider-monitor@2.0.0-7) (2021-03-06)\n\n### Features\n\n- update peer dependencies to allow react@^17 ([#703](https://github.com/reduxjs/redux-devtools/issues/703)) ([2aaa9c1](https://github.com/reduxjs/redux-devtools/commit/2aaa9c10a383e3a7ab20b3ab14639781fd7bb2eb))\n\n## 2.0.0-6 (2021-03-06)\n\n### Features\n\n- **redux-devtools-slider-monitor:** convert example to TypeScript ([#632](https://github.com/reduxjs/redux-devtools/issues/632)) ([ec75d3a](https://github.com/reduxjs/redux-devtools/commit/ec75d3a4b62d0f4b8d52a739a7727142421cc261))\n- **redux-devtools-slider-monitor:** convert to TypeScript ([#631](https://github.com/reduxjs/redux-devtools/issues/631)) ([8991732](https://github.com/reduxjs/redux-devtools/commit/89917320e5ecf33dc3625b05daa1e9fe120a783d))\n\n## [2.0.0-5](https://github.com/reduxjs/redux-devtools/compare/redux-devtools-slider-monitor@2.0.0-4...redux-devtools-slider-monitor@2.0.0-5) (2020-09-07)\n\n**Note:** Version bump only for package redux-devtools-slider-monitor\n\n## 2.0.0-4 (2020-08-14)\n\n**Note:** Version bump only for package redux-devtools-slider-monitor\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 Cale Newman\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/README.md",
    "content": "## Redux DevTools Slider Monitor\n\n[![npm version](https://img.shields.io/npm/v/redux-slider-monitor.svg?style=flat-square)](https://www.npmjs.com/package/redux-slider-monitor)\n\nA custom monitor for use with [Redux DevTools](https://github.com/gaearon/redux-devtools).\n\nIt uses a slider based on [react-slider](https://github.com/mpowaga/react-slider) to slide between different recorded actions. It also features play/pause/step-through, which is inspired by some very cool [Elm](http://elm-lang.org/) [examples](http://elm-lang.org/blog/time-travel-made-easy).\n\n[Try out the demo!](https://calesce.github.io/redux-slider-monitor/?debug_session=123)\n\n<image src=\"https://s3.amazonaws.com/f.cl.ly/items/1I3P222C3N2R1M2y1K3b/Screen%20Recording%202015-12-22%20at%2007.20%20PM.gif?v=1b6267e7\" width='800'>\n\n### Installation\n\n`yarn add @redux-devtools/slider-monitor`\n\n### Recommended Usage\n\nUse with [`DockMonitor`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-dock-monitor)\n\n```javascript\n<DockMonitor\n  toggleVisibilityKey=\"ctrl-h\"\n  changePositionKey=\"ctrl-q\"\n  defaultPosition=\"bottom\"\n  defaultSize={0.15}\n>\n  <SliderMonitor keyboardEnabled />\n</DockMonitor>\n```\n\nDispatch some Redux actions. Use the slider to navigate between the state changes.\n\nClick the play/pause buttons to watch the state changes over time, or step backward or forward in state time with the left/right arrow buttons. Change replay speeds with the `1x` button, and \"Live\" will replay actions with the same time intervals in which they originally were dispatched.\n\n## Keyboard shortcuts\n\nPass the `keyboardEnabled` prop to use these shortcuts\n\n`ctrl+j`: play/pause\n\n`ctrl+[`: step backward\n\n`ctrl+]`: step forward\n\n### Running Examples\n\nYou can do this:\n\n```\ngit clone https://github.com/reduxjs/redux-devtools.git\ncd packages/redux-devtools-slider-monitor/examples/todomvc\nyarn install\nnpm start\nopen http://localhost:3000\n```\n\n### License\n\nMIT\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/eslint.config.mjs",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTsReact from '../../eslint.ts.react.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTsReact(import.meta.dirname),\n  {\n    ignores: ['examples', 'lib'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/CHANGELOG.md",
    "content": "# slider-todomvc\n\n## 0.1.16\n\n### Patch Changes\n\n- Updated dependencies [12849a4]\n- Updated dependencies [804d6bd]\n  - @redux-devtools/dock-monitor@5.0.0\n  - @redux-devtools/log-monitor@6.0.0\n  - @redux-devtools/slider-monitor@7.0.0\n  - @redux-devtools/core@5.0.0\n\n## 0.1.15\n\n### Patch Changes\n\n- Updated dependencies [6163276]\n  - @redux-devtools/slider-monitor@6.0.0\n\n## 0.1.14\n\n### Patch Changes\n\n- Updated dependencies [91f21b2]\n  - @redux-devtools/core@4.1.1\n  - @redux-devtools/dock-monitor@4.1.1\n  - @redux-devtools/log-monitor@5.1.1\n  - @redux-devtools/slider-monitor@5.1.1\n\n## 0.1.13\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - @redux-devtools/dock-monitor@5.0.0\n  - @redux-devtools/log-monitor@6.0.0\n  - @redux-devtools/slider-monitor@6.0.0\n  - @redux-devtools/core@4.1.0\n\n## 0.1.12\n\n### Patch Changes\n\n- Updated dependencies [5cfe3e5]\n- Updated dependencies [decc035]\n  - @redux-devtools/dock-monitor@4.0.0\n  - @redux-devtools/log-monitor@5.0.0\n  - @redux-devtools/slider-monitor@5.0.0\n  - @redux-devtools/core@4.0.0\n\n## 0.1.11\n\n### Patch Changes\n\n- Updated dependencies [8a7eae4]\n  - @redux-devtools/dock-monitor@3.0.0\n  - @redux-devtools/log-monitor@4.0.0\n  - @redux-devtools/slider-monitor@4.0.0\n  - @redux-devtools/core@3.13.0\n\n## 0.1.10\n\n### Patch Changes\n\n- Updated dependencies [4891bf6]\n  - @redux-devtools/core@3.12.0\n  - @redux-devtools/dock-monitor@2.1.1\n  - @redux-devtools/log-monitor@3.1.1\n  - @redux-devtools/slider-monitor@3.1.2\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/README.md",
    "content": "# Redux DevTools TodoMVC example\n\n## Getting Started\n\n1. Install dependencies: `npm i`\n2. Start the development server: `npm start`\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/eslint.config.mjs",
    "content": "import eslintJs from '../../../../eslint.js.config.base.mjs';\nimport eslintTs from '../../../../eslint.ts.react.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTs(import.meta.dirname),\n  ...eslintTs(\n    import.meta.dirname,\n    ['webpack.config.ts'],\n    ['./tsconfig.webpack.json'],\n  ),\n  {\n    ignores: ['dist'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/index.html",
    "content": "<html>\n  <head>\n    <title>Redux TodoMVC</title>\n  </head>\n  <body>\n    <div class=\"todoapp\" id=\"root\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/package.json",
    "content": "{\n  \"private\": true,\n  \"name\": \"slider-todomvc\",\n  \"version\": \"0.1.16\",\n  \"description\": \"TodoMVC example for redux\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"start\": \"cross-env TS_NODE_PROJECT=\\\"tsconfig.webpack.json\\\" webpack serve --open\",\n    \"build\": \"cross-env TS_NODE_PROJECT=\\\"tsconfig.webpack.json\\\" webpack\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\"\n  },\n  \"dependencies\": {\n    \"@emotion/react\": \"^11.14.0\",\n    \"@emotion/styled\": \"^11.14.1\",\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@redux-devtools/dock-monitor\": \"workspace:^\",\n    \"@redux-devtools/log-monitor\": \"workspace:^\",\n    \"@redux-devtools/slider-monitor\": \"workspace:^\",\n    \"classnames\": \"^2.5.1\",\n    \"react\": \"^19.2.4\",\n    \"react-dom\": \"^19.2.4\",\n    \"react-is\": \"^19.2.4\",\n    \"react-redux\": \"^9.2.0\",\n    \"redux\": \"^5.0.1\",\n    \"todomvc-app-css\": \"^2.4.3\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.29.0\",\n    \"@babel/preset-env\": \"^7.29.0\",\n    \"@babel/preset-react\": \"^7.28.5\",\n    \"@babel/preset-typescript\": \"^7.28.5\",\n    \"@types/node\": \"^24.12.0\",\n    \"@types/react\": \"^19.2.14\",\n    \"@types/react-dom\": \"^19.2.3\",\n    \"@types/webpack-env\": \"^1.18.8\",\n    \"babel-loader\": \"^10.1.1\",\n    \"cross-env\": \"^10.1.0\",\n    \"css-loader\": \"^7.1.4\",\n    \"fork-ts-checker-webpack-plugin\": \"^9.1.0\",\n    \"html-webpack-plugin\": \"^5.6.6\",\n    \"style-loader\": \"^4.0.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"~5.9.3\",\n    \"webpack\": \"^5.105.4\",\n    \"webpack-cli\": \"^7.0.0\",\n    \"webpack-dev-server\": \"^5.2.3\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/src/actions/TodoActions.ts",
    "content": "import * as types from '../constants/ActionTypes';\n\ninterface AddTodoAction {\n  type: typeof types.ADD_TODO;\n  text: string;\n}\nexport function addTodo(text: string): AddTodoAction {\n  return {\n    type: types.ADD_TODO,\n    text,\n  };\n}\n\ninterface DeleteTodoAction {\n  type: typeof types.DELETE_TODO;\n  id: number;\n}\nexport function deleteTodo(id: number): DeleteTodoAction {\n  return {\n    type: types.DELETE_TODO,\n    id,\n  };\n}\n\ninterface EditTodoAction {\n  type: typeof types.EDIT_TODO;\n  id: number;\n  text: string;\n}\nexport function editTodo(id: number, text: string): EditTodoAction {\n  return {\n    type: types.EDIT_TODO,\n    id,\n    text,\n  };\n}\n\ninterface MarkTodoAction {\n  type: typeof types.MARK_TODO;\n  id: number;\n}\nexport function markTodo(id: number): MarkTodoAction {\n  return {\n    type: types.MARK_TODO,\n    id,\n  };\n}\n\ninterface MarkAllAction {\n  type: typeof types.MARK_ALL;\n}\nexport function markAll(): MarkAllAction {\n  return {\n    type: types.MARK_ALL,\n  };\n}\n\ninterface ClearMarkedAction {\n  type: typeof types.CLEAR_MARKED;\n}\nexport function clearMarked(): ClearMarkedAction {\n  return {\n    type: types.CLEAR_MARKED,\n  };\n}\n\nexport type TodoAction =\n  | AddTodoAction\n  | DeleteTodoAction\n  | EditTodoAction\n  | MarkTodoAction\n  | MarkAllAction\n  | ClearMarkedAction;\n\nexport interface TodoActions {\n  addTodo(this: void, text: string): AddTodoAction;\n  deleteTodo(this: void, id: number): DeleteTodoAction;\n  editTodo(this: void, id: number, text: string): EditTodoAction;\n  markTodo(this: void, id: number): MarkTodoAction;\n  markAll(this: void): MarkAllAction;\n  clearMarked(this: void): ClearMarkedAction;\n}\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/src/components/Footer.tsx",
    "content": "import React, { Component, MouseEventHandler } from 'react';\nimport classnames from 'classnames';\nimport {\n  SHOW_ALL,\n  SHOW_MARKED,\n  SHOW_UNMARKED,\n  TodoFilter,\n} from '../constants/TodoFilters';\n\nconst FILTER_TITLES = {\n  [SHOW_ALL]: 'All',\n  [SHOW_UNMARKED]: 'Active',\n  [SHOW_MARKED]: 'Completed',\n};\n\ninterface Props {\n  markedCount: number;\n  unmarkedCount: number;\n  filter: TodoFilter;\n  onClearMarked: MouseEventHandler<HTMLButtonElement>;\n  onShow: (filter: TodoFilter) => void;\n}\n\nexport default class Footer extends Component<Props> {\n  render() {\n    return (\n      <footer className=\"footer\">\n        {this.renderTodoCount()}\n        <ul className=\"filters\">\n          {([SHOW_ALL, SHOW_UNMARKED, SHOW_MARKED] as const).map((filter) => (\n            <li key={filter}>{this.renderFilterLink(filter)}</li>\n          ))}\n        </ul>\n        {this.renderClearButton()}\n      </footer>\n    );\n  }\n\n  renderTodoCount() {\n    const { unmarkedCount } = this.props;\n    const itemWord = unmarkedCount === 1 ? 'item' : 'items';\n\n    return (\n      <span className=\"todo-count\">\n        <strong>{unmarkedCount || 'No'}</strong> {itemWord} left\n      </span>\n    );\n  }\n\n  renderFilterLink(filter: TodoFilter) {\n    const title = FILTER_TITLES[filter];\n    const { filter: selectedFilter, onShow } = this.props;\n\n    return (\n      <a\n        className={classnames({ selected: filter === selectedFilter })}\n        style={{ cursor: 'hand' }}\n        onClick={() => onShow(filter)}\n      >\n        {title}\n      </a>\n    );\n  }\n\n  renderClearButton() {\n    const { markedCount, onClearMarked } = this.props;\n    if (markedCount > 0) {\n      return (\n        <button className=\"clear-completed\" onClick={onClearMarked}>\n          Clear completed\n        </button>\n      );\n    }\n    return null;\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/src/components/Header.tsx",
    "content": "import React, { Component } from 'react';\nimport TodoTextInput from './TodoTextInput';\n\ninterface Props {\n  addTodo: (text: string) => void;\n}\n\nexport default class Header extends Component<Props> {\n  handleSave = (text: string) => {\n    if (text.length !== 0) {\n      this.props.addTodo(text);\n    }\n  };\n\n  render() {\n    return (\n      <header className=\"header\">\n        <h1>todos</h1>\n        <TodoTextInput\n          newTodo\n          onSave={this.handleSave}\n          placeholder=\"What needs to be done?\"\n        />\n      </header>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/src/components/MainSection.tsx",
    "content": "import React, { Component, MouseEventHandler } from 'react';\nimport TodoItem from './TodoItem';\nimport Footer from './Footer';\nimport {\n  SHOW_ALL,\n  SHOW_MARKED,\n  SHOW_UNMARKED,\n  TodoFilter,\n} from '../constants/TodoFilters';\nimport { Todo } from '../reducers/todos';\nimport { TodoActions } from '../actions/TodoActions';\n\nconst TODO_FILTERS = {\n  [SHOW_ALL]: () => true,\n  [SHOW_UNMARKED]: (todo: Todo) => !todo.marked,\n  [SHOW_MARKED]: (todo: Todo) => todo.marked,\n};\n\ninterface State {\n  filter: TodoFilter;\n}\n\ninterface Props {\n  todos: Todo[];\n  actions: TodoActions;\n}\n\nexport default class MainSection extends Component<Props, State> {\n  state: State = { filter: SHOW_ALL };\n\n  handleClearMarked: MouseEventHandler<HTMLButtonElement> = () => {\n    const atLeastOneMarked = this.props.todos.some((todo) => todo.marked);\n    if (atLeastOneMarked) {\n      this.props.actions.clearMarked();\n    }\n  };\n\n  handleShow = (filter: TodoFilter) => {\n    this.setState({ filter });\n  };\n\n  render() {\n    const { todos, actions } = this.props;\n    const { filter } = this.state;\n\n    const filteredTodos = todos.filter(TODO_FILTERS[filter]);\n    const markedCount = todos.reduce(\n      (count, todo) => (todo.marked ? count + 1 : count),\n      0,\n    );\n\n    return (\n      <section className=\"main\">\n        {this.renderToggleAll(markedCount)}\n        <ul className=\"todo-list\">\n          {filteredTodos.map((todo) => (\n            <TodoItem key={todo.id} todo={todo} {...actions} />\n          ))}\n        </ul>\n        {this.renderFooter(markedCount)}\n      </section>\n    );\n  }\n\n  renderToggleAll(markedCount: number) {\n    const { todos, actions } = this.props;\n    if (todos.length > 0) {\n      return (\n        <input\n          className=\"toggle-all\"\n          type=\"checkbox\"\n          checked={markedCount === todos.length}\n          onChange={actions.markAll}\n        />\n      );\n    }\n    return null;\n  }\n\n  renderFooter(markedCount: number) {\n    const { todos } = this.props;\n    const { filter } = this.state;\n    const unmarkedCount = todos.length - markedCount;\n\n    if (todos.length) {\n      return (\n        <Footer\n          markedCount={markedCount}\n          unmarkedCount={unmarkedCount}\n          filter={filter}\n          onClearMarked={this.handleClearMarked}\n          onShow={this.handleShow}\n        />\n      );\n    }\n    return null;\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/src/components/TodoItem.tsx",
    "content": "import React, { Component } from 'react';\nimport classnames from 'classnames';\nimport TodoTextInput from './TodoTextInput';\nimport { Todo } from '../reducers/todos';\n\ninterface State {\n  editing: boolean;\n}\n\ninterface Props {\n  todo: Todo;\n  addTodo: (text: string) => void;\n  deleteTodo: (id: number) => void;\n  editTodo: (id: number, text: string) => void;\n  markTodo: (id: number) => void;\n  markAll: () => void;\n  clearMarked: () => void;\n}\n\nexport default class TodoItem extends Component<Props, State> {\n  state: State = {\n    editing: false,\n  };\n\n  handleDoubleClick = () => {\n    this.setState({ editing: true });\n  };\n\n  handleSave = (id: number, text: string) => {\n    if (text.length === 0) {\n      this.props.deleteTodo(id);\n    } else {\n      this.props.editTodo(id, text);\n    }\n    this.setState({ editing: false });\n  };\n\n  render() {\n    const { todo, markTodo, deleteTodo } = this.props;\n\n    let element;\n    if (this.state.editing) {\n      element = (\n        <TodoTextInput\n          text={todo.text}\n          editing={this.state.editing}\n          onSave={(text) => this.handleSave(todo.id, text)}\n        />\n      );\n    } else {\n      element = (\n        <div className=\"view\">\n          <input\n            className=\"toggle\"\n            type=\"checkbox\"\n            checked={todo.marked}\n            onChange={() => markTodo(todo.id)}\n          />\n          <label htmlFor=\"text\" onDoubleClick={this.handleDoubleClick}>\n            {todo.text}\n          </label>\n          <button className=\"destroy\" onClick={() => deleteTodo(todo.id)} />\n        </div>\n      );\n    }\n\n    return (\n      <li\n        className={classnames({\n          completed: todo.marked,\n          editing: this.state.editing,\n        })}\n      >\n        {element}\n      </li>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/src/components/TodoTextInput.tsx",
    "content": "import React, {\n  ChangeEventHandler,\n  Component,\n  FocusEventHandler,\n  KeyboardEventHandler,\n} from 'react';\nimport classnames from 'classnames';\n\ninterface State {\n  text: string;\n}\n\ninterface Props {\n  onSave: (text: string) => void;\n  text?: string;\n  placeholder?: string;\n  editing?: boolean;\n  newTodo?: boolean;\n}\n\nexport default class TodoTextInput extends Component<Props, State> {\n  static defaultProps = {\n    text: '',\n    placeholder: '',\n    editing: false,\n    newTodo: false,\n  };\n\n  state = {\n    text: this.props.text || '',\n  };\n\n  handleSubmit: KeyboardEventHandler<HTMLInputElement> = (e) => {\n    const text = e.currentTarget.value.trim();\n    if (e.which === 13) {\n      this.props.onSave(text);\n      if (this.props.newTodo) {\n        this.setState({ text: '' });\n      }\n    }\n  };\n\n  handleChange: ChangeEventHandler<HTMLInputElement> = (e) => {\n    this.setState({ text: e.target.value });\n  };\n\n  handleBlur: FocusEventHandler<HTMLInputElement> = (e) => {\n    if (!this.props.newTodo) {\n      this.props.onSave(e.target.value);\n    }\n  };\n\n  render() {\n    return (\n      <input\n        className={classnames({\n          edit: this.props.editing,\n          'new-todo': this.props.newTodo,\n        })}\n        type=\"text\"\n        placeholder={this.props.placeholder}\n        autoFocus={true}\n        value={this.state.text}\n        onBlur={this.handleBlur}\n        onChange={this.handleChange}\n        onKeyDown={this.handleSubmit}\n      />\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/src/constants/ActionTypes.ts",
    "content": "export const ADD_TODO = 'ADD_TODO';\nexport const DELETE_TODO = 'DELETE_TODO';\nexport const EDIT_TODO = 'EDIT_TODO';\nexport const MARK_TODO = 'MARK_TODO';\nexport const MARK_ALL = 'MARK_ALL';\nexport const CLEAR_MARKED = 'CLEAR_MARKED';\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/src/constants/TodoFilters.ts",
    "content": "export const SHOW_ALL = 'show_all';\nexport const SHOW_MARKED = 'show_marked';\nexport const SHOW_UNMARKED = 'show_unmarked';\n\nexport type TodoFilter =\n  | typeof SHOW_ALL\n  | typeof SHOW_MARKED\n  | typeof SHOW_UNMARKED;\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/src/containers/DevTools.tsx",
    "content": "import React from 'react';\nimport { createDevTools } from '@redux-devtools/core';\nimport { DockMonitor } from '@redux-devtools/dock-monitor';\nimport { SliderMonitor } from '@redux-devtools/slider-monitor';\n\nexport default createDevTools(\n  <DockMonitor\n    toggleVisibilityKey=\"ctrl-h\"\n    changePositionKey=\"ctrl-q\"\n    defaultPosition=\"bottom\"\n    defaultSize={0.15}\n  >\n    <SliderMonitor keyboardEnabled />\n  </DockMonitor>,\n);\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/src/containers/Root.dev.tsx",
    "content": "import React from 'react';\nimport { Provider } from 'react-redux';\nimport { Store } from 'redux';\nimport TodoApp from './TodoApp';\nimport DevTools from './DevTools';\nimport { TodoState } from '../reducers';\nimport { TodoAction } from '../actions/TodoActions';\n\ninterface Props {\n  store: Store<TodoState, TodoAction>;\n}\n\nconst Root: React.FunctionComponent<Props> = ({ store }) => (\n  <Provider store={store}>\n    <div>\n      <TodoApp />\n      <DevTools />\n    </div>\n  </Provider>\n);\n\nexport default Root;\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/src/containers/Root.prod.tsx",
    "content": "import React, { FunctionComponent } from 'react';\nimport { Provider } from 'react-redux';\nimport TodoApp from './TodoApp';\nimport { Store } from 'redux';\nimport { TodoState } from '../reducers';\nimport { TodoAction } from '../actions/TodoActions';\n\ninterface Props {\n  store: Store<TodoState, TodoAction>;\n}\n\nconst Root: FunctionComponent<Props> = ({ store }) => (\n  <Provider store={store}>\n    <div>\n      <TodoApp />\n    </div>\n  </Provider>\n);\n\nexport default Root;\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/src/containers/Root.ts",
    "content": "import { Store } from 'redux';\nimport { ComponentType } from 'react';\nimport { TodoState } from '../reducers';\nimport { TodoAction } from '../actions/TodoActions';\n\ninterface Props {\n  store: Store<TodoState, TodoAction>;\n}\nconst Root: ComponentType<Props> =\n  process.env.NODE_ENV === 'production'\n    ? // eslint-disable-next-line @typescript-eslint/no-require-imports\n      require('./Root.prod').default\n    : // eslint-disable-next-line @typescript-eslint/no-require-imports\n      require('./Root.dev').default;\nexport default Root;\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/src/containers/TodoApp.tsx",
    "content": "import React, { FunctionComponent } from 'react';\nimport { connect } from 'react-redux';\nimport { bindActionCreators, Dispatch } from 'redux';\nimport Header from '../components/Header';\nimport MainSection from '../components/MainSection';\nimport * as TodoActions from '../actions/TodoActions';\nimport {\n  TodoAction,\n  TodoActions as TodoActionsType,\n} from '../actions/TodoActions';\nimport { TodoState } from '../reducers';\nimport { Todo } from '../reducers/todos';\n\ninterface Props {\n  todos: Todo[];\n  actions: TodoActionsType;\n}\n\nconst TodoApp: FunctionComponent<Props> = ({ todos, actions }) => (\n  <div>\n    <Header addTodo={actions.addTodo} />\n    <MainSection todos={todos} actions={actions} />\n  </div>\n);\n\nfunction mapState(state: TodoState) {\n  return {\n    todos: state.todos,\n  };\n}\n\nfunction mapDispatch(dispatch: Dispatch<TodoAction>) {\n  return {\n    actions: bindActionCreators(TodoActions, dispatch),\n  };\n}\n\nexport default connect(mapState, mapDispatch)(TodoApp);\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/src/index.tsx",
    "content": "import 'todomvc-app-css/index.css';\nimport React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport configureStore from './store/configureStore';\nimport Root from './containers/Root';\n\nconst store = configureStore();\n\nconst rootEl = document.getElementById('root');\nconst root = ReactDOM.createRoot(rootEl!);\nroot.render(<Root store={store} />);\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/src/reducers/index.ts",
    "content": "import { combineReducers, Reducer } from 'redux';\nimport todos, { Todo } from './todos';\nimport { TodoAction } from '../actions/TodoActions';\n\nexport interface TodoState {\n  todos: Todo[];\n}\n\nconst rootReducer: Reducer<\n  TodoState,\n  TodoAction,\n  Partial<TodoState>\n> = combineReducers({\n  todos,\n}) as any;\n\nexport default rootReducer;\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/src/reducers/todos.ts",
    "content": "import {\n  ADD_TODO,\n  DELETE_TODO,\n  EDIT_TODO,\n  MARK_TODO,\n  MARK_ALL,\n  CLEAR_MARKED,\n} from '../constants/ActionTypes';\nimport { TodoAction } from '../actions/TodoActions';\n\nexport interface Todo {\n  text: string;\n  marked: boolean;\n  id: number;\n}\n\nconst initialState: Todo[] = [\n  {\n    text: 'Use Redux',\n    marked: false,\n    id: 0,\n  },\n];\n\nexport default function todos(state = initialState, action: TodoAction) {\n  switch (action.type) {\n    case ADD_TODO:\n      return [\n        {\n          id: state.length === 0 ? 0 : state[0].id + 1,\n          marked: false,\n          text: action.text,\n        },\n        ...state,\n      ];\n\n    case DELETE_TODO:\n      return state.filter((todo) => todo.id !== action.id);\n\n    case EDIT_TODO:\n      return state.map((todo) =>\n        todo.id === action.id ? { ...todo, text: action.text } : todo,\n      );\n\n    case MARK_TODO:\n      return state.map((todo) =>\n        todo.id === action.id ? { ...todo, marked: !todo.marked } : todo,\n      );\n\n    case MARK_ALL: {\n      const areAllMarked = state.every((todo) => todo.marked);\n      return state.map((todo) => ({\n        ...todo,\n        marked: !areAllMarked,\n      }));\n    }\n    case CLEAR_MARKED:\n      return state.filter((todo) => !todo.marked);\n\n    default:\n      return state;\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/src/store/configureStore.dev.ts",
    "content": "import { createStore, compose, StoreEnhancer } from 'redux';\nimport { persistState } from '@redux-devtools/core';\nimport rootReducer, { TodoState } from '../reducers';\nimport DevTools from '../containers/DevTools';\n\nfunction getDebugSessionKey() {\n  const matches = /[?&]debug_session=([^&#]+)\\b/.exec(window.location.href);\n  return matches && matches.length > 0 ? matches[1] : null;\n}\n\nconst enhancer: StoreEnhancer = compose(\n  DevTools.instrument(),\n  persistState(getDebugSessionKey()),\n);\n\nexport default function configureStore(initialState?: Partial<TodoState>) {\n  return createStore(rootReducer, initialState, enhancer);\n}\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/src/store/configureStore.prod.ts",
    "content": "import { createStore } from 'redux';\nimport rootReducer, { TodoState } from '../reducers';\n\nexport default function configureStore(initialState?: Partial<TodoState>) {\n  return createStore(rootReducer, initialState);\n}\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/src/store/configureStore.ts",
    "content": "import { Store } from 'redux';\nimport { TodoState } from '../reducers';\nimport { TodoAction } from '../actions/TodoActions';\n\nconst configureStore: (\n  initialState?: Partial<TodoState>,\n) => Store<TodoState, TodoAction> =\n  process.env.NODE_ENV === 'production'\n    ? // eslint-disable-next-line @typescript-eslint/no-require-imports\n      require('./configureStore.prod').default\n    : // eslint-disable-next-line @typescript-eslint/no-require-imports\n      require('./configureStore.dev').default;\nexport default configureStore;\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../../tsconfig.react.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"webpack-env\"]\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/tsconfig.webpack.json",
    "content": "{\n  \"extends\": \"../../../../tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"node\", \"webpack-dev-server\"]\n  },\n  \"include\": [\"webpack.config.ts\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/examples/todomvc/webpack.config.ts",
    "content": "import * as path from 'path';\nimport * as webpack from 'webpack';\nimport HtmlWebpackPlugin from 'html-webpack-plugin';\nimport ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';\n\nconst config: webpack.Configuration = {\n  mode: 'development',\n  entry: './src/index.tsx',\n  devtool: 'eval-source-map',\n  devServer: {\n    static: './dist',\n  },\n  plugins: [\n    new HtmlWebpackPlugin({ template: './index.html' }),\n    new ForkTsCheckerWebpackPlugin(),\n  ],\n  output: {\n    filename: 'bundle.js',\n    path: path.join(__dirname, 'dist'),\n    clean: true,\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.(js|ts)x?$/,\n        exclude: /node_modules/,\n        use: {\n          loader: 'babel-loader',\n          options: {\n            presets: [\n              ['@babel/preset-env', { targets: 'defaults' }],\n              '@babel/preset-react',\n              '@babel/preset-typescript',\n            ],\n          },\n        },\n      },\n      {\n        test: /\\.css$/i,\n        use: ['style-loader', 'css-loader'],\n      },\n    ],\n  },\n  resolve: {\n    extensions: ['.js', '.jsx', '.ts', '.tsx'],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/package.json",
    "content": "{\n  \"name\": \"@redux-devtools/slider-monitor\",\n  \"version\": \"7.0.0\",\n  \"description\": \"A custom monitor for replaying Redux actions that works similarly to a video player\",\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-slider-monitor\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Cale Newman <newman.cale@gmail.com> (http://github.com/calesce)\",\n  \"files\": [\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": \"./lib/index.js\",\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run type-check && pnpm run lint\"\n  },\n  \"dependencies\": {\n    \"@redux-devtools/ui\": \"workspace:^\",\n    \"react-base16-styling\": \"workspace:^\"\n  },\n  \"devDependencies\": {\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@types/node\": \"^24.12.0\",\n    \"@types/react\": \"^19.2.14\",\n    \"react\": \"^19.2.4\",\n    \"redux\": \"^5.0.1\",\n    \"rimraf\": \"^6.1.3\",\n    \"typescript\": \"~5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"@emotion/react\": \"^11.14.0\",\n    \"@emotion/styled\": \"^11.14.1\",\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@types/react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react\": \"^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"redux\": \"^3.4.0 || ^4.0.0 || ^5.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/src/SliderButton.tsx",
    "content": "import React, { Component, PureComponent } from 'react';\nimport type { Base16Theme } from 'react-base16-styling';\nimport { Button } from '@redux-devtools/ui';\n\ninterface Props {\n  theme: Base16Theme;\n  type: string;\n  onClick: () => void;\n  disabled?: boolean;\n}\n\nexport default class SliderButton extends (PureComponent || Component)<Props> {\n  iconStyle() {\n    return {\n      cursor: 'hand',\n      fill: this.props.theme.base06,\n      width: '1.8rem',\n      height: '1.8rem',\n    };\n  }\n\n  renderPlayButton() {\n    return (\n      <Button\n        onClick={this.props.onClick}\n        title=\"Play\"\n        size=\"small\"\n        disabled={this.props.disabled}\n        theme={this.props.theme}\n      >\n        <svg\n          viewBox=\"0 0 24 24\"\n          preserveAspectRatio=\"xMidYMid meet\"\n          style={this.iconStyle()}\n        >\n          <g>\n            <path d=\"M8 5v14l11-7z\" />\n          </g>\n        </svg>\n      </Button>\n    );\n  }\n\n  renderPauseButton = () => (\n    <Button\n      onClick={this.props.onClick}\n      title=\"Pause\"\n      size=\"small\"\n      disabled={this.props.disabled}\n      theme={this.props.theme}\n    >\n      <svg\n        viewBox=\"0 0 24 24\"\n        preserveAspectRatio=\"xMidYMid meet\"\n        style={this.iconStyle()}\n      >\n        <g>\n          <path d=\"M6 19h4V5H6v14zm8-14v14h4V5h-4z\" />\n        </g>\n      </svg>\n    </Button>\n  );\n\n  renderStepButton = (direction: 'left' | 'right') => {\n    const isLeft = direction === 'left';\n    const d = isLeft\n      ? 'M15.41 16.09l-4.58-4.59 4.58-4.59-1.41-1.41-6 6 6 6z'\n      : 'M8.59 16.34l4.58-4.59-4.58-4.59 1.41-1.41 6 6-6 6z';\n\n    return (\n      <Button\n        size=\"small\"\n        title={isLeft ? 'Go back' : 'Go forward'}\n        onClick={this.props.onClick}\n        disabled={this.props.disabled}\n        theme={this.props.theme}\n      >\n        <svg\n          viewBox=\"0 0 24 24\"\n          preserveAspectRatio=\"xMidYMid meet\"\n          style={this.iconStyle()}\n        >\n          <g>\n            <path d={d} />\n          </g>\n        </svg>\n      </Button>\n    );\n  };\n\n  render() {\n    switch (this.props.type) {\n      case 'play':\n        return this.renderPlayButton();\n      case 'pause':\n        return this.renderPauseButton();\n      case 'stepLeft':\n        return this.renderStepButton('left');\n      case 'stepRight':\n        return this.renderStepButton('right');\n      default:\n        return null;\n    }\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/src/SliderMonitor.tsx",
    "content": "import React, { Component, PureComponent } from 'react';\nimport { Action, Dispatch } from 'redux';\nimport { base16Themes } from 'react-base16-styling';\nimport type { Base16Theme } from 'react-base16-styling';\nimport {\n  ActionCreators,\n  LiftedAction,\n  LiftedState,\n} from '@redux-devtools/core';\nimport {\n  Button,\n  Divider,\n  SegmentedControl,\n  Slider,\n  Toolbar,\n} from '@redux-devtools/ui';\n\nimport reducer from './reducers.js';\nimport SliderButton from './SliderButton.js';\n\nconst { reset, jumpToAction } = ActionCreators;\n\ninterface ExternalProps<S, A extends Action<string>> {\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  dispatch: Dispatch<LiftedAction<S, A, {}>>;\n  preserveScrollTop: boolean;\n  select: (state: S) => unknown;\n  theme: keyof typeof base16Themes | Base16Theme;\n  keyboardEnabled: boolean;\n  hideResetButton?: boolean;\n}\n\ninterface DefaultProps {\n  select: (state: unknown) => unknown;\n  theme: keyof typeof base16Themes;\n  preserveScrollTop: boolean;\n  keyboardEnabled: boolean;\n}\n\ninterface SliderMonitorProps<S, A extends Action<string>> // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  extends LiftedState<S, A, {}> {\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  dispatch: Dispatch<LiftedAction<S, A, {}>>;\n  preserveScrollTop: boolean;\n  select: (state: S) => unknown;\n  theme: keyof typeof base16Themes | Base16Theme;\n  keyboardEnabled: boolean;\n  hideResetButton?: boolean;\n}\n\ninterface State {\n  timer: number | undefined;\n  replaySpeed: string;\n}\n\nclass SliderMonitor<S, A extends Action<string>> extends (PureComponent ||\n  Component)<SliderMonitorProps<S, A>, State> {\n  static update = reducer;\n\n  static defaultProps = {\n    select: (state: unknown) => state,\n    theme: 'nicinabox',\n    preserveScrollTop: true,\n    keyboardEnabled: true,\n  };\n\n  state: State = {\n    timer: undefined,\n    replaySpeed: '1x',\n  };\n\n  componentDidMount() {\n    if (typeof window !== 'undefined') {\n      window.addEventListener('keydown', this.handleKeyPress);\n    }\n  }\n\n  componentWillUnmount() {\n    if (typeof window !== 'undefined') {\n      window.removeEventListener('keydown', this.handleKeyPress);\n    }\n  }\n\n  setUpTheme = (): Base16Theme => {\n    let theme;\n    if (typeof this.props.theme === 'string') {\n      if (typeof base16Themes[this.props.theme] !== 'undefined') {\n        theme = base16Themes[this.props.theme];\n      } else {\n        theme = base16Themes.nicinabox;\n      }\n    } else {\n      theme = this.props.theme;\n    }\n\n    return theme;\n  };\n\n  handleReset = () => {\n    this.pauseReplay();\n    this.props.dispatch(reset());\n  };\n\n  handleKeyPress = (event: KeyboardEvent) => {\n    if (!this.props.keyboardEnabled) {\n      return null;\n    }\n    if (event.ctrlKey && event.keyCode === 74) {\n      // ctrl+j\n      event.preventDefault();\n\n      if (this.state.timer) {\n        return this.pauseReplay();\n      }\n\n      if (this.state.replaySpeed === 'Live') {\n        this.startRealtimeReplay();\n      } else {\n        this.startReplay();\n      }\n    } else if (event.ctrlKey && event.keyCode === 219) {\n      // ctrl+[\n      event.preventDefault();\n      this.stepLeft();\n    } else if (event.ctrlKey && event.keyCode === 221) {\n      // ctrl+]\n      event.preventDefault();\n      this.stepRight();\n    }\n    return null;\n  };\n\n  handleSliderChange = (value: number) => {\n    if (this.state.timer) {\n      this.pauseReplay();\n    }\n\n    this.props.dispatch(jumpToAction(this.props.stagedActionIds[value]));\n  };\n\n  startReplay = () => {\n    const { computedStates, currentStateIndex, dispatch, stagedActionIds } =\n      this.props;\n\n    if (computedStates.length < 2) {\n      return;\n    }\n    const speed = this.state.replaySpeed === '1x' ? 500 : 200;\n\n    let stateIndex;\n    if (currentStateIndex === computedStates.length - 1) {\n      dispatch(jumpToAction(stagedActionIds[0]));\n      stateIndex = 0;\n    } else if (currentStateIndex === computedStates.length - 2) {\n      dispatch(jumpToAction(stagedActionIds[currentStateIndex + 1]));\n      return;\n    } else {\n      stateIndex = currentStateIndex + 1;\n      dispatch(jumpToAction(stagedActionIds[currentStateIndex + 1]));\n    }\n\n    let counter = stateIndex;\n    const timer = window.setInterval(() => {\n      if (counter + 1 <= computedStates.length - 1) {\n        dispatch(jumpToAction(stagedActionIds[counter + 1]));\n      }\n      counter += 1;\n\n      if (counter >= computedStates.length - 1) {\n        clearInterval(this.state.timer);\n        this.setState({\n          timer: undefined,\n        });\n      }\n    }, speed);\n\n    this.setState({ timer });\n  };\n\n  startRealtimeReplay = () => {\n    if (this.props.computedStates.length < 2) {\n      return;\n    }\n\n    if (this.props.currentStateIndex === this.props.computedStates.length - 1) {\n      this.props.dispatch(jumpToAction(this.props.stagedActionIds[0]));\n\n      this.loop(0);\n    } else {\n      this.loop(this.props.currentStateIndex);\n    }\n  };\n\n  loop = (index: number) => {\n    let currentTimestamp = Date.now();\n    let timestampDiff = this.getLatestTimestampDiff(index);\n\n    const aLoop = () => {\n      const replayDiff = Date.now() - currentTimestamp;\n      if (replayDiff >= timestampDiff) {\n        this.props.dispatch(\n          jumpToAction(\n            this.props.stagedActionIds[this.props.currentStateIndex + 1],\n          ),\n        );\n\n        if (\n          this.props.currentStateIndex >=\n          this.props.computedStates.length - 1\n        ) {\n          this.pauseReplay();\n          return;\n        }\n\n        timestampDiff = this.getLatestTimestampDiff(\n          this.props.currentStateIndex,\n        );\n        currentTimestamp = Date.now();\n\n        this.setState({\n          timer: requestAnimationFrame(aLoop),\n        });\n      } else {\n        this.setState({\n          timer: requestAnimationFrame(aLoop),\n        });\n      }\n    };\n\n    if (index !== this.props.computedStates.length - 1) {\n      this.setState({\n        timer: requestAnimationFrame(aLoop),\n      });\n    }\n  };\n\n  getLatestTimestampDiff = (index: number) =>\n    this.getTimestampOfStateIndex(index + 1) -\n    this.getTimestampOfStateIndex(index);\n\n  getTimestampOfStateIndex = (stateIndex: number) => {\n    const id = this.props.stagedActionIds[stateIndex];\n    return this.props.actionsById[id].timestamp;\n  };\n\n  pauseReplay = (cb?: () => void) => {\n    if (this.state.timer) {\n      cancelAnimationFrame(this.state.timer);\n      clearInterval(this.state.timer);\n      this.setState(\n        {\n          timer: undefined,\n        },\n        () => {\n          if (typeof cb === 'function') {\n            cb();\n          }\n        },\n      );\n    }\n  };\n\n  stepLeft = () => {\n    this.pauseReplay();\n\n    if (this.props.currentStateIndex !== 0) {\n      this.props.dispatch(\n        jumpToAction(\n          this.props.stagedActionIds[this.props.currentStateIndex - 1],\n        ),\n      );\n    }\n  };\n\n  stepRight = () => {\n    this.pauseReplay();\n\n    if (this.props.currentStateIndex !== this.props.computedStates.length - 1) {\n      this.props.dispatch(\n        jumpToAction(\n          this.props.stagedActionIds[this.props.currentStateIndex + 1],\n        ),\n      );\n    }\n  };\n\n  changeReplaySpeed = (replaySpeed: string) => {\n    this.setState({ replaySpeed });\n\n    if (this.state.timer) {\n      this.pauseReplay(() => {\n        if (replaySpeed === 'Live') {\n          this.startRealtimeReplay();\n        } else {\n          this.startReplay();\n        }\n      });\n    }\n  };\n\n  render() {\n    const {\n      currentStateIndex,\n      computedStates,\n      actionsById,\n      stagedActionIds,\n      hideResetButton,\n    } = this.props;\n    const { replaySpeed } = this.state;\n    const theme = this.setUpTheme();\n\n    const max = computedStates.length - 1;\n    const actionId = stagedActionIds[currentStateIndex];\n    let actionType = actionsById[actionId].action.type;\n    if (actionType === undefined) actionType = '<UNDEFINED>';\n    else if (actionType === null) actionType = '<NULL>';\n    else actionType = actionType.toString() || '<EMPTY>';\n\n    const onPlayClick =\n      replaySpeed === 'Live' ? this.startRealtimeReplay : this.startReplay;\n    const playPause = this.state.timer ? (\n      <SliderButton theme={theme} type=\"pause\" onClick={this.pauseReplay} />\n    ) : (\n      <SliderButton\n        theme={theme}\n        type=\"play\"\n        disabled={max <= 0}\n        onClick={onPlayClick}\n      />\n    );\n\n    return (\n      <Toolbar noBorder compact fullHeight theme={theme}>\n        {playPause}\n        <Slider\n          label={actionType}\n          sublabel={`(${actionId})`}\n          min={0}\n          max={max}\n          value={currentStateIndex}\n          onChange={this.handleSliderChange}\n          theme={theme}\n        />\n        <SliderButton\n          theme={theme}\n          type=\"stepLeft\"\n          disabled={currentStateIndex <= 0}\n          onClick={this.stepLeft}\n        />\n        <SliderButton\n          theme={theme}\n          type=\"stepRight\"\n          disabled={currentStateIndex === max}\n          onClick={this.stepRight}\n        />\n        <Divider theme={theme} />\n        <SegmentedControl\n          theme={theme}\n          values={['Live', '1x', '2x']}\n          selected={replaySpeed}\n          onClick={this.changeReplaySpeed}\n        />\n        {!hideResetButton && [\n          <Divider key=\"divider\" theme={theme} />,\n          <Button key=\"reset\" theme={theme} onClick={this.handleReset}>\n            Reset\n          </Button>,\n        ]}\n      </Toolbar>\n    );\n  }\n}\n\nexport default SliderMonitor as unknown as React.ComponentType<\n  ExternalProps<unknown, Action<string>>\n> & {\n  update(\n    monitorProps: ExternalProps<unknown, Action<string>>,\n    // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n    state: {} | undefined,\n    action: Action<string>,\n    // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  ): {};\n  defaultProps: DefaultProps;\n};\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/src/index.ts",
    "content": "export { default as SliderMonitor } from './SliderMonitor.js';\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/src/reducers.ts",
    "content": "export default function reducer() {\n  return {};\n}\n"
  },
  {
    "path": "packages/redux-devtools-slider-monitor/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-ui/.gitignore",
    "content": "storybook-static\n*storybook.log\n"
  },
  {
    "path": "packages/redux-devtools-ui/.storybook/main.ts",
    "content": "import type { StorybookConfig } from '@storybook/react-webpack5';\n\nimport { dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * This function is used to resolve the absolute path of a package.\n * It is needed in projects that use Yarn PnP or are set up within a monorepo.\n */\nfunction getAbsolutePath(packageName: string) {\n  return dirname(\n    fileURLToPath(import.meta.resolve(`${packageName}/package.json`)),\n  );\n}\n\nconst config: StorybookConfig = {\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [getAbsolutePath('@storybook/addon-onboarding')],\n  framework: {\n    name: getAbsolutePath('@storybook/react-vite'),\n    options: {},\n  },\n  staticDirs: ['../fonts'],\n};\nexport default config;\n"
  },
  {
    "path": "packages/redux-devtools-ui/.storybook/preview.tsx",
    "content": "import React from 'react';\nimport type { Preview } from '@storybook/react-vite';\n\nimport { Container } from '../src';\nimport { listSchemes, listThemes } from '../src/utils/theme';\n\nconst withThemeProvider = (Story, context) => (\n  <Container\n    themeData={{\n      theme: context.globals.theme,\n      scheme: context.globals.scheme,\n      colorPreference: context.globals.color,\n    }}\n  >\n    <Story {...context} />\n  </Container>\n);\n\nconst preview: Preview = {\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/i,\n      },\n    },\n  },\n  globalTypes: {\n    theme: {\n      name: 'Theme',\n      description: 'Global theme for components',\n      defaultValue: 'default',\n      toolbar: {\n        items: listThemes(),\n        showName: true,\n      },\n    },\n    scheme: {\n      name: 'Color Scheme',\n      description: 'Global color scheme for components',\n      defaultValue: 'default',\n      toolbar: {\n        items: listSchemes(),\n        showName: true,\n      },\n    },\n    color: {\n      name: 'Color',\n      description: 'Global color for components',\n      defaultValue: 'light',\n      toolbar: {\n        items: ['auto', 'light', 'dark'],\n        showName: true,\n      },\n    },\n  },\n  decorators: [withThemeProvider],\n};\n\nexport default preview;\n"
  },
  {
    "path": "packages/redux-devtools-ui/CHANGELOG.md",
    "content": "# Change Log\n\n## 3.0.0\n\n### Major Changes\n\n- d61d31a: Remove theme prop from Editor. Wrap any usage of Editor in Container to provide theme through context.\n- 804e729: Convert @redux-devtools/ui to ESM\n\n## 2.0.0\n\n### Major Changes\n\n- 6163276: Replace styled-components with Emotion\n\n## 1.4.0\n\n### Minor Changes\n\n- 6830118: Add React 19 to peer deps\n\n## 1.3.2\n\n### Patch Changes\n\n- Updated dependencies [bbb1a40]\n  - react-base16-styling@0.10.0\n\n## 1.3.1\n\n### Patch Changes\n\n- 7f5bddbd: Widen peer dependencies\n\n## 1.3.0\n\n### Minor Changes\n\n- 8a7eae4: Add React 18 to peerDependencies range\n\n## 1.2.2\n\n### Patch Changes\n\n- a25551f: Fix failing to bundle fonts\n\n## [1.0.0-9](https://github.com/reduxjs/redux-devtools/compare/devui@1.0.0-8...devui@1.0.0-9) (2021-06-11)\n\n### Bug Fixes\n\n- fix Select types and usages ([#724](https://github.com/reduxjs/redux-devtools/issues/724)) ([07e409d](https://github.com/reduxjs/redux-devtools/commit/07e409de6a1c3d362929d854542df0c1d74ce18e))\n- **devui:** clean up after fixing UI bugs ([#728](https://github.com/reduxjs/redux-devtools/issues/728)) ([dbc08ab](https://github.com/reduxjs/redux-devtools/commit/dbc08ab1b4d6d7d8b77af9cece9e9b329a95b31e))\n- **devui:** Fix buggy UI behaviors with redux-devtools-app ([#709](https://github.com/reduxjs/redux-devtools/issues/709)) ([ed25a72](https://github.com/reduxjs/redux-devtools/commit/ed25a72e99d56c2141175cd0cb4306353e65e6ad))\n- **devui:** fix Select widget in Form ([#722](https://github.com/reduxjs/redux-devtools/issues/722)) ([a8d99ee](https://github.com/reduxjs/redux-devtools/commit/a8d99ee424b48974314b8b94e1b93f84924b4352))\n- **devui:** fix style of Select ([#721](https://github.com/reduxjs/redux-devtools/issues/721)) ([bb72311](https://github.com/reduxjs/redux-devtools/commit/bb72311e1ccb7a0425a02a1d9271c8534fcd90e0))\n\n## [1.0.0-8](https://github.com/reduxjs/redux-devtools/compare/devui@1.0.0-7...devui@1.0.0-8) (2021-03-06)\n\n### Features\n\n- update peer dependencies to allow react@^17 ([#703](https://github.com/reduxjs/redux-devtools/issues/703)) ([2aaa9c1](https://github.com/reduxjs/redux-devtools/commit/2aaa9c10a383e3a7ab20b3ab14639781fd7bb2eb))\n\n## [1.0.0-7](https://github.com/reduxjs/redux-devtools/compare/devui@1.0.0-6...devui@1.0.0-7) (2021-03-06)\n\n### Bug Fixes\n\n- **redux-devtools-test-generator:** fix devui's Select component ([#637](https://github.com/reduxjs/redux-devtools/issues/637)) ([f9f15a4](https://github.com/reduxjs/redux-devtools/commit/f9f15a41defab9c9ce6ba7491f75a7ce69aae152))\n\n### Features\n\n- **redux-devtools-slider-monitor:** convert to TypeScript ([#631](https://github.com/reduxjs/redux-devtools/issues/631)) ([8991732](https://github.com/reduxjs/redux-devtools/commit/89917320e5ecf33dc3625b05daa1e9fe120a783d))\n\n## [1.0.0-6](https://github.com/reduxjs/redux-devtools/compare/devui@1.0.0-5...devui@1.0.0-6) (2020-09-07)\n\n**Note:** Version bump only for package devui\n\n## [1.0.0-5](https://github.com/reduxjs/redux-devtools/compare/devui@1.0.0-4...devui@1.0.0-5) (2020-08-14)\n\n**Note:** Version bump only for package devui\n"
  },
  {
    "path": "packages/redux-devtools-ui/README.md",
    "content": "# Redux DevTools UI\n\nWIP\n"
  },
  {
    "path": "packages/redux-devtools-ui/eslint.config.mjs",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTsReact from '../../eslint.ts.react.config.base.mjs';\nimport eslintTsReactJest from '../../eslint.ts.react.jest.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTsReact(import.meta.dirname),\n  ...eslintTsReactJest(import.meta.dirname),\n  {\n    ignores: ['.storybook', 'jest.config.ts', 'lib', 'storybook-static'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-ui/fonts/index.css",
    "content": "/* source-code-pro-regular - latin */\n@font-face {\n  font-family: 'Source Code Pro';\n  font-style: normal;\n  font-weight: 400;\n  src:\n    local('Source Code Pro'),\n    local('SourceCodePro-Regular'),\n    url('./source-code-pro-v6-latin/source-code-pro-v6-latin-regular.woff2')\n      format('woff2');\n}\n/* source-sans-pro-regular - latin */\n@font-face {\n  font-family: 'Source Sans Pro';\n  font-style: normal;\n  font-weight: 400;\n  src:\n    local('Source Sans Pro'),\n    local('SourceSansPro-Regular'),\n    url('./source-sans-pro-v9-latin/source-sans-pro-v9-latin-regular.woff2')\n      format('woff2');\n}\n/* source-sans-pro-600 - latin */\n@font-face {\n  font-family: 'Source Sans Pro';\n  font-style: normal;\n  font-weight: 600;\n  src:\n    local('Source Sans Pro Semibold'),\n    local('SourceSansPro-Semibold'),\n    url('./source-sans-pro-v9-latin/source-sans-pro-v9-latin-600.woff2')\n      format('woff2');\n}\n\n/* roboto-regular - latin */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 400;\n  src:\n    local('Roboto'),\n    local('Roboto-Regular'),\n    url('./roboto-v15-latin/roboto-v15-latin-regular.woff2') format('woff2');\n}\n/* roboto-mono-regular - latin */\n@font-face {\n  font-family: 'Roboto Mono';\n  font-style: normal;\n  font-weight: 400;\n  src:\n    local('Roboto Mono'),\n    local('RobotoMono-Regular'),\n    url('./roboto-mono-v4-latin/roboto-mono-v4-latin-regular.woff2')\n      format('woff2');\n}\n\n/* Generated with https://google-webfonts-helper.herokuapp.com */\n"
  },
  {
    "path": "packages/redux-devtools-ui/jest.config.ts",
    "content": "import { createDefaultEsmPreset, type JestConfigWithTsJest } from 'ts-jest';\n\nconst presetConfig = createDefaultEsmPreset({\n  tsconfig: 'tsconfig.test.json',\n});\n\nconst jestConfig: JestConfigWithTsJest = {\n  ...presetConfig,\n  testEnvironment: 'jsdom',\n  moduleNameMapper: {\n    '^(\\\\.{1,2}/.*)\\\\.js$': '$1',\n    '\\\\.css$': '<rootDir>/test/__mocks__/styleMock.ts',\n  },\n};\n\nexport default jestConfig;\n"
  },
  {
    "path": "packages/redux-devtools-ui/package.json",
    "content": "{\n  \"name\": \"@redux-devtools/ui\",\n  \"version\": \"3.0.0\",\n  \"description\": \"Reusable React components for building DevTools monitors and apps.\",\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-ui\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)\",\n  \"files\": [\n    \"fonts\",\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": \"./lib/index.js\",\n  \"type\": \"module\",\n  \"sideEffects\": [\n    \"*.css\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"start\": \"pnpm run storybook\",\n    \"storybook\": \"storybook dev -p 6006\",\n    \"build:storybook\": \"storybook build --quiet\",\n    \"build\": \"pnpm run build:lib && pnpm run build:storybook\",\n    \"build:lib\": \"tsc && pnpm run build:css\",\n    \"build:css\": \"ncp fonts lib/fonts\",\n    \"clean\": \"rimraf lib storybook-static\",\n    \"test\": \"node --experimental-vm-modules node_modules/jest/bin/jest.js\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run lint && pnpm run test\"\n  },\n  \"dependencies\": {\n    \"@codemirror/lang-javascript\": \"^6.2.5\",\n    \"@codemirror/view\": \"^6.40.0\",\n    \"@lezer/highlight\": \"^1.2.3\",\n    \"@rjsf/core\": \"^6.4.1\",\n    \"@rjsf/utils\": \"^6.4.1\",\n    \"@rjsf/validator-ajv8\": \"^6.4.1\",\n    \"@types/codemirror\": \"^5.60.17\",\n    \"@types/json-schema\": \"^7.0.15\",\n    \"@types/simple-element-resize-detector\": \"^1.3.3\",\n    \"@uiw/codemirror-themes\": \"^4.25.8\",\n    \"@uiw/react-codemirror\": \"^4.25.8\",\n    \"color\": \"^5.0.3\",\n    \"react-base16-styling\": \"workspace:^\",\n    \"react-icons\": \"^5.6.0\",\n    \"react-select\": \"^5.10.2\",\n    \"simple-element-resize-detector\": \"^1.3.0\"\n  },\n  \"devDependencies\": {\n    \"@emotion/react\": \"^11.14.0\",\n    \"@emotion/styled\": \"^11.14.1\",\n    \"@jest/globals\": \"^30.3.0\",\n    \"@storybook/addon-onboarding\": \"^10.2.19\",\n    \"@storybook/react-vite\": \"^10.2.19\",\n    \"@testing-library/dom\": \"^10.4.1\",\n    \"@testing-library/react\": \"^16.3.2\",\n    \"@testing-library/user-event\": \"^14.6.1\",\n    \"@types/color\": \"^4.2.0\",\n    \"@types/node\": \"^24.12.0\",\n    \"@types/jest\": \"^30.0.0\",\n    \"@types/react\": \"^19.2.14\",\n    \"csstype\": \"^3.2.3\",\n    \"jest\": \"^30.3.0\",\n    \"jest-environment-jsdom\": \"^30.3.0\",\n    \"ncp\": \"^2.0.0\",\n    \"react\": \"^19.2.4\",\n    \"react-dom\": \"^19.2.4\",\n    \"react-is\": \"^19.2.4\",\n    \"rimraf\": \"^6.1.3\",\n    \"storybook\": \"^10.2.19\",\n    \"ts-jest\": \"^29.4.6\",\n    \"typescript\": \"~5.9.3\",\n    \"vite\": \"^8.0.0\"\n  },\n  \"peerDependencies\": {\n    \"@emotion/react\": \"^11.14.0\",\n    \"@emotion/styled\": \"^11.14.1\",\n    \"@types/react\": \"^16.3.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react\": \"^16.3.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Button/Button.stories.tsx",
    "content": "import React from 'react';\nimport styled from '@emotion/styled';\nimport { MdFiberManualRecord } from 'react-icons/md';\nimport { Meta, StoryObj } from '@storybook/react-vite';\nimport Button from './index.js';\n\nconst meta: Meta = {\n  title: 'Button',\n  component: Button,\n};\n\nexport default meta;\n\nconst Container = styled.div`\n  display: flex;\n  height: 100%;\n  width: 100%;\n  justify-content: center;\n  align-items: center;\n`;\n\ntype Story = StoryObj<typeof Button>;\n\nexport const Default: Story = {\n  render: (args) => (\n    <Container>\n      <Button {...args} />\n    </Container>\n  ),\n  args: {\n    title: 'Hello Tooltip! \\\\a And from new line hello!',\n    tooltipPosition: 'top',\n    primary: true,\n    size: 'normal',\n    disabled: false,\n    children: 'Hello Button',\n  },\n  argTypes: {\n    onClick: { control: { disable: true } },\n    type: { control: { disable: true } },\n    mark: { control: { disable: true } },\n    theme: { control: { disable: true } },\n  },\n};\n\nexport const Mark: Story = {\n  render: Default.render,\n  args: {\n    mark: 'base08',\n    title: 'Hello Tooltip',\n    tooltipPosition: 'top',\n    size: 'normal',\n    disabled: false,\n    children: <MdFiberManualRecord />,\n  },\n  argTypes: {\n    children: { control: { disable: true } },\n    onClick: { control: { disable: true } },\n    type: { control: { disable: true } },\n    primary: { control: { disable: true } },\n    theme: { control: { disable: true } },\n  },\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Button/Button.tsx",
    "content": "import React, { Component, ReactNode } from 'react';\nimport type { Base16Theme } from 'react-base16-styling';\nimport createStyledComponent from '../utils/createStyledComponent.js';\nimport * as styles from './styles/index.js';\nimport { commonStyle, tooltipStyle } from './styles/common.js';\n\nconst ButtonWrapper = createStyledComponent(styles, 'button');\nconst TooltipWrapper = createStyledComponent(tooltipStyle);\nconst CommonWrapper = createStyledComponent(commonStyle);\n\nexport type TooltipPosition =\n  | 'top'\n  | 'bottom'\n  | 'left'\n  | 'right'\n  | 'bottom-left'\n  | 'bottom-right'\n  | 'top-left'\n  | 'top-right';\n\nexport type Size = 'big' | 'normal' | 'small';\n\nexport type Mark =\n  | 'base08'\n  | 'base09'\n  | 'base0A'\n  | 'base0B'\n  | 'base0C'\n  | 'base0D'\n  | 'base0E'\n  | 'base0F';\n\nexport interface ButtonProps {\n  children: ReactNode;\n  title?: string;\n  tooltipPosition: TooltipPosition;\n  onClick?: React.MouseEventHandler<HTMLButtonElement>;\n  type?: 'button' | 'reset' | 'submit';\n  disabled?: boolean;\n  primary?: boolean;\n  size?: Size;\n  mark?: Mark | false;\n  theme?: Base16Theme;\n}\n\nexport default class Button extends Component<ButtonProps> {\n  shouldComponentUpdate(nextProps: ButtonProps) {\n    return (\n      nextProps.children !== this.props.children ||\n      nextProps.disabled !== this.props.disabled ||\n      nextProps.mark !== this.props.mark ||\n      nextProps.size !== this.props.size ||\n      nextProps.primary !== this.props.primary ||\n      nextProps.tooltipPosition !== this.props.tooltipPosition ||\n      nextProps.title !== this.props.title\n    );\n  }\n\n  onMouseUp: React.MouseEventHandler<HTMLButtonElement> = (e) => {\n    e.currentTarget.blur();\n  };\n\n  render() {\n    const button = (\n      <ButtonWrapper\n        theme={this.props.theme}\n        aria-label={this.props.title}\n        primary={this.props.primary}\n        disabled={this.props.disabled}\n        onMouseUp={this.onMouseUp}\n        onClick={this.props.onClick}\n        type={this.props.type}\n      >\n        {this.props.children}\n      </ButtonWrapper>\n    );\n\n    const Wrapper = this.props.title ? TooltipWrapper : CommonWrapper;\n    return (\n      <Wrapper\n        theme={this.props.theme}\n        tooltipTitle={this.props.title}\n        tooltipPosition={this.props.tooltipPosition}\n        size={this.props.size}\n        mark={this.props.mark}\n      >\n        {button}\n      </Wrapper>\n    );\n  }\n\n  static defaultProps = {\n    tooltipPosition: 'top',\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Button/index.ts",
    "content": "export { default } from './Button.js';\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Button/styles/common.ts",
    "content": "import { css } from '@emotion/react';\nimport { fadeIn } from '../../utils/animations.js';\nimport colorEffect from '../../utils/color.js';\nimport { Mark, Size, TooltipPosition } from '../Button.js';\nimport { Theme } from '../../themes/default.js';\n\nconst both = (tooltipPosition: TooltipPosition) => {\n  switch (tooltipPosition) {\n    case 'bottom':\n      return `\n      transform: translate(-50%, 100%);\n      top: auto;\n      `;\n    case 'left':\n      return `\n      transform: translate(-100%, -50%);\n      top: 50%;\n      right: auto;\n      `;\n    case 'right':\n      return `\n      transform: translate(100%, -50%);\n      top: 50%;\n      left: auto;\n      `;\n    case 'bottom-left':\n      return `\n      transform: translate(-100%, 100%);\n      top: auto;\n      `;\n    case 'bottom-right':\n      return `\n      transform: translateY(100%);\n      top: auto;\n      `;\n    case 'top-left':\n      return `\n      transform: translate(-100%, -100%);\n      `;\n    case 'top-right':\n      return `\n      transform: translateY(-100%);\n      `;\n    default:\n      return `\n       transform: translate(-50%, -100%);\n      `;\n  }\n};\n\nconst before = (tooltipPosition: TooltipPosition) => {\n  switch (tooltipPosition) {\n    case 'bottom-left':\n      return `\n      left: calc(50% + 11px);\n      `;\n    case 'bottom-right':\n      return `\n      left: calc(50% - 11px);\n      `;\n    case 'top-left':\n      return `\n      left: calc(50% + 11px);\n      `;\n    case 'top-right':\n      return `\n      left: calc(50% - 11px);\n      `;\n    default:\n      return '';\n  }\n};\n\nconst after = (tooltipPosition: TooltipPosition, color: string) => {\n  switch (tooltipPosition) {\n    case 'bottom':\n      return `\n      border-color: transparent transparent ${color} transparent;\n      `;\n    case 'left':\n      return `\n      border-color: transparent transparent transparent ${color};\n      `;\n    case 'right':\n      return `\n      border-color: transparent ${color} transparent transparent;\n      `;\n    case 'bottom-left':\n      return `\n      left: calc(50% + 10px);\n      border-color: transparent transparent ${color} transparent;\n      `;\n    case 'bottom-right':\n      return `\n      left: calc(50% - 10px);\n      border-color: transparent transparent ${color} transparent;\n      `;\n    case 'top-left':\n      return `\n      left: calc(50% + 10px);\n      border-color: ${color} transparent transparent transparent;\n      `;\n    case 'top-right':\n      return `\n      left: calc(50% - 10px);\n      border-color: ${color} transparent transparent transparent;\n      `;\n    default:\n      return `\n       border-color: ${color} transparent transparent transparent;\n      `;\n  }\n};\n\nconst getDirection = (tooltipPosition: TooltipPosition) => {\n  return tooltipPosition.indexOf('-') > 0\n    ? tooltipPosition.substring(0, tooltipPosition.indexOf('-'))\n    : tooltipPosition;\n};\n\nconst getSize = (size: Size | undefined) => {\n  switch (size) {\n    case 'big':\n      return 'min-height: 34px; padding: 2px 12px;';\n    case 'small':\n      return 'padding: 0;';\n    default:\n      return 'min-height: 30px; padding: 2px 7px;';\n  }\n};\n\ninterface CommonStyleProps {\n  size: Size | undefined;\n  mark: Mark | false | undefined;\n}\n\nexport const commonStyle = ({\n  theme,\n  mark,\n  size,\n}: CommonStyleProps & { theme: Theme }) => css`\n  display: inline-block;\n  position: relative;\n  flex-shrink: 0;\n  line-height: 0;\n  margin: 0 1px;\n\n  & > button {\n    width: 100%;\n    line-height: 0;\n    ${getSize(size)}\n\n    > svg {\n      font-size: 1.5em;\n      overflow: visible;\n      pointer-events: none;\n    }\n\n    ${mark &&\n    `\n    background-color: ${colorEffect(\n      theme[mark],\n      'fade',\n      theme.light ? 0.92 : 0.82,\n    )};\n  \n    > svg {\n      color: ${theme[mark]};\n      stroke: ${theme[mark]};\n      stroke-width: 14px;\n      stroke-opacity: 0.2;\n      user-select: none;\n    }\n  `}\n  }\n`;\n\ninterface TooltipStyleProps {\n  tooltipTitle: string | undefined;\n  tooltipPosition: TooltipPosition;\n  size: Size | undefined;\n  mark: Mark | false | undefined;\n}\n\nexport const tooltipStyle = ({\n  theme,\n  tooltipTitle,\n  tooltipPosition,\n  mark,\n  size,\n}: TooltipStyleProps & { theme: Theme }) => css`\n  ${commonStyle({ theme, mark, size })}\n\n  &:before {\n    content: '${tooltipTitle}';\n    white-space: pre;\n    color: ${theme.base06};\n    line-height: 16px;\n    padding: 4px 8px;\n    border-radius: 3px;\n    background: ${theme.base01};\n    border: 1px solid ${theme.base02};\n    box-shadow:\n      1px 1px 2px -1px ${theme.base02},\n      1px 1px 2px 0px ${theme.base02};\n  }\n\n  &:after,\n  &:before {\n    opacity: 0;\n    visibility: hidden;\n    position: absolute;\n    left: 50%;\n    z-index: 999;\n    ${both(tooltipPosition)}\n    user-select: none;\n  }\n\n  &:before {\n    transition: 0.3s ease-in-out;\n  }\n\n  &:before {\n    ${before(tooltipPosition)}\n    ${getDirection(tooltipPosition)}: 3px;\n    ${theme.type === 'material'\n      ? css`\n          animation: ${fadeIn} 500ms;\n        `\n      : ''}\n  }\n\n  ${theme.type !== 'material' &&\n  `\n  &:after {\n    content: \"\";\n    border-style: solid;\n    border-width: 7px;\n    margin: 1px;\n    ${after(tooltipPosition, theme.base02)}\n    ${getDirection(tooltipPosition)}: 7px;\n  }\n  `}\n\n  &:hover:after,\n  &:hover:before {\n    opacity: 0.9;\n    visibility: visible;\n  }\n  &:hover:after {\n    ${getDirection(tooltipPosition)}: 8px;\n    transition-delay: 500ms;\n  }\n  &:hover:before {\n    ${getDirection(tooltipPosition)}: -4px;\n    transition-delay: 200ms;\n  }\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Button/styles/default.ts",
    "content": "import { css } from '@emotion/react';\nimport { Theme } from '../../themes/default.js';\n\nexport interface StyleProps {\n  primary: boolean | undefined;\n  disabled: boolean | undefined;\n}\n\nexport const style = ({\n  theme,\n  primary,\n  disabled,\n}: StyleProps & { theme: Theme }) => css`\n  box-sizing: border-box;\n  -webkit-font-smoothing: antialiased;\n  outline: none;\n  font-weight: 600;\n  text-decoration: none;\n  display: inline-block;\n  transition: all 0.5s;\n  margin: auto 0;\n  border: 1px solid ${theme.base02};\n  border-radius: 4px;\n  ${primary\n    ? `\n  background-color: ${theme.base05};\n  color: ${theme.base00};\n  `\n    : `\n  background-color: ${theme.base01};\n  color: ${theme.base05};\n `}\n  ${disabled\n    ? `\n  cursor: not-allowed;\n  opacity: 0.6;\n  `\n    : `\n  cursor: pointer;\n  `}\n\n  ${!disabled &&\n  `\n  &:hover,\n  &:focus {\n    background-color: ${primary ? theme.base07 : theme.base02};\n    box-shadow: 1px 1px 2px ${theme.base03};\n  }\n `}\n  &:focus {\n    border: 1px solid ${theme.base0D};\n  }\n  &:active {\n    border: 1px solid ${theme.base03};\n    box-shadow: 1px 1px 2px ${theme.base04};\n  }\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Button/styles/index.ts",
    "content": "export { style as default } from './default.js';\nexport { style as material } from './material.js';\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Button/styles/material.ts",
    "content": "import { css } from '@emotion/react';\nimport { ripple } from '../../utils/animations.js';\nimport { StyleProps } from './default.js';\nimport { Theme } from '../../themes/default.js';\n\nexport const style = ({\n  theme,\n  primary,\n  disabled,\n}: StyleProps & { theme: Theme }) => css`\n  box-sizing: border-box;\n  -webkit-font-smoothing: antialiased;\n  outline: none;\n  font-family: inherit;\n  font-weight: 600;\n  text-decoration: none;\n  display: inline-block;\n  border: none;\n  text-transform: uppercase;\n  margin: auto 0;\n  background-color: ${primary ? theme.base05 : theme.base01};\n  ${disabled\n    ? `\n  cursor: not-allowed;\n  color: ${theme.base04};\n  opacity: 0.6;\n  `\n    : `\n  cursor: pointer;\n  color: ${primary ? theme.base00 : theme.base05};\n  `}\n  ${!disabled\n    ? `\n    box-shadow:\n      0 2px 2px 0 ${theme.base03},\n      0 3px 1px -2px ${theme.base02},\n      0 1px 5px 0 ${theme.base02};\n  `\n    : ''}\n\n\n  &:hover, &:focus:not(:active) {\n    background-color: ${theme.base02};\n  }\n\n  &:focus:not(:active) {\n    background-color: ${theme.base02};\n    box-shadow:\n      0 0 4px ${theme.base02},\n      0 4px 8px ${theme.base04};\n  }\n\n  ${ripple(theme)}\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Container/index.tsx",
    "content": "import React from 'react';\nimport { ThemeProvider } from '@emotion/react';\nimport { useTheme, ThemeData } from '../utils/theme.js';\nimport { MainContainerWrapper, ContainerWrapper } from './styles/index.js';\nimport { Theme } from '../themes/default.js';\n\ninterface ContainerFromThemeDataProps {\n  children?: React.ReactNode;\n  themeData: ThemeData;\n  className?: string;\n}\n\nconst ContainerFromThemeData: React.FunctionComponent<\n  ContainerFromThemeDataProps\n> = ({ themeData, className, children }) => {\n  const theme = useTheme(themeData);\n  return (\n    <ThemeProvider theme={theme}>\n      <MainContainerWrapper className={className}>\n        {children}\n      </MainContainerWrapper>\n    </ThemeProvider>\n  );\n};\n\ninterface Props {\n  children?: React.ReactNode;\n  themeData?: ThemeData;\n  theme?: Theme;\n  className?: string;\n}\n\nconst Container: React.FunctionComponent<Props> = ({\n  themeData,\n  className,\n  theme,\n  children,\n}) => {\n  if (!themeData) {\n    return (\n      <ContainerWrapper className={className} theme={theme}>\n        {children}\n      </ContainerWrapper>\n    );\n  }\n\n  return (\n    <ContainerFromThemeData themeData={themeData} className={className}>\n      {children}\n    </ContainerFromThemeData>\n  );\n};\n\nexport default Container;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Container/styles/index.ts",
    "content": "import styled from '@emotion/styled';\nimport color from '../../utils/color.js';\nimport { Theme } from '../../themes/default.js';\n\nexport const MainContainerWrapper = styled.div`\n  display: flex;\n  height: 100%;\n  width: 100%;\n  flex-flow: column nowrap;\n  overflow: auto;\n  background-color: ${(props: { theme?: Theme }) =>\n    color(props.theme!.base00, 'lighten', 0.03)};\n  color: ${(props) => props.theme.base07};\n  font-size: 12px;\n\n  div,\n  input,\n  textarea,\n  keygen,\n  select,\n  button {\n    font-family: ${(props) => props.theme.fontFamily || 'monaco, monospace'};\n  }\n\n  .cm-editor div,\n  pre,\n  .monitor div,\n  .slider div {\n    font-family: ${(props) =>\n      props.theme.codeFontFamily || props.theme.fontFamily || 'monospace'};\n  }\n\n  .monitor {\n    flex-grow: 1;\n    display: flex;\n    flex-flow: column nowrap;\n    overflow: auto;\n\n    > div {\n      flex-grow: 1;\n    }\n  }\n`;\n\nexport const ContainerWrapper = styled.div`\n  display: flex;\n  height: 100%;\n  width: 100%;\n  flex-flow: column nowrap;\n  overflow: auto;\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/ContextMenu/ContextMenu.stories.tsx",
    "content": "import React from 'react';\nimport styled from '@emotion/styled';\nimport { Meta, StoryObj } from '@storybook/react-vite';\nimport ContextMenu from './index.js';\nimport { items } from './data.js';\n\nconst meta: Meta = {\n  title: 'ContextMenu',\n  component: ContextMenu,\n};\n\nexport default meta;\n\nconst Container = styled.div`\n  display: flex;\n  height: 100%;\n  width: 100%;\n  justify-content: center;\n  align-items: center;\n`;\n\ntype Story = StoryObj<typeof ContextMenu>;\n\nexport const Default: Story = {\n  render: (args) => (\n    <Container>\n      <ContextMenu {...args} />\n    </Container>\n  ),\n  args: {\n    visible: true,\n    x: 100,\n    y: 100,\n    items,\n  },\n  argTypes: {\n    visible: { control: { disable: true } },\n    items: { control: { disable: true } },\n    onClick: { control: { disable: true } },\n  },\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/ContextMenu/ContextMenu.tsx",
    "content": "import React, { Component } from 'react';\nimport createStyledComponent from '../utils/createStyledComponent.js';\nimport styles from './styles/index.js';\n\nconst ContextMenuWrapper = createStyledComponent(styles);\n\ntype ReactButtonElement = React.ReactElement<\n  React.JSX.IntrinsicElements['button'],\n  'button'\n>;\ntype Item = { name: string; value?: string } | ReactButtonElement;\n\nfunction isReactButtonElement(item: Item): item is ReactButtonElement {\n  return (item as ReactButtonElement).type === 'button';\n}\n\nexport interface ContextMenuProps {\n  items: Item[];\n  onClick: (value: string) => void;\n  x: number;\n  y: number;\n  visible?: boolean;\n}\n\nexport default class ContextMenu extends Component<ContextMenuProps> {\n  menu?: HTMLDivElement | null;\n\n  componentDidMount() {\n    this.amendPosition();\n  }\n\n  componentDidUpdate(prevProps: ContextMenuProps) {\n    if (prevProps.x !== this.props.x || prevProps.y !== this.props.y) {\n      this.amendPosition();\n    }\n  }\n\n  onMouseUp: React.MouseEventHandler<HTMLButtonElement> = (e) => {\n    e.currentTarget.blur();\n  };\n\n  onClick: React.MouseEventHandler<HTMLButtonElement> = (e) => {\n    this.props.onClick(e.currentTarget.value);\n  };\n\n  amendPosition() {\n    const { x, y } = this.props;\n    const { scrollTop, scrollLeft } = document.documentElement;\n    const { innerWidth, innerHeight } = window;\n    const rect = this.menu!.getBoundingClientRect();\n    let left = x + scrollLeft;\n    let top = y + scrollTop;\n\n    if (y + rect.height > innerHeight) {\n      top = innerHeight - rect.height;\n    }\n    if (x + rect.width > innerWidth) {\n      left = innerWidth - rect.width;\n    }\n    if (top < 0) {\n      top = rect.height < innerHeight ? (innerHeight - rect.height) / 2 : 0;\n    }\n    if (left < 0) {\n      left = rect.width < innerWidth ? (innerWidth - rect.width) / 2 : 0;\n    }\n\n    this.menu!.style.top = `${top}px`;\n    this.menu!.style.left = `${left}px`;\n  }\n\n  renderItems() {\n    return this.props.items.map((item) => {\n      if (isReactButtonElement(item)) return item;\n      const value = item.value || item.name;\n      return (\n        <button\n          key={value}\n          value={value}\n          onMouseUp={this.onMouseUp}\n          onClick={this.onClick}\n        >\n          {item.name}\n        </button>\n      );\n    });\n  }\n\n  menuRef: React.RefCallback<HTMLDivElement> = (c) => {\n    this.menu = c;\n  };\n\n  render() {\n    return (\n      <ContextMenuWrapper\n        ref={this.menuRef}\n        left={this.props.x}\n        top={this.props.y}\n        visible={this.props.visible}\n      >\n        {this.renderItems()}\n      </ContextMenuWrapper>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/ContextMenu/data.ts",
    "content": "export const items = [\n  {\n    name: 'Menu Item 1',\n  },\n  {\n    name: 'Menu Item 2',\n  },\n  {\n    name: 'Menu Item 3',\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/ContextMenu/index.ts",
    "content": "export { default } from './ContextMenu.js';\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/ContextMenu/styles/index.ts",
    "content": "import { css } from '@emotion/react';\nimport { Theme } from '../../themes/default.js';\n\ninterface StyleProps {\n  left: number;\n  top: number;\n  visible: boolean | undefined;\n}\n\nexport default ({\n  theme,\n  left,\n  top,\n  visible,\n}: StyleProps & { theme: Theme }) => css`\n  ${visible\n    ? `\n    visibility: visible;\n    opacity: 1;\n    transition: opacity 0.2s linear;\n    `\n    : `\n    visibility: hidden;\n    opacity: 0;\n    transition: visibility 0s 0.2s, opacity 0.2s linear;\n  `}\n  position: fixed;\n  top: ${top}px;\n  left: ${left}px;\n  font-size: 14px;\n  color: ${theme.base07};\n  cursor: pointer;\n  display: block;\n  line-height: ${theme.inputInternalHeight / 2}px;\n  border: 1px solid ${theme.base02};\n\n  button {\n    box-sizing: border-box;\n    background-color: ${theme.base00};\n    color: ${theme.base07};\n    cursor: pointer;\n    display: block;\n    padding: ${theme.inputHeight / 3}px;\n    line-height: ${theme.inputInternalHeight / 2}px;\n    border: none;\n    white-space: nowrap;\n\n    &:hover {\n      background-color: ${theme.base02};\n      color: ${theme.base07};\n    }\n    &:focus {\n      outline: 0;\n    }\n  }\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Dialog/Dialog.stories.tsx",
    "content": "import React from 'react';\nimport { Meta, StoryObj } from '@storybook/react-vite';\nimport Dialog from './index.js';\nimport { schema, uiSchema, formData } from '../Form/schema.js';\n\nconst meta: Meta = {\n  title: 'Dialog',\n  component: Dialog,\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof Dialog>;\n\nexport const Default: Story = {\n  args: {\n    title: 'Dialog Title',\n    submitText: 'Submit!',\n    open: true,\n    noHeader: false,\n    noFooter: false,\n    modal: false,\n    fullWidth: false,\n    children: 'Hello Dialog!',\n  },\n  argTypes: {\n    actions: { control: { disable: true } },\n    onDismiss: { control: { disable: true } },\n    onSubmit: { control: { disable: true } },\n    theme: { control: { disable: true } },\n  },\n};\n\nexport const WithForm: Story = {\n  args: {\n    open: true,\n    noHeader: false,\n    noFooter: false,\n    fullWidth: false,\n    submitText: 'Submit!',\n    formData,\n    schema,\n    uiSchema,\n  },\n  argTypes: {\n    title: { control: { disable: true } },\n    children: { control: { disable: true } },\n    actions: { control: { disable: true } },\n    modal: { control: { disable: true } },\n    onDismiss: { control: { disable: true } },\n    onSubmit: { control: { disable: true } },\n    theme: { control: { disable: true } },\n  },\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Dialog/Dialog.tsx",
    "content": "import React, { PureComponent } from 'react';\nimport type { Base16Theme } from 'react-base16-styling';\nimport createStyledComponent from '../utils/createStyledComponent.js';\nimport * as styles from './styles/index.js';\nimport Button from '../Button/index.js';\nimport Form from '../Form/index.js';\nimport { Props as FormProps } from '../Form/Form.js';\n\nconst DialogWrapper = createStyledComponent(styles);\n\nexport interface DialogProps {\n  open?: boolean;\n  title?: string;\n  children?: React.ReactNode;\n  actions?: React.ReactNode[];\n  submitText?: string;\n  fullWidth?: boolean;\n  noHeader?: boolean;\n  noFooter?: boolean;\n  modal?: boolean;\n  onDismiss: (\n    e: React.MouseEvent<HTMLButtonElement | HTMLDivElement> | false,\n  ) => void;\n  onSubmit: () => void;\n  theme?: Base16Theme;\n}\n\ntype Rest<P> = Omit<\n  DialogProps & FormProps<P>,\n  | 'modal'\n  | 'open'\n  | 'fullWidth'\n  | 'title'\n  | 'children'\n  | 'actions'\n  | 'noHeader'\n  | 'noFooter'\n  | 'submitText'\n  | 'onDismiss'\n>;\nfunction isForm<P>(rest?: FormProps<P>): rest is FormProps<P> {\n  return (rest as FormProps<P>).schema !== undefined;\n}\n\nexport default class Dialog<P> extends PureComponent<\n  DialogProps | (Omit<DialogProps, 'onSubmit'> & FormProps<P>)\n> {\n  submitButton?: HTMLInputElement | null;\n\n  onSubmit = () => {\n    if (this.submitButton) this.submitButton.click();\n    else (this.props.onSubmit as () => void)();\n  };\n\n  getFormButtonRef: React.RefCallback<HTMLInputElement> = (node) => {\n    this.submitButton = node;\n  };\n\n  onKeyDown: React.KeyboardEventHandler<HTMLDivElement> = (e) => {\n    if (e.keyCode === 27 /* esc */) {\n      e.preventDefault();\n      this.props.onDismiss(false);\n    }\n  };\n\n  render() {\n    const {\n      modal,\n      open,\n      fullWidth,\n      title,\n      children,\n      actions,\n      noHeader,\n      noFooter,\n      submitText,\n      onDismiss,\n      ...rest\n    } = this.props;\n    const schema = (rest as Rest<P>).schema;\n\n    return (\n      <DialogWrapper\n        open={open}\n        fullWidth={fullWidth}\n        onKeyDown={this.onKeyDown}\n        theme={rest.theme}\n      >\n        <div onClick={!modal ? onDismiss : undefined} />\n        <div>\n          {!noHeader && (\n            <div className=\"mc-dialog--header\">\n              <div>{schema ? schema.title || title : title}</div>\n              {!modal && <button onClick={onDismiss}>×</button>}\n            </div>\n          )}\n          <div className=\"mc-dialog--body\">\n            {children}\n            {isForm(rest as FormProps<P>) && (\n              <Form {...(rest as FormProps<P>)}>\n                {!noFooter && (\n                  <input\n                    type=\"submit\"\n                    ref={this.getFormButtonRef}\n                    className=\"mc-dialog--hidden\"\n                  />\n                )}\n              </Form>\n            )}\n          </div>\n          {!noFooter &&\n            (actions ? (\n              <div className=\"mc-dialog--footer\">\n                {submitText\n                  ? [\n                      ...actions,\n                      <Button\n                        key=\"default-submit\"\n                        primary\n                        onClick={this.onSubmit}\n                      >\n                        {submitText}\n                      </Button>,\n                    ]\n                  : actions}\n              </div>\n            ) : (\n              <div className=\"mc-dialog--footer\">\n                <Button onClick={onDismiss}>Cancel</Button>\n                <Button primary onClick={this.onSubmit}>\n                  {submitText || 'Submit'}\n                </Button>\n              </div>\n            ))}\n        </div>\n      </DialogWrapper>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Dialog/index.ts",
    "content": "export { default } from './Dialog.js';\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Dialog/styles/default.ts",
    "content": "import { css } from '@emotion/react';\nimport { Theme } from '../../themes/default.js';\n\nexport interface StyleProps {\n  open: boolean | undefined;\n  fullWidth: boolean | undefined;\n}\n\nexport const style = ({\n  theme,\n  open,\n  fullWidth,\n}: StyleProps & { theme: Theme }) => css`\n  position: fixed;\n  top: 0px;\n  right: 0px;\n  bottom: 0px;\n  left: 0px;\n  z-index: 14;\n  display: ${open ? 'flex' : 'none'};\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n\n  > div:first-child {\n    position: fixed;\n    top: 0px;\n    right: 0px;\n    bottom: 0px;\n    left: 0px;\n    background-color: ${theme.base05};\n    opacity: 0.2;\n  }\n\n  > div:last-child {\n    display: flex;\n    flex-direction: column;\n    box-sizing: border-box;\n    position: relative;\n    z-index: 12;\n    max-height: 100%;\n    min-width: 320px;\n    ${fullWidth ? 'width: 99%;' : ''}\n    padding: 16px;\n    margin-bottom: 16px;\n    border: 1px outset ${theme.base01};\n    border-radius: 2px;\n    background-color: ${theme.base00};\n    box-shadow:\n      0 9px 46px 8px rgba(0, 0, 0, 0.14),\n      0 11px 15px -7px rgba(0, 0, 0, 0.12),\n      0 24px 38px 3px rgba(0, 0, 0, 0.2);\n\n    > div.mc-dialog--header {\n      display: flex;\n      align-items: center;\n      font-weight: 600;\n      margin: -17px -17px 0;\n      padding: 16px;\n      color: ${theme.light ? theme.base00 : theme.base07};\n      background-color: ${theme.light ? theme.base04 : theme.base02};\n      border: none;\n\n      > div:first-child {\n        flex-grow: 1;\n      }\n\n      > button {\n        box-sizing: border-box;\n        font-size: 1.5em;\n        line-height: 1;\n        font-weight: bold;\n        margin: 0px;\n        padding: 0px 5px;\n        cursor: pointer;\n        color: inherit;\n        background-color: transparent;\n        border: 0px;\n        -webkit-appearance: none;\n        outline: none;\n      }\n    }\n\n    > div.mc-dialog--body {\n      overflow: auto;\n\n      > form {\n        padding: 0;\n\n        > .form-group {\n          margin-bottom: 0;\n        }\n\n        > div > fieldset {\n          legend {\n            display: none;\n          }\n          #root__description {\n            margin-top: 0;\n          }\n        }\n\n        .mc-dialog--hidden {\n          display: none;\n        }\n      }\n    }\n\n    > div.mc-dialog--body:not(:empty) {\n      margin: 16px 0;\n    }\n\n    > div.mc-dialog--footer {\n      min-height: 45px;\n      box-sizing: border-box;\n      font-size: 12px;\n      display: flex;\n      align-items: center;\n      justify-content: flex-end;\n      margin: 0 -16px -16px;\n      padding: 2px 10px;\n      border-top: 1px solid ${theme.base03};\n\n      > button {\n        margin-left: 5px;\n      }\n    }\n  }\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Dialog/styles/index.ts",
    "content": "export { style as default } from './default.js';\nexport { style as material } from './material.js';\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Dialog/styles/material.ts",
    "content": "import { css } from '@emotion/react';\nimport { StyleProps } from './default.js';\nimport { Theme } from '../../themes/default.js';\n\nexport const style = ({\n  theme,\n  open,\n  fullWidth,\n}: StyleProps & { theme: Theme }) => css`\n  position: fixed;\n  top: 0px;\n  right: 0px;\n  bottom: 0px;\n  left: 0px;\n  z-index: 14;\n  display: ${open ? 'flex' : 'none'};\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n\n  > div:first-child {\n    position: fixed;\n    top: 0px;\n    right: 0px;\n    bottom: 0px;\n    left: 0px;\n    background-color: ${theme.base05};\n    opacity: 0.3;\n  }\n\n  > div:last-child {\n    display: flex;\n    flex-direction: column;\n    box-sizing: border-box;\n    position: relative;\n    z-index: 12;\n    max-height: 100%;\n    min-width: 320px;\n    ${fullWidth ? 'width: 99%;' : ''}\n    padding: 16px;\n    margin-bottom: 16px;\n    border: none;\n    background-color: ${theme.base00};\n    box-shadow:\n      0 9px 46px 8px rgba(0, 0, 0, 0.14),\n      0 11px 15px -7px rgba(0, 0, 0, 0.12),\n      0 24px 38px 3px rgba(0, 0, 0, 0.2);\n\n    > div.mc-dialog--header {\n      display: flex;\n      align-items: center;\n      font-size: 20px;\n      margin: -17px -17px 6px;\n      padding: 16px;\n      border: none;\n\n      > div:first-child {\n        flex-grow: 1;\n      }\n\n      > button {\n        box-sizing: border-box;\n        font-size: 1em;\n        line-height: 1;\n        font-weight: bold;\n        margin: 0px;\n        padding: 0px 5px;\n        cursor: pointer;\n        color: inherit;\n        background-color: transparent;\n        border: 0px;\n        -webkit-appearance: none;\n        outline: none;\n      }\n    }\n\n    > div.mc-dialog--body {\n      overflow: auto;\n\n      > form {\n        padding: 0;\n\n        > .form-group {\n          margin-bottom: 0;\n        }\n\n        > div > fieldset {\n          legend {\n            display: none;\n          }\n          #root__description {\n            margin-top: 0;\n          }\n        }\n\n        .mc-dialog--hidden {\n          display: none;\n        }\n      }\n    }\n\n    > div.mc-dialog--footer {\n      min-height: 45px;\n      box-sizing: border-box;\n      font-size: 12px;\n      display: flex;\n      align-items: center;\n      justify-content: flex-end;\n      margin: 16px -16px -16px;\n      padding: 2px 10px;\n\n      > button {\n        box-shadow: none;\n      }\n    }\n  }\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Editor/Editor.stories.tsx",
    "content": "import React from 'react';\nimport { Meta, StoryObj } from '@storybook/react-vite';\nimport Editor from './index.js';\nimport { default as WithTabsComponent, WithTabsProps } from './WithTabs.js';\n\nconst value = `\nvar themes = [];\n\nfunction getThemes() {\n  return themes;\n}\n`;\n\nconst meta: Meta = {\n  title: 'Editor',\n  component: Editor,\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof Editor>;\n\nexport const Default: Story = {\n  args: {\n    value,\n    lineNumbers: true,\n    foldGutter: true,\n    readOnly: false,\n    autofocus: true,\n  },\n  argTypes: {\n    autofocus: { control: { disable: true } },\n    onChange: { control: { disable: true } },\n  },\n};\n\nexport const WithTabs: StoryObj<WithTabsProps> = {\n  render: (args) => <WithTabsComponent {...args} />,\n  args: {\n    lineNumbers: true,\n    position: 'left',\n  },\n  argTypes: {\n    value: { control: { disable: true } },\n    readOnly: { control: { disable: true } },\n    theme: { control: { disable: true } },\n    foldGutter: { control: { disable: true } },\n    autofocus: { control: { disable: true } },\n    onChange: { control: { disable: true } },\n  } as any,\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Editor/Editor.tsx",
    "content": "import React from 'react';\nimport styled from '@emotion/styled';\nimport CodeMirror from '@uiw/react-codemirror';\nimport { createTheme } from '@uiw/codemirror-themes';\nimport { javascript } from '@codemirror/lang-javascript';\nimport type { ViewUpdate } from '@codemirror/view';\nimport { tags as t } from '@lezer/highlight';\nimport { useTheme } from '@emotion/react';\nimport type { ThemeFromProvider } from '../utils/theme.js';\nimport { defaultStyle } from './styles/index.js';\n\nimport '../../fonts/index.css';\n\nconst EditorContainer = styled.div(\n  '' as unknown as TemplateStringsArray,\n  defaultStyle,\n);\n\nexport interface EditorProps {\n  value?: string;\n  lineNumbers?: boolean;\n  readOnly?: boolean;\n  foldGutter?: boolean;\n  autofocus?: boolean;\n  onChange?: (value: string, viewUpdate: ViewUpdate) => void;\n}\n\nexport default function Editor({\n  value = '',\n  lineNumbers = true,\n  readOnly = false,\n  foldGutter = true,\n  autofocus = false,\n  onChange,\n}: EditorProps) {\n  const theme = useTheme() as ThemeFromProvider;\n\n  const myTheme =\n    theme.scheme === 'default' && theme.light\n      ? undefined\n      : createTheme({\n          theme: theme.light ? 'light' : 'dark',\n          settings: {\n            background: theme.base00,\n            foreground: theme.base04,\n            selection: theme.base01,\n            selectionMatch: 'transparent',\n            gutterBackground: theme.base01,\n            gutterForeground: theme.base05,\n            gutterBorder: 'transparent',\n            gutterActiveForeground: theme.base05,\n            lineHighlight: 'transparent',\n          },\n          styles: [\n            { tag: t.heading, color: theme.base05 },\n            { tag: t.quote, color: theme.base09 },\n            { tag: t.keyword, color: theme.base0F },\n            { tag: t.atom, color: theme.base0F },\n            { tag: t.number, color: theme.base0F },\n            { tag: t.definition(t.variableName), color: theme.base0D },\n            { tag: t.variableName, color: theme.base05 },\n            { tag: t.propertyName, color: theme.base0C },\n            { tag: t.operator, color: theme.base0E },\n            { tag: t.comment, color: theme.base05, fontStyle: 'italic' },\n            { tag: t.string, color: theme.base0B },\n            { tag: t.meta, color: theme.base0B },\n            { tag: t.tagName, color: theme.base02 },\n            { tag: t.attributeName, color: theme.base0C },\n            { tag: t.attributeName, color: theme.base02, cursor: 'pointer' },\n            {\n              tag: t.emphasis,\n              color: '#999',\n              textDecoration: 'underline',\n              textDecorationStyle: 'dotted',\n            },\n            { tag: t.strong, color: theme.base01 },\n            {\n              tag: t.invalid,\n              color: theme.base05,\n              borderBottom: `1px dotted ${theme.base08}`,\n            },\n          ],\n        });\n\n  return (\n    <EditorContainer>\n      <CodeMirror\n        value={value}\n        theme={myTheme}\n        extensions={[javascript()]}\n        onChange={onChange}\n        readOnly={readOnly}\n        autoFocus={autofocus}\n        basicSetup={{\n          lineNumbers,\n          foldGutter,\n        }}\n      />\n    </EditorContainer>\n  );\n}\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Editor/WithTabs.tsx",
    "content": "import React, { Component, ComponentType } from 'react';\nimport Editor from './index.js';\nimport Tabs from '../Tabs/index.js';\n\nconst value1 = `\n  const func1 = () => {}\n`;\n\nconst value2 = `\n  const func2 = () => {}\n`;\n\nexport interface WithTabsProps {\n  position: 'left' | 'right' | 'center';\n  lineNumbers: boolean;\n}\n\ninterface TabProps {\n  value: string;\n  lineNumbers: boolean;\n}\n\nexport default class WithTabs extends Component<WithTabsProps> {\n  state = {\n    selected: 'Function 1',\n  };\n\n  render() {\n    const { position, lineNumbers } = this.props;\n    return (\n      <Tabs<TabProps>\n        tabs={[\n          {\n            name: 'Function 1',\n            component: Editor as unknown as ComponentType<TabProps>,\n            selector: () => ({ value: value1, lineNumbers }),\n          },\n          {\n            name: 'Function 2',\n            component: Editor as unknown as ComponentType<TabProps>,\n            selector: () => ({ value: value2, lineNumbers }),\n          },\n        ]}\n        selected={this.state.selected}\n        onClick={(selected) => {\n          this.setState({ selected });\n        }}\n        position={position}\n      />\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Editor/index.ts",
    "content": "export { default } from './Editor.js';\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Editor/styles/index.ts",
    "content": "export const defaultStyle = `\n  height: 100%;\n  overflow: auto;\n\n  .cm-theme,\n  .cm-editor {\n    height: 100%;\n    line-height: 1.45em;\n  }\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Form/Form.stories.tsx",
    "content": "import { Meta, StoryObj } from '@storybook/react-vite';\nimport Form from './index.js';\nimport { schema, uiSchema, formData } from './schema.js';\n\nconst meta: Meta = {\n  title: 'Form',\n  component: Form,\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof Form>;\n\nexport const Default: Story = {\n  args: {\n    formData,\n    schema,\n    uiSchema,\n    submitText: 'Submit',\n  },\n  argTypes: {\n    children: { control: { disable: true } },\n    primaryButton: { control: { disable: true } },\n    noSubmit: { control: { disable: true } },\n    widgets: { control: { disable: true } },\n  },\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Form/Form.tsx",
    "content": "import React, { PureComponent, Component } from 'react';\nimport JSONSchemaForm, { FormProps } from '@rjsf/core';\nimport validator from '@rjsf/validator-ajv8';\nimport type { Base16Theme } from 'react-base16-styling';\nimport createStyledComponent from '../utils/createStyledComponent.js';\nimport styles from './styles/index.js';\nimport Button from '../Button/index.js';\nimport customWidgets from './widgets.js';\n\nconst FormContainer = createStyledComponent(styles, JSONSchemaForm);\n\nexport interface Props<T> extends Omit<FormProps<T>, 'validator'> {\n  children?: React.ReactNode;\n  submitText?: string;\n  primaryButton?: boolean;\n  noSubmit?: boolean;\n  theme?: Base16Theme;\n}\n\n/**\n * Wrapper around [`react-jsonschema-form`](https://github.com/rjsf-team/react-jsonschema-form) with custom widgets.\n */\nexport default class Form<T> extends (PureComponent || Component)<Props<T>> {\n  render() {\n    const { widgets, children, submitText, primaryButton, noSubmit, ...rest } =\n      this.props;\n    return (\n      <FormContainer\n        {...(rest as Props<unknown>)}\n        validator={validator}\n        widgets={{ ...customWidgets, ...widgets }}\n      >\n        {noSubmit ? (\n          <noscript />\n        ) : (\n          children || (\n            <Button\n              size=\"big\"\n              primary={primaryButton}\n              theme={rest.theme}\n              type=\"submit\"\n            >\n              {submitText || 'Submit'}\n            </Button>\n          )\n        )}\n      </FormContainer>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Form/index.ts",
    "content": "export { default } from './Form.js';\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Form/schema.ts",
    "content": "import { JSONSchema7 } from 'json-schema';\n\nexport const schema: JSONSchema7 = {\n  title: 'Example form',\n  description: 'A simple form example.',\n  type: 'object',\n  required: ['name'],\n  properties: {\n    name: {\n      type: 'string',\n      title: 'Full name',\n    },\n    age: {\n      type: 'integer',\n      title: 'Age',\n    },\n    bio: {\n      type: 'string',\n      title: 'Bio',\n    },\n    password: {\n      type: 'string',\n      title: 'Password',\n      minLength: 3,\n    },\n    multipleChoicesList: {\n      type: 'array',\n      title: 'A multiple choices list',\n      items: {\n        type: 'string',\n        enum: ['foo', 'bar', 'fuzz'],\n      },\n      uniqueItems: true,\n    },\n    numberEnum: {\n      type: 'number',\n      title: 'Number enum',\n      enum: [1, 2, 3],\n    },\n    numberEnumRadio: {\n      type: 'number',\n      title: 'Number enum',\n      enum: [1, 2, 3],\n    },\n    integerRange: {\n      title: 'Integer range',\n      type: 'integer',\n      minimum: 42,\n      maximum: 100,\n    },\n  },\n};\n\nexport const uiSchema = {\n  name: {\n    'ui:autofocus': true,\n  },\n  age: {\n    'ui:widget': 'updown',\n  },\n  bio: {\n    'ui:widget': 'textarea',\n  },\n  password: {\n    'ui:widget': 'password',\n    'ui:help': 'Hint: Make it strong!',\n  },\n  date: {\n    'ui:widget': 'alt-datetime',\n  },\n  multipleChoicesList: {\n    'ui:widget': 'checkboxes',\n  },\n  numberEnumRadio: {\n    'ui:widget': 'radio',\n    'ui:options': {\n      inline: true,\n    },\n  },\n  integerRange: {\n    'ui:widget': 'range',\n  },\n};\n\nexport const formData = {\n  name: 'Chuck Norris',\n  age: 75,\n  bio: 'Roundhouse kicking asses since 1940',\n  password: 'noneed',\n  integerRange: 52,\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Form/styles/index.ts",
    "content": "import { css } from '@emotion/react';\nimport { Theme } from '../../themes/default.js';\n\nexport default ({ theme }: { theme: Theme }) => css`\n  padding: 10px;\n  line-height: 1.846;\n  font-size: 14px;\n  color: ${theme.base06};\n\n  fieldset {\n    padding: 0;\n    margin: 0;\n    border: 0;\n    min-width: 0;\n  }\n\n  legend {\n    display: block;\n    width: 100%;\n    padding: 0;\n    font-size: 20px;\n    color: ${theme.base04};\n    border: 0;\n  }\n\n  label {\n    display: inline-block;\n    max-width: 100%;\n    font-weight: bold;\n  }\n\n  .form-control {\n    display: block;\n    box-sizing: border-box;\n    font-size: 12px;\n    width: 100%;\n    color: ${theme.base05};\n    background-color: transparent;\n    background-image: none;\n    line-height: ${theme.inputInternalHeight}px;\n    padding: 0 ${theme.inputPadding}px;\n    border-style: solid;\n    border-width: ${theme.inputBorderWidth}px;\n    border-color: ${theme.inputBorderColor};\n    border-radius: ${theme.inputBorderRadius}px;\n  }\n\n  .form-control:focus,\n  input.form-control:focus {\n    outline: 0;\n    ${theme.inputFocusedStyle}\n  }\n\n  .form-control[disabled],\n  .form-control[readonly],\n  fieldset[disabled] .form-control {\n    background-color: transparent;\n    opacity: 1;\n  }\n\n  .form-control[disabled],\n  fieldset[disabled] .form-control {\n    cursor: not-allowed;\n  }\n\n  textarea.form-control {\n    height: auto;\n  }\n\n  .form-group {\n    margin-bottom: 5px;\n  }\n\n  .radio,\n  .checkbox {\n    position: relative;\n    display: block;\n    margin-top: 10px;\n    margin-bottom: 10px;\n  }\n\n  .radio label,\n  .checkbox label {\n    min-height: 23px;\n    padding-left: 20px;\n    margin-bottom: 0;\n    font-weight: normal;\n    cursor: pointer;\n  }\n\n  .radio input[type='radio'],\n  .radio-inline input[type='radio'],\n  .checkbox input[type='checkbox'],\n  .checkbox-inline input[type='checkbox'] {\n    position: absolute;\n    margin-left: -20px;\n    margin-top: 4px \\\\9;\n  }\n\n  .radio + .radio,\n  .checkbox + .checkbox {\n    margin-top: -5px;\n  }\n\n  .radio-inline,\n  .checkbox-inline {\n    position: relative;\n    display: inline-block;\n    padding-left: 25px;\n    margin-bottom: 0;\n    vertical-align: middle;\n    font-weight: normal;\n    cursor: pointer;\n  }\n\n  .radio-inline + .radio-inline,\n  .checkbox-inline + .checkbox-inline {\n    margin-top: 0;\n    margin-left: 10px;\n  }\n\n  .radio label,\n  .radio-inline label,\n  .checkbox label,\n  .checkbox-inline label {\n    padding-left: 25px;\n  }\n\n  .radio input[type='radio'],\n  .radio-inline input[type='radio'],\n  .checkbox input[type='radio'],\n  .checkbox-inline input[type='radio'],\n  .radio input[type='checkbox'],\n  .radio-inline input[type='checkbox'],\n  .checkbox input[type='checkbox'],\n  .checkbox-inline input[type='checkbox'] {\n    margin-left: -25px;\n  }\n\n  input[type='radio'],\n  .radio input[type='radio'],\n  .radio-inline input[type='radio'] {\n    position: relative;\n    margin-top: 6px;\n    margin-right: 4px;\n    vertical-align: top;\n    border: none;\n    background-color: transparent;\n    appearance: none;\n    cursor: pointer;\n  }\n\n  input[type='radio']:focus,\n  .radio input[type='radio']:focus,\n  .radio-inline input[type='radio']:focus {\n    outline: none;\n  }\n\n  input[type='radio']:before,\n  .radio input[type='radio']:before,\n  .radio-inline input[type='radio']:before,\n  input[type='radio']:after,\n  .radio input[type='radio']:after,\n  .radio-inline input[type='radio']:after {\n    content: '';\n    display: block;\n    width: 18px;\n    height: 18px;\n    border-radius: 50%;\n    transition: 240ms;\n    box-sizing: border-box;\n  }\n\n  input[type='radio']:before,\n  .radio input[type='radio']:before,\n  .radio-inline input[type='radio']:before {\n    position: absolute;\n    left: 0;\n    top: -3px;\n    background-color: ${theme.base0D};\n    transform: scale(0);\n  }\n\n  input[type='radio']:after,\n  .radio input[type='radio']:after,\n  .radio-inline input[type='radio']:after {\n    position: relative;\n    top: -3px;\n    border: 2px solid ${theme.base03};\n  }\n\n  input[type='radio']:checked:before,\n  .radio input[type='radio']:checked:before,\n  .radio-inline input[type='radio']:checked:before {\n    transform: scale(0.5);\n  }\n\n  input[type='radio']:disabled:checked:before,\n  .radio input[type='radio']:disabled:checked:before,\n  .radio-inline input[type='radio']:disabled:checked:before {\n    background-color: ${theme.base03};\n  }\n\n  input[type='radio']:checked:after,\n  .radio input[type='radio']:checked:after,\n  .radio-inline input[type='radio']:checked:after {\n    border-color: ${theme.base0D};\n  }\n\n  input[type='radio']:disabled:after,\n  .radio input[type='radio']:disabled:after,\n  .radio-inline input[type='radio']:disabled:after,\n  input[type='radio']:disabled:checked:after,\n  .radio input[type='radio']:disabled:checked:after,\n  .radio-inline input[type='radio']:disabled:checked:after {\n    border-color: ${theme.base03};\n  }\n\n  input[type='checkbox'],\n  .checkbox input[type='checkbox'],\n  .checkbox-inline input[type='checkbox'] {\n    position: relative;\n    border: none;\n    margin-bottom: -4px;\n    appearance: none;\n    cursor: pointer;\n  }\n\n  input[type='checkbox']:focus,\n  .checkbox input[type='checkbox']:focus,\n  .checkbox-inline input[type='checkbox']:focus {\n    outline: none;\n  }\n\n  input[type='checkbox']:focus:after,\n  .checkbox input[type='checkbox']:focus:after,\n  .checkbox-inline input[type='checkbox']:focus:after {\n    border-color: ${theme.base0D};\n  }\n\n  input[type='checkbox']:after,\n  .checkbox input[type='checkbox']:after,\n  .checkbox-inline input[type='checkbox']:after {\n    content: '';\n    display: block;\n    width: 18px;\n    height: 18px;\n    margin-top: -2px;\n    margin-right: 5px;\n    border: 2px solid ${theme.base03};\n    border-radius: 4px;\n    transition: 240ms;\n    box-sizing: border-box;\n  }\n\n  input[type='checkbox']:checked:before,\n  .checkbox input[type='checkbox']:checked:before,\n  .checkbox-inline input[type='checkbox']:checked:before {\n    content: '';\n    position: absolute;\n    top: 0;\n    left: 6px;\n    display: table;\n    width: 6px;\n    height: 12px;\n    border: 2px solid #fff;\n    border-top-width: 0;\n    border-left-width: 0;\n    transform: rotate(45deg);\n    box-sizing: border-box;\n  }\n\n  input[type='checkbox']:checked:after,\n  .checkbox input[type='checkbox']:checked:after,\n  .checkbox-inline input[type='checkbox']:checked:after {\n    background-color: ${theme.base0D};\n    border-color: ${theme.base0D};\n  }\n\n  input[type='checkbox']:disabled:after,\n  .checkbox input[type='checkbox']:disabled:after,\n  .checkbox-inline input[type='checkbox']:disabled:after {\n    border-color: ${theme.base03};\n  }\n\n  input[type='checkbox']:disabled:checked:after,\n  .checkbox input[type='checkbox']:disabled:checked:after,\n  .checkbox-inline input[type='checkbox']:disabled:checked:after {\n    background-color: ${theme.base03};\n    border-color: transparent;\n  }\n\n  input[type='radio'][disabled],\n  input[type='checkbox'][disabled],\n  input[type='radio'].disabled,\n  input[type='checkbox'].disabled,\n  fieldset[disabled] input[type='radio'],\n  fieldset[disabled] input[type='checkbox'] {\n    cursor: not-allowed;\n  }\n\n  .radio-inline.disabled,\n  .checkbox-inline.disabled,\n  fieldset[disabled] .radio-inline,\n  fieldset[disabled] .checkbox-inline {\n    cursor: not-allowed;\n  }\n\n  .radio.disabled label,\n  .checkbox.disabled label,\n  fieldset[disabled] .radio label,\n  fieldset[disabled] .checkbox label {\n    cursor: not-allowed;\n  }\n\n  .has-error .help-block,\n  .has-error .control-label,\n  .has-error .radio,\n  .has-error .checkbox,\n  .has-error .radio-inline,\n  .has-error .checkbox-inline,\n  .has-error.radio label,\n  .has-error.checkbox label,\n  .has-error.radio-inline label,\n  .has-error.checkbox-inline label {\n    color: ${theme.base08};\n  }\n\n  .panel {\n    border: none;\n    border-radius: 2px;\n    box-shadow: 0 1px 4px ${theme.base03};\n    margin-bottom: 23px;\n  }\n\n  .panel-heading {\n    padding: 5px 15px;\n  }\n\n  .panel-title {\n    margin-top: 0;\n    margin-bottom: 0;\n    font-size: 15px;\n  }\n\n  .panel-danger {\n    box-shadow: 0 1px 4px ${theme.base08};\n  }\n\n  .panel-danger > .panel-heading {\n    color: ${theme.base00};\n    background-color: ${theme.base08};\n  }\n\n  .text-danger {\n    color: ${theme.base08};\n  }\n\n  .list-group {\n    padding: 0;\n    margin: 0;\n  }\n\n  .list-group-item {\n    position: relative;\n    display: block;\n    padding: 10px 15px;\n  }\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Form/widgets.tsx",
    "content": "import React from 'react';\nimport { FieldProps, Widget, WidgetProps } from '@rjsf/utils';\nimport Select from '../Select/index.js';\nimport Slider from '../Slider/index.js';\n\n/* eslint-disable react/prop-types */\nconst SelectWidget: Widget = ({\n  options,\n  onChange,\n  value,\n  onBlur,\n  defaultValue,\n  tabIndex,\n  onFocus,\n  'aria-invalid': ariaInvalid,\n  ...rest\n}) => (\n  <Select<{ label: string; value: string }>\n    options={options.enumOptions as { label: string; value: string }[]}\n    onChange={(option) => {\n      onChange(option?.value);\n    }}\n    value={(options.enumOptions as { label: string; value: string }[]).find(\n      (option) => option.value === value,\n    )}\n    {...rest}\n  />\n);\n\nconst RangeWidget: Widget = (({\n  schema,\n  disabled,\n  label, // eslint-disable-line\n  options, // eslint-disable-line\n  formContext, // eslint-disable-line\n  registry, // eslint-disable-line\n  ...rest\n}: WidgetProps & { registry: FieldProps['registry'] }) =>\n  (\n    <Slider\n      {...rest}\n      disabled={disabled}\n      min={schema.minimum}\n      max={schema.maximum}\n      withValue\n    />\n  ) as unknown) as Widget;\n\nexport default { SelectWidget, RangeWidget };\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Notification/Notification.stories.tsx",
    "content": "import React from 'react';\nimport styled from '@emotion/styled';\nimport { Meta, StoryObj } from '@storybook/react-vite';\nimport Notification from './index.js';\n\nconst Container = styled.div`\n  display: flex;\n  height: 100%;\n  width: 100%;\n  justify-content: center;\n  align-items: center;\n`;\n\nconst meta: Meta = {\n  title: 'Notification',\n  component: Notification,\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof Notification>;\n\nexport const Default: Story = {\n  render: (args) => (\n    <Container>\n      <Notification {...args} />\n    </Container>\n  ),\n  args: {\n    type: 'warning',\n    children: 'Hello Notification',\n  },\n  argTypes: {\n    onClose: { control: { disable: true } },\n    theme: { control: { disable: true } },\n  },\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Notification/Notification.tsx",
    "content": "import React, { Component } from 'react';\nimport { MdClose } from 'react-icons/md';\nimport { MdWarning } from 'react-icons/md';\nimport { MdError } from 'react-icons/md';\nimport { MdCheckCircle } from 'react-icons/md';\nimport type { Base16Theme } from 'react-base16-styling';\nimport createStyledComponent from '../utils/createStyledComponent.js';\nimport styles from './styles/index.js';\n\nconst NotificationWrapper = createStyledComponent(styles);\n\nexport type Type = 'info' | 'success' | 'warning' | 'error';\n\nexport interface NotificationProps {\n  children?: React.ReactNode;\n  type: Type;\n  onClose?: React.MouseEventHandler<HTMLButtonElement>;\n  theme?: Base16Theme;\n}\n\nexport default class Notification extends Component<NotificationProps> {\n  shouldComponentUpdate(nextProps: NotificationProps) {\n    return (\n      nextProps.children !== this.props.children ||\n      nextProps.type !== this.props.type\n    );\n  }\n\n  getIcon = () => {\n    switch (this.props.type) {\n      case 'warning':\n        return <MdWarning />;\n      case 'error':\n        return <MdError />;\n      case 'success':\n        return <MdCheckCircle />;\n      default:\n        return null;\n    }\n  };\n\n  render() {\n    return (\n      <NotificationWrapper type={this.props.type} theme={this.props.theme}>\n        {this.getIcon()}\n        <span>{this.props.children}</span>\n        {this.props.onClose && (\n          <button onClick={this.props.onClose}>\n            <MdClose />\n          </button>\n        )}\n      </NotificationWrapper>\n    );\n  }\n\n  static defaultProps = {\n    type: 'info',\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Notification/index.ts",
    "content": "export { default } from './Notification.js';\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Notification/styles/index.ts",
    "content": "import { css } from '@emotion/react';\nimport { Theme } from '../../themes/default.js';\nimport { Type } from '../Notification.js';\n\nconst getBackground = (theme: Theme, type: Type) => {\n  switch (type) {\n    case 'success':\n      return `background-color: ${theme.base0B};`;\n    case 'warning':\n      return `background-color: ${theme.base0A};`;\n    case 'error':\n      return `background-color: ${theme.base08};`;\n    default:\n      return `background-color: ${theme.base0D};`;\n  }\n};\n\ninterface StyleProps {\n  type: Type;\n}\n\nexport default ({ theme, type }: StyleProps & { theme: Theme }) => css`\n  display: flex;\n  align-items: flex-start;\n  flex-shrink: 0;\n  box-sizing: border-box;\n  box-shadow: inset ${theme.base05} 0 0 1px;\n  font-size: 1.1em;\n  padding: 7px;\n  width: 100%;\n  color: ${theme.base01};\n  ${getBackground(theme, type)}\n\n  & > svg:first-child {\n    font-size: 1.4em;\n    opacity: 0.5;\n  }\n\n  & > span {\n    width: 100%;\n    text-align: center;\n    padding: 0.1em;\n  }\n\n  & > button {\n    cursor: pointer;\n    float: right;\n    font-size: 1.1em;\n    border: 1px solid transparent;\n    background: transparent;\n    padding: 0.1em;\n    line-height: 0;\n    outline: none;\n    color: inherit;\n    opacity: 0.8;\n  }\n\n  & > button:hover,\n  & > button:active {\n    opacity: 1;\n  }\n\n  & > button:focus {\n    border: 1px solid ${theme.base03};\n  }\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/SegmentedControl/SegmentedControl.stories.tsx",
    "content": "import React from 'react';\nimport styled from '@emotion/styled';\nimport { Meta, StoryObj } from '@storybook/react-vite';\nimport SegmentedControl from './index.js';\n\nconst Container = styled.div`\n  display: flex;\n  height: 100%;\n  width: 100%;\n  justify-content: center;\n  align-items: center;\n`;\n\nconst meta: Meta = {\n  title: 'SegmentedControl',\n  component: SegmentedControl,\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof SegmentedControl>;\n\nexport const Default: Story = {\n  render: ({ values, ...args }) => (\n    <Container>\n      <SegmentedControl values={['Button1', 'Button2', 'Button3']} {...args} />\n    </Container>\n  ),\n  args: {\n    selected: 'Button1',\n    disabled: false,\n  },\n  argTypes: {\n    values: { control: { disable: true } },\n    onClick: { control: { disable: true } },\n    theme: { control: { disable: true } },\n  },\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/SegmentedControl/SegmentedControl.tsx",
    "content": "import React, { Component } from 'react';\nimport type { Base16Theme } from 'react-base16-styling';\nimport createStyledComponent from '../utils/createStyledComponent.js';\nimport styles from './styles/index.js';\n\nconst SegmentedWrapper = createStyledComponent(styles);\n\nexport interface SegmentedControlProps {\n  values: string[];\n  selected?: string;\n  onClick: (value: string) => void;\n  disabled?: boolean;\n  theme?: Base16Theme;\n}\n\nexport default class SegmentedControl extends Component<SegmentedControlProps> {\n  shouldComponentUpdate(nextProps: SegmentedControlProps) {\n    return (\n      nextProps.disabled !== this.props.disabled ||\n      nextProps.selected !== this.props.selected\n    );\n  }\n\n  onClick: React.MouseEventHandler<HTMLButtonElement> = (e) => {\n    this.props.onClick(e.currentTarget.value);\n  };\n\n  onMouseUp: React.MouseEventHandler<HTMLButtonElement> = (e) => {\n    e.currentTarget.blur();\n  };\n\n  render() {\n    const { values, selected } = this.props;\n    return (\n      <SegmentedWrapper disabled={this.props.disabled} theme={this.props.theme}>\n        {values.map((button) => (\n          <button\n            key={button}\n            value={button}\n            data-selected={button === selected ? true : undefined}\n            onMouseUp={this.onMouseUp}\n            onClick={this.onClick}\n          >\n            {button}\n          </button>\n        ))}\n      </SegmentedWrapper>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/SegmentedControl/index.tsx",
    "content": "export { default } from './SegmentedControl.js';\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/SegmentedControl/styles/index.ts",
    "content": "import { css } from '@emotion/react';\nimport color from '../../utils/color.js';\nimport { Theme } from '../../themes/default.js';\n\ninterface StyleProps {\n  disabled: boolean | undefined;\n}\n\nexport default ({ theme, disabled }: StyleProps & { theme: Theme }) => css`\n  display: flex;\n  flex-shrink: 0;\n\n  > [data-selected],\n  > [data-selected]:hover {\n    background-color: ${theme.base04};\n    color: ${theme.base00};\n  }\n\n  > button {\n    outline: none;\n    box-sizing: border-box;\n    flex-shrink: 0;\n    -webkit-font-smoothing: antialiased;\n    min-height: 30px;\n    border: 1px solid ${color(theme.base03, 'alpha', 0.4)};\n    border-left-width: 0;\n    padding: 5px 10px;\n    ${disabled\n      ? `\n    cursor: not-allowed;\n    opacity: 0.6;\n    `\n      : `\n    cursor: pointer;\n    color: ${theme.base05};\n    background-color: ${theme.base01};\n\n    &:hover, &:focus {\n      background-color: ${theme.base02};\n      color: ${theme.base07};\n    }\n    `}\n\n    &:first-child {\n      border-top-left-radius: 3px;\n      border-bottom-left-radius: 3px;\n      border-left-width: 1px;\n    }\n\n    &:last-child {\n      border-top-right-radius: 3px;\n      border-bottom-right-radius: 3px;\n    }\n  }\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Select/Select.stories.tsx",
    "content": "import React from 'react';\nimport styled from '@emotion/styled';\nimport Select from './index.js';\nimport { options } from './options.js';\nimport { Meta, StoryObj } from '@storybook/react-vite';\n\nconst Container = styled.div`\n  display: flex;\n  height: 100%;\n  width: 100%;\n  justify-content: center;\n  align-items: center;\n\n  > div {\n    width: 90%;\n  }\n`;\n\nconst meta: Meta = {\n  title: 'Select',\n  component: Select,\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof Select>;\n\nexport const Default: Story = {\n  render: ({ value, ...args }) => (\n    <Container>\n      <Select\n        options={options}\n        value={options.filter((option) => option.value === value)}\n        {...args}\n      />\n    </Container>\n  ),\n  args: {\n    value: 'one',\n    maxMenuHeight: 300,\n    isClearable: false,\n    isDisabled: false,\n    isLoading: false,\n    isMulti: false,\n    isSearchable: true,\n    menuPlacement: 'bottom',\n  },\n  argTypes: {\n    onChange: {\n      action: 'selected',\n    },\n  },\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Select/Select.tsx",
    "content": "import React, { PureComponent, Component, ReactElement } from 'react';\nimport ReactSelect, {\n  GroupBase,\n  Props as ReactSelectProps,\n} from 'react-select';\nimport createThemedComponent from '../utils/createThemedComponent.js';\nimport { Theme } from '../themes/default.js';\n\nexport interface SelectProps<\n  Option,\n  IsMulti extends boolean = false,\n  Group extends GroupBase<Option> = GroupBase<Option>,\n> extends Omit<ReactSelectProps<Option, IsMulti, Group>, 'theme'> {\n  theme: Theme;\n}\n\n/**\n * Wrapper around [React Select](https://github.com/JedWatson/react-select).\n */\nexport class Select<\n  Option,\n  IsMulti extends boolean = false,\n  Group extends GroupBase<Option> = GroupBase<Option>,\n> extends (PureComponent || Component)<SelectProps<Option, IsMulti, Group>> {\n  render() {\n    return (\n      <ReactSelect\n        {...this.props}\n        theme={(theme) => ({\n          ...theme,\n          borderRadius: 0,\n          colors: {\n            ...theme.colors,\n\n            primary: this.props.theme.base05,\n            primary50: this.props.theme.base03,\n            primary25: this.props.theme.base01,\n\n            dangerLight: this.props.theme.base03,\n            danger: this.props.theme.base07,\n\n            neutral0: this.props.theme.base00,\n            neutral5: this.props.theme.base01,\n            neutral10: this.props.theme.base02,\n            neutral20: this.props.theme.base03,\n            neutral30: this.props.theme.base04,\n            neutral40: this.props.theme.base05,\n            neutral60: this.props.theme.base06,\n            neutral80: this.props.theme.base07,\n          },\n          spacing: {\n            ...theme.spacing,\n            baseUnit: 2,\n            controlHeight: this.props.theme.inputHeight,\n          },\n        })}\n        styles={{\n          container: (base) => ({\n            ...base,\n            flexGrow: 1,\n          }),\n          control: (base, props) => ({\n            ...base,\n            backgroundColor: props.isFocused\n              ? props.theme.colors.neutral10\n              : props.theme.colors.neutral5,\n            borderColor: props.theme.colors.neutral10,\n\n            '&:hover': {\n              backgroundColor: props.theme.colors.neutral10,\n              borderColor: props.theme.colors.neutral10,\n            },\n          }),\n          menu: (base) => ({\n            ...base,\n            zIndex: 10,\n          }),\n        }}\n      />\n    );\n  }\n}\n\nexport interface ExternalSelectProps<\n  Option,\n  IsMulti extends boolean = false,\n  Group extends GroupBase<Option> = GroupBase<Option>,\n> extends Omit<ReactSelectProps<Option, IsMulti, Group>, 'theme'> {\n  theme?: Theme;\n}\n\ntype SelectComponent = <\n  Option,\n  IsMulti extends boolean = false,\n  Group extends GroupBase<Option> = GroupBase<Option>,\n>(\n  props: ExternalSelectProps<Option, IsMulti, Group>,\n) => ReactElement;\n\nexport default createThemedComponent(Select) as SelectComponent & {\n  theme?: Theme;\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Select/index.ts",
    "content": "export { default } from './Select.js';\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Select/options.ts",
    "content": "export const options = [\n  { value: 'one', label: 'One' },\n  { value: 'two', label: 'Two' },\n  { value: 'hundred', label: 'One hundred' },\n];\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Slider/Slider.stories.tsx",
    "content": "import React from 'react';\nimport styled from '@emotion/styled';\nimport { Meta, StoryObj } from '@storybook/react-vite';\nimport Slider from './index.js';\n\nconst Container = styled.div`\n  display: flex;\n  height: 100%;\n  width: 100%;\n  justify-content: center;\n  align-items: center;\n`;\n\nconst meta: Meta = {\n  title: 'Slider',\n  component: Slider,\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof Slider>;\n\nexport const Default: Story = {\n  render: (args) => (\n    <Container>\n      <Slider {...args} />\n    </Container>\n  ),\n  args: {\n    value: 0,\n    min: 0,\n    max: 100,\n    label: 'Slider label',\n    sublabel: '(sublabel}',\n    withValue: false,\n    disabled: false,\n  },\n  argTypes: {\n    onChange: { control: { disable: true } },\n    theme: { control: { disable: true } },\n  },\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Slider/Slider.tsx",
    "content": "import React, { Component } from 'react';\nimport type { Base16Theme } from 'react-base16-styling';\nimport createStyledComponent from '../utils/createStyledComponent.js';\nimport * as styles from './styles/index.js';\nimport { containerStyle } from './styles/common.js';\n\nconst SliderWrapper = createStyledComponent(styles);\nconst ContainerWithValue = createStyledComponent(containerStyle);\n\nexport interface SliderProps {\n  value: number;\n  min: number;\n  max: number;\n  label?: string;\n  sublabel?: string;\n  withValue?: boolean;\n  disabled?: boolean;\n  onChange: (value: number) => void;\n  theme?: Base16Theme;\n}\n\nexport default class Slider extends Component<SliderProps> {\n  shouldComponentUpdate(nextProps: SliderProps) {\n    return (\n      nextProps.label !== this.props.label ||\n      nextProps.value !== this.props.value ||\n      nextProps.max !== this.props.max ||\n      nextProps.min !== this.props.min ||\n      nextProps.withValue !== this.props.withValue ||\n      nextProps.disabled !== this.props.disabled\n    );\n  }\n\n  onChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {\n    this.props.onChange(parseFloat(e.target.value));\n  };\n\n  render() {\n    const { label, sublabel, withValue, theme, ...rest } = this.props;\n    const { value, max, min, disabled } = rest;\n    const absMax = max - min;\n    const percent = ((value - min) / absMax) * 100;\n    const slider = <input {...rest} onChange={this.onChange} type=\"range\" />;\n\n    return (\n      <SliderWrapper\n        percent={percent}\n        disabled={disabled || absMax === 0}\n        withLabel={!!label}\n        theme={theme}\n      >\n        {label && (\n          <label>\n            {label} {sublabel && <span>{sublabel}</span>}\n          </label>\n        )}\n        {!withValue ? (\n          slider\n        ) : (\n          <ContainerWithValue theme={theme}>\n            {slider}\n            <div>{value}</div>\n          </ContainerWithValue>\n        )}\n      </SliderWrapper>\n    );\n  }\n\n  static defaultProps = { value: 0, min: 0, max: 100 };\n}\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Slider/index.ts",
    "content": "export { default } from './Slider.js';\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Slider/styles/common.ts",
    "content": "import { css } from '@emotion/react';\nimport { Theme } from '../../themes/default.js';\n\nexport const containerStyle = ({ theme }: { theme: Theme }) => css`\n  display: flex;\n  align-items: center;\n\n  div {\n    margin-left: 4px;\n    padding: 0.3em 0.5em;\n    border: ${theme.inputBorderWidth}px solid ${theme.inputBorderColor};\n    border-radius: ${theme.inputBorderRadius}px;\n    background-color: ${theme.base00};\n    opacity: 0.7;\n  }\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Slider/styles/default.ts",
    "content": "/*\nBased on:\n http://codepen.io/thebabydino/pen/NPYBJQ\n http://codepen.io/thebabydino/pen/zxRzPw\n http://codepen.io/thebabydino/pen/dPqrrY\n http://codepen.io/thebabydino/pen/YPOPxr\n*/\n\nimport { css } from '@emotion/react';\nimport { prefixSelectors } from '../../utils/autoPrefix.js';\nimport { Theme } from '../../themes/default.js';\n\nexport interface StyleProps {\n  percent: number;\n  disabled: boolean;\n  withLabel: boolean;\n}\n\nexport const style = ({\n  theme,\n  percent,\n  disabled,\n  withLabel,\n}: StyleProps & { theme: Theme }) => css`\n  display: block;\n  width: 100%;\n  position: relative;\n  padding: ${withLabel ? '1.2em 0' : '0'};\n\n  label {\n    position: absolute;\n    display: block;\n    font-size: 11px;\n    padding: 0 10px;\n    top: 0.3em;\n    width: 100%;\n    color: ${theme.base06};\n\n    > span {\n      color: ${theme.base04};\n    }\n  }\n\n  input {\n    opacity: ${disabled ? '0.5' : '1'};\n    outline: none;\n    margin: 0;\n    box-sizing: border-box;\n    display: block;\n    appearance: none;\n    border-top: solid 0.5em transparent;\n    border-bottom: solid 0.5em transparent;\n    padding: 0.5em;\n    width: 100%;\n    height: 2.5em;\n    border-radius: 0.8em/1.1em;\n    font-size: 1em;\n    cursor: pointer;\n    background:\n      linear-gradient(${theme.base02}, ${theme.base00}) padding-box,\n      50% 50% border-box;\n    background-size: 100% 100%;\n  }\n\n  ${prefixSelectors(\n    'input',\n    ['webkit-slider-runnable-track', 'moz-range-track', 'ms-track'],\n    `{\n    position: relative;\n    height: 0.8em;\n    border-radius: 0.5em;\n    box-shadow: 0 0 .125em ${theme.base04};\n    background: linear-gradient(${theme.base01}, ${theme.base02} 40%, ${theme.base01})\n      no-repeat ${theme.base00};\n    background-size: ${percent}% 100%;\n  }`,\n  )}\n\n  ${prefixSelectors(\n    'input',\n    ['webkit-slider-thumb', 'moz-range-thumb', 'ms-thumb'],\n    `{\n    position: relative;\n    appearance: none;\n    cursor: ew-resize;\n    margin-top: -0.36em;\n    background: ${theme.light ? theme.base00 : theme.base06};\n    border: solid 1px ${theme.base03};\n    box-shadow: 0 1px .125em ${theme.base03};\n    width: 1.5em;\n    height: 1.5em;\n    border-radius: 50%;\n    cursor: pointer;\n  }`,\n  )}\n\n ${prefixSelectors(\n    'input:focus:not(:active)',\n    ['webkit-slider-thumb', 'moz-range-thumb', 'ms-thumb'],\n    `{\n    box-shadow: 0 0 1px 2px ${theme.base0D};\n  }`,\n  )}\n\n  input::-moz-focus-outer {\n    border: 0;\n  }\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Slider/styles/index.ts",
    "content": "export { style as default } from './default.js';\nexport { style as material } from './material.js';\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Slider/styles/material.ts",
    "content": "import { css } from '@emotion/react';\nimport { prefixSelectors } from '../../utils/autoPrefix.js';\nimport color from '../../utils/color.js';\nimport { animationCurve } from '../../utils/animations.js';\nimport { StyleProps } from './default.js';\nimport { Theme } from '../../themes/default.js';\n\nexport const style = ({\n  theme,\n  percent,\n  disabled,\n  withLabel,\n}: StyleProps & { theme: Theme }) => css`\n  display: block;\n  width: 100%;\n  position: relative;\n  z-index: 1;\n  padding: ${withLabel ? '2em 0' : '0'};\n\n  label {\n    position: absolute;\n    display: block;\n    font-size: 11px;\n    padding: 0.3em 0.5em;\n    top: 0;\n    width: 100%;\n    color: ${theme.base06};\n\n    > span {\n      color: ${theme.base04};\n    }\n  }\n\n  input {\n    opacity: ${disabled ? '0.7' : '1'};\n    outline: none;\n    box-sizing: border-box;\n    display: block;\n    width: 100%;\n    margin: 0;\n    cursor: pointer;\n    color: inherit;\n    background-color: ${theme.base02};\n    background-image: linear-gradient(\n      90deg,\n      currentcolor,\n      currentcolor ${percent}%,\n      transparent ${percent}%\n    );\n    background-clip: content-box;\n    height: 0.5em;\n    border-radius: 999px;\n    appearance: none;\n    font-size: 1em;\n  }\n\n  ${prefixSelectors(\n    'input',\n    ['webkit-slider-thumb', 'moz-range-thumb', 'ms-thumb'],\n    `{\n    width: 1.5em;\n    height: 1.5em;\n    background-image: none;\n    background-color: ${percent === 0 ? theme.base00 : 'currentcolor'};\n    border: ${percent === 0 ? `5px solid ${theme.base03}` : 'none'};;\n    border-radius: 50%;\n    appearance: none;\n    transition: transform 0.18s ${animationCurve},\n      border 0.18s ${animationCurve},\n      box-shadow 0.18s ${animationCurve},\n      background 0.28s ${animationCurve};\n  }`,\n  )}\n\n  ${prefixSelectors(\n    'input:focus:not(:active)',\n    ['webkit-slider-thumb', 'moz-range-thumb', 'ms-thumb'],\n    `{\n    box-shadow: 0 0 0 8px ${color(theme.base0D, 'alpha', 0.5)};\n    transform: scale(1.2);\n  }`,\n  )}\n\n  input::-moz-focus-outer {\n    border: 0;\n  }\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Tabs/Tabs.stories.tsx",
    "content": "import React from 'react';\nimport styled from '@emotion/styled';\nimport { Meta, StoryObj } from '@storybook/react-vite';\nimport Tabs from './index.js';\nimport { tabs, simple10Tabs } from './data.js';\nimport { TabsProps } from './Tabs.js';\n\nconst Container = styled.div`\n  display: flex;\n  height: 100%;\n  width: 100%;\n  justify-content: center;\n  align-items: center;\n`;\n\nconst meta: Meta = {\n  title: 'Tabs',\n  component: Tabs,\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof Tabs>;\n\nexport const Default: Story = {\n  render: (args) => (\n    <Container>\n      <Tabs {...args} />\n    </Container>\n  ),\n  args: {\n    tabs: simple10Tabs,\n    selected: '2',\n    main: true,\n    collapsible: true,\n    position: 'left',\n  },\n  argTypes: {\n    tabs: { control: { disable: true } },\n    onClick: { control: { disable: true } },\n  },\n};\n\nexport const WithContext: StoryObj<TabsProps<{ selected: string }>> = {\n  render: (args) => (\n    <Container>\n      <Tabs {...args} />\n    </Container>\n  ),\n  args: {\n    tabs,\n    selected: 'Tab2',\n    main: false,\n    collapsible: false,\n    position: 'left',\n  },\n  argTypes: {\n    tabs: { control: { disable: true } },\n    onClick: { control: { disable: true } },\n  },\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Tabs/Tabs.tsx",
    "content": "import React, { Component } from 'react';\nimport TabsHeader, { Tab } from './TabsHeader.js';\nimport { TabsContainer } from './styles/common.js';\n\nexport type Position = 'left' | 'right' | 'center';\n\nexport interface TabsProps<P> {\n  tabs: Tab<P>[];\n  selected?: string;\n  main?: boolean;\n  onClick: (value: string) => void;\n  collapsible?: boolean;\n  position: Position;\n}\n\nexport default class Tabs<P extends object> extends Component<TabsProps<P>> {\n  SelectedComponent?: React.ComponentType<P>;\n  selector?: () => P;\n\n  onMouseUp: React.MouseEventHandler<HTMLButtonElement> = (e) => {\n    e.currentTarget.blur();\n  };\n\n  onClick: React.MouseEventHandler<HTMLButtonElement> = (e) => {\n    this.props.onClick(e.currentTarget.value);\n  };\n\n  renderTabs() {\n    const tabs = this.props.tabs;\n    const selected = this.props.selected;\n\n    return tabs.map((tab, i) => {\n      let isSelected;\n      const value = typeof tab.value !== 'undefined' ? tab.value : tab.name;\n      if (value === selected) {\n        isSelected = true;\n        if (tab.component) {\n          this.SelectedComponent = tab.component;\n          if (tab.selector) this.selector = () => tab.selector!(tab);\n        }\n      }\n      return (\n        <button\n          key={i}\n          value={value}\n          data-selected={isSelected}\n          onMouseUp={this.onMouseUp}\n          onClick={this.onClick}\n        >\n          {tab.name}\n        </button>\n      );\n    });\n  }\n\n  render() {\n    const tabsHeader = (\n      <TabsHeader\n        tabs={this.renderTabs()}\n        items={this.props.tabs}\n        main={this.props.main}\n        collapsible={this.props.collapsible}\n        onClick={this.props.onClick}\n        selected={this.props.selected}\n        position={this.props.position}\n      />\n    );\n\n    if (!this.SelectedComponent) {\n      return (\n        <TabsContainer position={this.props.position}>\n          {tabsHeader}\n        </TabsContainer>\n      );\n    }\n\n    return (\n      <TabsContainer position={this.props.position}>\n        {tabsHeader}\n        <div>\n          <this.SelectedComponent {...(this.selector! && this.selector())} />\n        </div>\n      </TabsContainer>\n    );\n  }\n\n  static defaultProps = { position: 'left' };\n}\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Tabs/TabsHeader.tsx",
    "content": "import React, { Component } from 'react';\nimport observeResize from 'simple-element-resize-detector';\nimport { FaAngleDoubleRight } from 'react-icons/fa';\nimport ContextMenu from '../ContextMenu/index.js';\nimport createStyledComponent from '../utils/createStyledComponent.js';\nimport * as styles from './styles/index.js';\n\nconst TabsWrapper = createStyledComponent(styles);\n\nexport type ReactButtonElement = React.ReactElement<\n  React.JSX.IntrinsicElements['button'],\n  'button'\n>;\n\nexport interface Tab<P> {\n  name: string;\n  value?: string;\n  component?: React.ComponentType<P>;\n  selector?: (tab: this) => P;\n}\n\ninterface Props<P> {\n  tabs: ReactButtonElement[];\n  items: Tab<P>[];\n  main: boolean | undefined;\n  onClick: (value: string) => void;\n  position: 'left' | 'right' | 'center';\n  collapsible: boolean | undefined;\n  selected: string | undefined;\n}\n\ninterface State {\n  visibleTabs: ReactButtonElement[];\n  hiddenTabs: ReactButtonElement[];\n  subMenuOpened: boolean;\n  contextMenu: { top: number; left: number } | undefined;\n}\n\nexport default class TabsHeader<P> extends Component<Props<P>, State> {\n  state: State = {\n    visibleTabs: this.props.tabs.slice(),\n    hiddenTabs: [],\n    subMenuOpened: false,\n    contextMenu: undefined,\n  };\n\n  iconWidth = 0;\n  hiddenTabsWidth: number[] = [];\n  tabsWrapperRef?: HTMLDivElement | null;\n  tabsRef?: HTMLDivElement | null;\n  resizeDetector?: HTMLIFrameElement;\n\n  UNSAFE_componentWillReceiveProps(nextProps: Props<P>) {\n    if (\n      nextProps.tabs !== this.props.tabs ||\n      nextProps.selected !== this.props.selected ||\n      nextProps.collapsible !== this.props.collapsible\n    ) {\n      this.setState({ hiddenTabs: [], visibleTabs: nextProps.tabs.slice() });\n    }\n  }\n\n  componentDidMount() {\n    if (this.props.collapsible) {\n      this.collapse();\n      this.enableResizeEvents();\n    }\n  }\n\n  componentDidUpdate(prevProps: Props<P>) {\n    const { collapsible } = this.props;\n    if (!collapsible) {\n      if (prevProps.collapsible !== collapsible) this.disableResizeEvents();\n      return;\n    }\n\n    let shouldCollapse = false;\n    if (this.iconWidth === 0) {\n      const tabButtons = this.tabsRef!.children;\n      if (\n        (this.tabsRef!.children[tabButtons.length - 1] as HTMLButtonElement)\n          .value === 'expandIcon'\n      ) {\n        this.iconWidth =\n          tabButtons[tabButtons.length - 1].getBoundingClientRect().width;\n        shouldCollapse = true;\n      }\n    } else if (this.state.hiddenTabs.length === 0) {\n      this.iconWidth = 0;\n    }\n\n    if (prevProps.collapsible !== collapsible) {\n      this.enableResizeEvents();\n      shouldCollapse = true;\n    }\n\n    if (shouldCollapse || this.props.selected !== prevProps.selected) {\n      this.collapse();\n    }\n  }\n\n  componentWillUnmount() {\n    if (this.props.collapsible) {\n      this.disableResizeEvents();\n    }\n  }\n\n  enableResizeEvents() {\n    this.resizeDetector = observeResize(this.tabsWrapperRef!, this.collapse);\n    window.addEventListener('mousedown', this.hideSubmenu);\n  }\n\n  disableResizeEvents() {\n    this.resizeDetector!.remove();\n    window.removeEventListener('mousedown', this.hideSubmenu);\n  }\n\n  collapse = () => {\n    if (this.state.subMenuOpened) this.hideSubmenu();\n\n    const { selected, tabs } = this.props;\n    const tabsWrapperRef = this.tabsWrapperRef;\n    const tabsRef = this.tabsRef;\n    const tabButtons = this.tabsRef!.children;\n    const visibleTabs = this.state.visibleTabs;\n    const hiddenTabs = this.state.hiddenTabs;\n    let tabsWrapperRight = tabsWrapperRef!.getBoundingClientRect().right;\n    if (!tabsWrapperRight) return; // tabs are hidden\n\n    const tabsRefRight = tabsRef!.getBoundingClientRect().right;\n    let i = visibleTabs.length - 1;\n    let hiddenTab;\n\n    if (tabsRefRight >= tabsWrapperRight - this.iconWidth) {\n      if (\n        this.props.position === 'right' &&\n        hiddenTabs.length > 0 &&\n        tabsRef!.getBoundingClientRect().width + this.hiddenTabsWidth[0] <\n          tabsWrapperRef!.getBoundingClientRect().width\n      ) {\n        while (\n          i < tabs.length - 1 &&\n          tabsRef!.getBoundingClientRect().width + this.hiddenTabsWidth[0] <\n            tabsWrapperRef!.getBoundingClientRect().width\n        ) {\n          hiddenTab = hiddenTabs.shift()!;\n          visibleTabs.splice(Number(hiddenTab.key), 0, hiddenTab);\n          i++;\n        }\n      } else {\n        while (\n          i > 0 &&\n          tabButtons[i] &&\n          tabButtons[i].getBoundingClientRect().right >=\n            tabsWrapperRight - this.iconWidth\n        ) {\n          if ((tabButtons[i] as HTMLButtonElement).value !== selected) {\n            hiddenTabs.unshift(...visibleTabs.splice(i, 1));\n            this.hiddenTabsWidth.unshift(\n              tabButtons[i].getBoundingClientRect().width,\n            );\n          } else {\n            tabsWrapperRight -= tabButtons[i].getBoundingClientRect().width;\n          }\n          i--;\n        }\n      }\n    } else {\n      while (\n        i < tabs.length - 1 &&\n        tabButtons[i] &&\n        tabButtons[i].getBoundingClientRect().right + this.hiddenTabsWidth[0] <\n          tabsWrapperRight - this.iconWidth\n      ) {\n        hiddenTab = hiddenTabs.shift()!;\n        visibleTabs.splice(Number(hiddenTab.key), 0, hiddenTab);\n        this.hiddenTabsWidth.shift();\n        i++;\n      }\n    }\n    this.setState({ visibleTabs, hiddenTabs });\n  };\n\n  hideSubmenu = () => {\n    this.setState({ subMenuOpened: false, contextMenu: undefined });\n  };\n\n  getTabsWrapperRef: React.RefCallback<HTMLDivElement> = (node) => {\n    this.tabsWrapperRef = node;\n  };\n\n  getTabsRef: React.RefCallback<HTMLDivElement> = (node) => {\n    this.tabsRef = node;\n  };\n\n  expandMenu: React.MouseEventHandler = (e) => {\n    const rect = e.currentTarget.children[0].getBoundingClientRect();\n    this.setState({\n      contextMenu: {\n        top: rect.top + 10,\n        left: rect.left,\n      },\n      subMenuOpened: true,\n    });\n  };\n\n  render() {\n    const { visibleTabs, hiddenTabs, contextMenu } = this.state;\n    return (\n      <TabsWrapper\n        ref={this.getTabsWrapperRef}\n        main={this.props.main}\n        position={this.props.position}\n      >\n        <div ref={this.getTabsRef}>\n          {visibleTabs}\n          {this.props.collapsible &&\n            visibleTabs.length < this.props.items.length && (\n              <button onClick={this.expandMenu} value=\"expandIcon\">\n                <FaAngleDoubleRight />\n              </button>\n            )}\n        </div>\n        {this.props.collapsible && contextMenu && (\n          <ContextMenu\n            items={hiddenTabs}\n            onClick={this.props.onClick}\n            x={contextMenu.left}\n            y={contextMenu.top}\n            visible={this.state.subMenuOpened}\n          />\n        )}\n      </TabsWrapper>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Tabs/data.tsx",
    "content": "import React from 'react';\n\n/* eslint-disable react/prop-types */\nconst Component = ({ selected }: { selected: string }) => (\n  <div\n    style={{\n      display: 'flex',\n      alignItems: 'center',\n      justifyContent: 'center',\n      width: '100%',\n      height: '100%',\n      fontSize: '22px',\n    }}\n  >\n    Selected {selected}\n  </div>\n);\n/* eslint-enable react/prop-types */\n\nconst selector = (tab: { name: string; value?: string }) => ({\n  selected: tab.name,\n});\n\nexport const tabs = [\n  {\n    name: 'Tab1',\n    component: Component,\n    selector,\n  },\n  {\n    name: 'Tab2',\n    component: Component,\n    selector,\n  },\n  {\n    name: 'Tab3',\n    component: Component,\n    selector,\n  },\n];\n\nexport const simple10Tabs: { name: string; value: string }[] = [];\nfor (let i = 1; i <= 10; i++)\n  simple10Tabs.push({ name: `Tab${i}`, value: `${i}` });\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Tabs/index.ts",
    "content": "export { default } from './Tabs.js';\nexport type { Tab } from './TabsHeader.js';\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Tabs/styles/common.ts",
    "content": "import styled from '@emotion/styled';\nimport { Position } from '../Tabs.js';\n\ninterface StyleProps {\n  position: Position;\n}\n\nexport const TabsContainer = styled.div<StyleProps>`\n  position: relative;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  flex: 1;\n  overflow-y: hidden;\n  overflow-x: hidden;\n  height: 100%;\n\n  > div > div:first-child {\n    ${(props) =>\n      props.position !== 'left' &&\n      `\n      margin-left: auto !important;\n    `}\n    ${(props) =>\n      props.position === 'center' &&\n      `\n      margin-right: auto !important;\n    `}\n  }\n\n  > div:nth-child(2) {\n    flex: 1;\n    overflow-y: auto;\n    position: relative;\n  }\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Tabs/styles/default.ts",
    "content": "import { css } from '@emotion/react';\nimport { Theme } from '../../themes/default.js';\n\nexport interface StyleProps {\n  main: boolean | undefined;\n}\n\nexport const style = ({ theme, main }: StyleProps & { theme: Theme }) => css`\n  display: flex;\n  flex: 0 0 1;\n  padding-left: 1px;\n  background-color: ${theme.base01};\n  width: 100%;\n  overflow: hidden;\n  ${!main &&\n  `\n  border-top: 1px solid ${theme.base01};\n  border-bottom: 1px solid ${theme.base02};\n  `}\n\n  > div {\n    display: flex;\n    align-items: flex-end;\n    flex-wrap: nowrap;\n\n    button {\n      background-color: ${theme.base01};\n      color: ${theme.base05};\n      letter-spacing: 0.3px;\n      min-height: 30px;\n      padding: 2px 8px;\n      margin-right: 1px;\n      border: ${main ? '2' : '1'}px solid transparent;\n      cursor: pointer;\n      text-align: center;\n      overflow: hidden;\n      outline: 0;\n      transition: all 0.5s;\n\n      &:hover,\n      &:focus {\n        background-color: ${main ? theme.base02 : theme.base00};\n        text-shadow: ${theme.base01} 0 1px;\n      }\n    }\n\n    > [data-selected] {\n      ${main\n        ? `border-bottom: 2px solid ${theme.base0D};`\n        : `\n      background-color: ${theme.base00};\n      border: 1px solid ${theme.base02};\n      border-bottom: 1px solid ${theme.base00};\n      box-shadow: 0 1px ${theme.base00};\n      `}\n      color: ${theme.base07};\n    }\n  }\n  > div:nth-child(2) {\n    display: block;\n    z-index: 10;\n\n    button {\n      display: block;\n      background: ${theme.base00};\n      width: 100%;\n\n      &:hover,\n      &:focus {\n        background-color: ${main ? theme.base02 : theme.base00};\n        text-shadow: ${theme.base01} 0 1px;\n      }\n    }\n  }\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Tabs/styles/index.ts",
    "content": "export { style as default } from './default.js';\nexport { style as material } from './material.js';\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Tabs/styles/material.ts",
    "content": "import { css } from '@emotion/react';\nimport { ripple } from '../../utils/animations.js';\nimport { Theme } from '../../themes/default.js';\nimport { StyleProps } from './default.js';\n\nexport const style = ({ theme, main }: StyleProps & { theme: Theme }) => css`\n  display: flex;\n  flex: 0 0 1;\n  padding-left: 1px;\n  background-color: ${theme.base01};\n  width: 100%;\n  overflow: hidden;\n  ${!main &&\n  `\n  border-top: 1px solid ${theme.base01};\n  border-bottom: 1px solid ${theme.base02};\n  `}\n\n  > div {\n    display: flex;\n    align-items: flex-end;\n    flex-wrap: nowrap;\n\n    button {\n      background-color: ${theme.base01};\n      color: ${theme.base07};\n      min-height: 30px;\n      padding: 0 2em;\n      ${main && 'text-transform: uppercase;'}\n      cursor: pointer;\n      border: none;\n      border-bottom: 2px solid transparent;\n      text-align: center;\n      overflow: hidden;\n      outline: 0;\n      transition: all 0.5s;\n\n      &:hover,\n      &:focus {\n        border-bottom: 2px solid ${theme.base03};\n        color: ${theme.base04};\n      }\n      &.collapsed {\n        display: none;\n      }\n\n      ${ripple(theme)}\n    }\n\n    > [data-selected] {\n      border-bottom: 2px solid ${theme.base0D};\n    }\n  }\n  > div:nth-child(2) {\n    display: block;\n    z-index: 10;\n\n    button {\n      display: block;\n      background: ${theme.base00};\n      width: 100%;\n    }\n  }\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Toolbar/Toolbar.stories.tsx",
    "content": "import React, { ReactNode } from 'react';\nimport styled from '@emotion/styled';\nimport { Meta, StoryObj } from '@storybook/react-vite';\nimport { MdPlayArrow } from 'react-icons/md';\nimport { MdFiberManualRecord } from 'react-icons/md';\nimport { MdKeyboardArrowLeft } from 'react-icons/md';\nimport { MdKeyboardArrowRight } from 'react-icons/md';\nimport {\n  Toolbar,\n  Divider,\n  Spacer,\n  Button,\n  Select,\n  Slider,\n  SegmentedControl,\n  Tabs as TabsComponent,\n} from '../index.js';\nimport { options } from '../Select/options.js';\nimport { simple10Tabs } from '../Tabs/data.js';\nimport { BorderPosition } from './styles/Toolbar.js';\nimport { TooltipPosition } from '../Button/Button.js';\nimport { Position } from '../Tabs/Tabs.js';\n\nconst Container = styled.div`\n  display: flex;\n  height: 100%;\n  width: 100%;\n  justify-content: center;\n  align-items: center;\n`;\n\nconst SliderContainer = styled.div`\n  width: 90%;\n  height: 80px;\n`;\n\nconst meta: Meta = {\n  title: 'Toolbar',\n  component: Toolbar,\n};\n\nexport default meta;\n\ninterface TemplateArgs {\n  borderPosition: BorderPosition;\n  title?: string;\n  tooltipPosition: TooltipPosition;\n  disabled?: boolean;\n  onClick?: React.MouseEventHandler<HTMLButtonElement>;\n  label: ReactNode;\n}\n\nexport const Default: StoryObj<TemplateArgs> = {\n  render: ({\n    // eslint-disable-next-line react/prop-types\n    borderPosition,\n    // eslint-disable-next-line react/prop-types\n    title,\n    // eslint-disable-next-line react/prop-types\n    tooltipPosition,\n    // eslint-disable-next-line react/prop-types\n    disabled,\n    // eslint-disable-next-line react/prop-types\n    onClick,\n    // eslint-disable-next-line react/prop-types\n    label,\n  }) => (\n    <Container>\n      <Toolbar borderPosition={borderPosition}>\n        <Button\n          title={title}\n          tooltipPosition={tooltipPosition}\n          disabled={disabled}\n          onClick={onClick}\n        >\n          {label}\n        </Button>\n        <Divider />\n        <Button\n          title={title}\n          tooltipPosition={tooltipPosition}\n          disabled={disabled}\n          onClick={onClick}\n        >\n          <MdFiberManualRecord />\n        </Button>\n        <Divider />\n        <Spacer />\n        <Select options={options} />\n      </Toolbar>\n    </Container>\n  ),\n  args: {\n    borderPosition: 'top',\n    title: 'Hello Tooltip',\n    tooltipPosition: 'top',\n    disabled: false,\n    label: 'Hello Button',\n  },\n  argTypes: {\n    borderPosition: {\n      control: {\n        type: 'select',\n        options: ['top', 'bottom'],\n      },\n    },\n    tooltipPosition: {\n      control: {\n        type: 'select',\n        options: [\n          'top',\n          'bottom',\n          'left',\n          'right',\n          'bottom-left',\n          'bottom-right',\n          'top-left',\n          'top-right',\n        ],\n      },\n    },\n    onClick: {\n      action: 'button clicked',\n    },\n  },\n};\n\ninterface TabsTemplateArgs {\n  title?: string;\n  tooltipPosition: TooltipPosition;\n  disabled?: boolean;\n  buttonOnClick?: React.MouseEventHandler<HTMLButtonElement>;\n  label: ReactNode;\n  selected?: string;\n  main?: boolean;\n  tabsOnClick: (value: string) => void;\n  collapsible?: boolean;\n  position: Position;\n}\n\nexport const Tabs: StoryObj<TabsTemplateArgs> = {\n  render: ({\n    // eslint-disable-next-line react/prop-types\n    title,\n    // eslint-disable-next-line react/prop-types\n    tooltipPosition,\n    // eslint-disable-next-line react/prop-types\n    disabled,\n    // eslint-disable-next-line react/prop-types\n    buttonOnClick,\n    // eslint-disable-next-line react/prop-types\n    label,\n    // eslint-disable-next-line react/prop-types\n    selected,\n    // eslint-disable-next-line react/prop-types\n    main,\n    // eslint-disable-next-line react/prop-types\n    tabsOnClick,\n    // eslint-disable-next-line react/prop-types\n    collapsible,\n    // eslint-disable-next-line react/prop-types\n    position,\n    // eslint-disable-next-line react/prop-types\n  }) => (\n    <Container>\n      <Toolbar>\n        <Button\n          title={title}\n          tooltipPosition={tooltipPosition}\n          disabled={disabled}\n          onClick={buttonOnClick}\n        >\n          {label}\n        </Button>\n        <TabsComponent\n          tabs={simple10Tabs}\n          selected={selected}\n          main={main}\n          onClick={tabsOnClick}\n          collapsible={collapsible}\n          position={position}\n        />\n        <Button\n          title={title}\n          tooltipPosition={tooltipPosition}\n          disabled={disabled}\n          onClick={buttonOnClick}\n        >\n          {label}\n        </Button>\n      </Toolbar>\n    </Container>\n  ),\n  args: {\n    title: 'Hello Tooltip',\n    tooltipPosition: 'top',\n    disabled: false,\n    label: 'Hello Button',\n    selected: '2',\n    main: true,\n    collapsible: true,\n    position: 'center',\n  },\n  argTypes: {\n    tooltipPosition: {\n      control: {\n        type: 'select',\n        options: [\n          'top',\n          'bottom',\n          'left',\n          'right',\n          'bottom-left',\n          'bottom-right',\n          'top-left',\n          'top-right',\n        ],\n      },\n    },\n    buttonOnClick: {\n      action: 'button clicked',\n    },\n    tabsOnClick: {\n      action: 'tab selected',\n    },\n    position: {\n      control: {\n        type: 'select',\n        options: ['left', 'right', 'center'],\n      },\n    },\n  },\n};\n\ninterface WithSliderTemplateArgs {\n  title?: string;\n  tooltipPosition: TooltipPosition;\n  playOnClick?: React.MouseEventHandler<HTMLButtonElement>;\n  value: number;\n  min: number;\n  max: number;\n  label?: string;\n  withValue?: boolean;\n  onChange: (value: number) => void;\n  previousStateOnClick?: React.MouseEventHandler<HTMLButtonElement>;\n  nextStateOnClick?: React.MouseEventHandler<HTMLButtonElement>;\n  selected?: string;\n  segmentedControlOnClick: (value: string) => void;\n}\n\nexport const WithSlider: StoryObj<WithSliderTemplateArgs> = {\n  render: ({\n    // eslint-disable-next-line react/prop-types\n    title,\n    // eslint-disable-next-line react/prop-types\n    tooltipPosition,\n    // eslint-disable-next-line react/prop-types\n    playOnClick,\n    // eslint-disable-next-line react/prop-types\n    value,\n    // eslint-disable-next-line react/prop-types\n    min,\n    // eslint-disable-next-line react/prop-types\n    max,\n    // eslint-disable-next-line react/prop-types\n    label,\n    // eslint-disable-next-line react/prop-types\n    withValue,\n    // eslint-disable-next-line react/prop-types\n    onChange,\n    // eslint-disable-next-line react/prop-types\n    previousStateOnClick,\n    // eslint-disable-next-line react/prop-types\n    nextStateOnClick,\n    // eslint-disable-next-line react/prop-types\n    selected,\n    // eslint-disable-next-line react/prop-types\n    segmentedControlOnClick,\n  }) => (\n    <Container>\n      <SliderContainer>\n        <Toolbar noBorder fullHeight compact>\n          <Button\n            title={title}\n            tooltipPosition={tooltipPosition}\n            onClick={playOnClick}\n          >\n            <MdPlayArrow />\n          </Button>\n          <Slider\n            value={value}\n            min={min}\n            max={max}\n            label={label}\n            withValue={withValue}\n            onChange={onChange}\n          />\n          <Button\n            title=\"Previous state\"\n            tooltipPosition={tooltipPosition}\n            disabled\n            onClick={previousStateOnClick}\n          >\n            <MdKeyboardArrowLeft />\n          </Button>\n          <Button\n            title=\"Next state\"\n            tooltipPosition={tooltipPosition}\n            onClick={nextStateOnClick}\n          >\n            <MdKeyboardArrowRight />\n          </Button>\n          <SegmentedControl\n            values={['live', '1x']}\n            selected={selected}\n            onClick={segmentedControlOnClick}\n          />\n        </Toolbar>\n      </SliderContainer>\n    </Container>\n  ),\n  args: {\n    title: 'Play',\n    tooltipPosition: 'top',\n    value: 80,\n    min: 0,\n    max: 100,\n    label: 'Slider label',\n    withValue: false,\n    selected: 'live',\n  },\n  argTypes: {\n    tooltipPosition: {\n      control: {\n        type: 'select',\n        options: [\n          'top',\n          'bottom',\n          'left',\n          'right',\n          'bottom-left',\n          'bottom-right',\n          'top-left',\n          'top-right',\n        ],\n      },\n    },\n    playOnClick: {\n      action: 'button clicked',\n    },\n    onChange: {\n      action: 'slider changed',\n    },\n    previousStateOnClick: {\n      action: 'previous state clicked',\n    },\n    nextStateOnClick: {\n      action: 'next state clicked',\n    },\n    selected: {\n      control: {\n        type: 'select',\n        options: ['live', '1x'],\n      },\n    },\n    segmentedControlOnClick: {\n      action: 'button selected',\n    },\n  },\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Toolbar/index.ts",
    "content": "export { default as Toolbar } from './styles/Toolbar.js';\nexport { default as Divider } from './styles/Divider.js';\nexport { default as Spacer } from './styles/Spacer.js';\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Toolbar/styles/Divider.ts",
    "content": "import styled from '@emotion/styled';\nimport { Base16Theme } from 'react-base16-styling';\n\nconst Divider = styled.div`\n  background-color: ${(props: {\n    theme?: Base16Theme & { inputHeight?: number };\n  }) => props.theme!.base02};\n  box-shadow: 1px 1px 2px ${(props) => props.theme.base00};\n  height: ${(props) => props.theme.inputHeight || '30'}px;\n  width: 1px;\n  margin: auto 3px !important;\n  flex-shrink: 0;\n`;\n\nexport default Divider;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Toolbar/styles/Spacer.ts",
    "content": "import styled from '@emotion/styled';\n\nconst Spacer = styled.div`\n  flex-grow: 1;\n`;\n\nexport default Spacer;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/Toolbar/styles/Toolbar.ts",
    "content": "import styled from '@emotion/styled';\nimport type { Base16Theme } from 'react-base16-styling';\nimport * as CSS from 'csstype';\n\nexport type BorderPosition = 'top' | 'bottom';\n\nexport interface Props {\n  fullHeight?: boolean;\n  compact?: boolean;\n  borderPosition?: BorderPosition;\n  noBorder?: boolean;\n}\n\nconst Toolbar = styled.div<\n  Props & { theme?: Base16Theme & { fontFamily?: CSS.Property.FontFamily } }\n>`\n  display: flex;\n  flex-shrink: 0;\n  box-sizing: border-box;\n  width: 100%;\n  font-family: ${(props) => props.theme.fontFamily || 'monospace'};\n  font-size: 12px;\n  line-height: 16px;\n  ${(props) => props.fullHeight && 'height: 100%;'}\n  padding: ${(props) => (props.compact ? '0' : '5px')} 5px;\n  background-color: ${(props) => props.theme.base01};\n  text-align: center;\n  position: relative;\n  ${({ borderPosition, theme }) =>\n    borderPosition && `border-${borderPosition}: 1px solid ${theme.base02};`}\n\n  & > div {\n    margin: auto ${(props) => (props.noBorder ? '0' : '1px;')};\n  }\n\n  & button {\n    border-radius: 0;\n    ${(props) => props.noBorder && 'border-color: transparent;'}\n    white-space: nowrap;\n    box-shadow: none !important;\n  }\n\n  & > .Select {\n    position: static;\n    text-align: left;\n    margin: auto 1px;\n    flex-grow: 1;\n\n    .Select-control {\n      cursor: pointer;\n      border-radius: 0 !important;\n      text-align: center;\n      background-color: ${(props) => props.theme.base01};\n    }\n\n    .Select-menu-outer {\n      margin-top: 5px;\n    }\n  }\n  & > .Select.is-focused > .Select-control {\n    text-align: left;\n  }\n`;\n\nexport default Toolbar;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/colorSchemes/atom-one-dark.ts",
    "content": "export default {\n  scheme: 'atom one dark',\n  author: 'Lalit Magant (http://github.com/tilal6991)',\n  base00: '#282c34',\n  base01: '#353b45',\n  base02: '#3e4451',\n  base03: '#545862',\n  base04: '#565c64',\n  base05: '#abb2bf',\n  base06: '#b6bdca',\n  base07: '#c8ccd4',\n  base08: '#e06c75',\n  base09: '#d19a66',\n  base0A: '#e5c07b',\n  base0B: '#98c379',\n  base0C: '#56b6c2',\n  base0D: '#61afef',\n  base0E: '#c678dd',\n  base0F: '#be5046',\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/colorSchemes/default.ts",
    "content": "// Based on unikitty theme and on\n// https://github.com/reduxjs/redux-devtools/blob/master/packages/redux-devtools-inspector-monitor/src/themes/inspector.ts\n\nexport default {\n  scheme: 'default',\n  author: 'Mihail Diordiev (https://github.com/zalmoxisus)',\n  base00: '#ffffff',\n  base01: '#f3f3f3',\n  base02: '#e8e8e8',\n  base03: '#b8b8b8',\n  base04: '#585858',\n  base05: '#383838',\n  base06: '#282828',\n  base07: '#181818',\n  base08: '#d80000',\n  base09: '#d65407',\n  base0A: '#dc8a0e',\n  base0B: '#236e25',\n  base0C: '#86c1b9',\n  base0D: '#1155cc',\n  base0E: '#aa17e6',\n  base0F: '#a16946',\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/colorSchemes/dracula.ts",
    "content": "// Based on Dracula Theme (http://github.com/dracula)\nexport default {\n  scheme: 'dracula',\n  author: 'Mike Barkmin (http://github.com/mikebarkmin)',\n  base00: '#282936',\n  base01: '#3a3c4e',\n  base02: '#4d4f68',\n  base03: '#626483',\n  base04: '#62d6e8',\n  base05: '#e9e9f4',\n  base06: '#f1f2f8',\n  base07: '#f7f7fb',\n  base08: '#ea51b2',\n  base09: '#b45bcf',\n  base0A: '#00f769',\n  base0B: '#ebff87',\n  base0C: '#a1efe4',\n  base0D: '#62d6e8',\n  base0E: '#b45bcf',\n  base0F: '#00f769',\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/colorSchemes/github.ts",
    "content": "// Modified based on default theme\nexport default {\n  scheme: 'github',\n  author: 'defman21',\n  base00: '#181818',\n  base01: '#282828',\n  base02: '#333333',\n  base03: '#969896',\n  base04: '#c8c8fa',\n  base05: '#e8e8e8',\n  base06: '#f5f5f5',\n  base07: '#ffffff',\n  base08: '#a71d5d',\n  base09: '#ed6a43',\n  base0A: '#f7ca88',\n  base0B: '#a1b56c',\n  base0C: '#0086b3',\n  base0D: '#183691',\n  base0E: '#795da3',\n  base0F: '#ed6a43',\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/colorSchemes/index.ts",
    "content": "export { default } from './default.js';\nexport { default as github } from './github.js';\nexport { default as atomOneDark } from './atom-one-dark.js';\nexport { default as dracula } from './dracula.js';\nexport { default as iRBlack } from './ir-black.js';\nexport { default as macintosh } from './macintosh.js';\nexport { default as materia } from './materia.js';\nexport { default as oceanicNext } from './oceanic-next.js';\nexport { default as phD } from './phd.js';\nexport { default as pico } from './pico.js';\nexport { default as solarFlare } from './solar-flare.js';\nexport { default as spacemacs } from './spacemacs.js';\nexport { default as unikitty } from './unikitty.js';\nexport { default as woodland } from './woodland.js';\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/colorSchemes/ir-black.ts",
    "content": "export default {\n  scheme: 'ir black',\n  author: 'Timothée Poisot (http://timotheepoisot.fr)',\n  base00: '#000000',\n  base01: '#242422',\n  base02: '#484844',\n  base03: '#6c6c66',\n  base04: '#918f88',\n  base05: '#b5b3aa',\n  base06: '#d9d7cc',\n  base07: '#fdfbee',\n  base08: '#ff6c60',\n  base09: '#e9c062',\n  base0A: '#ffffb6',\n  base0B: '#a8ff60',\n  base0C: '#c6c5fe',\n  base0D: '#96cbfe',\n  base0E: '#ff73fd',\n  base0F: '#b18a3d',\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/colorSchemes/macintosh.ts",
    "content": "export default {\n  scheme: 'macintosh',\n  author: 'Rebecca Bettencourt (http://www.kreativekorp.com)',\n  base00: '#000000',\n  base01: '#404040',\n  base02: '#404040',\n  base03: '#808080',\n  base04: '#808080',\n  base05: '#c0c0c0',\n  base06: '#c0c0c0',\n  base07: '#ffffff',\n  base08: '#dd0907',\n  base09: '#ff6403',\n  base0A: '#fbf305',\n  base0B: '#1fb714',\n  base0C: '#02abea',\n  base0D: '#0000d3',\n  base0E: '#4700a5',\n  base0F: '#90713a',\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/colorSchemes/materia.ts",
    "content": "export default {\n  scheme: 'materia',\n  author: 'defman21',\n  base00: '#263238',\n  base01: '#2C393F',\n  base02: '#37474F',\n  base03: '#707880',\n  base04: '#C9CCD3',\n  base05: '#CDD3DE',\n  base06: '#D5DBE5',\n  base07: '#FFFFFF',\n  base08: '#EC5F67',\n  base09: '#EA9560',\n  base0A: '#FFCC00',\n  base0B: '#8BD649',\n  base0C: '#80CBC4',\n  base0D: '#89DDFF',\n  base0E: '#82AAFF',\n  base0F: '#EC5F67',\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/colorSchemes/oceanic-next.ts",
    "content": "export default {\n  scheme: 'oceanic next',\n  author: 'https://github.com/voronianski/oceanic-next-color-scheme',\n  base00: '#1B2B34',\n  base01: '#343D46',\n  base02: '#4F5B66',\n  base03: '#65737E',\n  base04: '#A7ADBA',\n  base05: '#C0C5CE',\n  base06: '#CDD3DE',\n  base07: '#D8DEE9',\n  base08: '#EC5f67',\n  base09: '#F99157',\n  base0A: '#FAC863',\n  base0B: '#99C794',\n  base0C: '#5FB3B3',\n  base0D: '#6699CC',\n  base0E: '#C594C5',\n  base0F: '#AB7967',\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/colorSchemes/phd.ts",
    "content": "export default {\n  scheme: 'phD',\n  author: 'Hennig Hasemann (http://leetless.de/vim.html)',\n  base00: '#061229',\n  base01: '#2a3448',\n  base02: '#4d5666',\n  base03: '#717885',\n  base04: '#9a99a3',\n  base05: '#b8bbc2',\n  base06: '#dbdde0',\n  base07: '#ffffff',\n  base08: '#d07346',\n  base09: '#f0a000',\n  base0A: '#fbd461',\n  base0B: '#99bf52',\n  base0C: '#72b9bf',\n  base0D: '#5299bf',\n  base0E: '#9989cc',\n  base0F: '#b08060',\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/colorSchemes/pico.ts",
    "content": "export default {\n  scheme: 'pico',\n  author: 'PICO-8 (http://www.lexaloffle.com/pico-8.php)',\n  base00: '#000000',\n  base01: '#1d2b53',\n  base02: '#7e2553',\n  base03: '#008751',\n  base04: '#ab5236',\n  base05: '#5f574f',\n  base06: '#c2c3c7',\n  base07: '#fff1e8',\n  base08: '#ff004d',\n  base09: '#ffa300',\n  base0A: '#fff024',\n  base0B: '#00e756',\n  base0C: '#29adff',\n  base0D: '#83769c',\n  base0E: '#ff77a8',\n  base0F: '#ffccaa',\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/colorSchemes/solar-flare.ts",
    "content": "export default {\n  scheme: 'solar flare',\n  author: 'Chuck Harmston (https://chuck.harmston.ch)',\n  base00: '#18262F',\n  base01: '#222E38',\n  base02: '#586875',\n  base03: '#667581',\n  base04: '#85939E',\n  base05: '#A6AFB8',\n  base06: '#E8E9ED',\n  base07: '#F5F7FA',\n  base08: '#EF5253',\n  base09: '#E66B2B',\n  base0A: '#E4B51C',\n  base0B: '#7CC844',\n  base0C: '#52CBB0',\n  base0D: '#33B5E1',\n  base0E: '#A363D5',\n  base0F: '#D73C9A',\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/colorSchemes/spacemacs.ts",
    "content": "export default {\n  scheme: 'spacemacs',\n  author: 'Nasser Alshammari (https://github.com/nashamri/spacemacs-theme)',\n  base00: '#1f2022',\n  base01: '#282828',\n  base02: '#444155',\n  base03: '#585858',\n  base04: '#b8b8b8',\n  base05: '#a3a3a3',\n  base06: '#e8e8e8',\n  base07: '#f8f8f8',\n  base08: '#f2241f',\n  base09: '#ffa500',\n  base0A: '#b1951d',\n  base0B: '#67b11d',\n  base0C: '#2d9574',\n  base0D: '#4f97d7',\n  base0E: '#a31db1',\n  base0F: '#b03060',\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/colorSchemes/unikitty.ts",
    "content": "export default {\n  scheme: 'unikitty',\n  author: 'Josh W Lewis (@joshwlewis)',\n  base00: '#2e2a31',\n  base01: '#4b484e',\n  base02: '#69666b',\n  base03: '#878589',\n  base04: '#a5a3a6',\n  base05: '#c3c2c4',\n  base06: '#e1e0e1',\n  base07: '#ffffff',\n  base08: '#d8137f',\n  base09: '#d65407',\n  base0A: '#dc8a0e',\n  base0B: '#17ad98',\n  base0C: '#149bda',\n  base0D: '#7864fa',\n  base0E: '#b33ce8',\n  base0F: '#d41acd',\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/colorSchemes/woodland.ts",
    "content": "export default {\n  scheme: 'woodland',\n  author: 'Jay Cornwall (https://jcornwall.com)',\n  base00: '#231e18',\n  base01: '#302b25',\n  base02: '#48413a',\n  base03: '#9d8b70',\n  base04: '#b4a490',\n  base05: '#cabcb1',\n  base06: '#d7c8bc',\n  base07: '#e4d4c8',\n  base08: '#d35c5c',\n  base09: '#ca7f32',\n  base0A: '#e0ac16',\n  base0B: '#b7ba53',\n  base0C: '#6eb958',\n  base0D: '#88a4d3',\n  base0E: '#bb90e2',\n  base0F: '#b49368',\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/index.ts",
    "content": "export type { Base16Theme } from 'react-base16-styling';\n\nexport { default as Container } from './Container/index.js';\nexport { default as Button } from './Button/index.js';\nexport { default as ContextMenu } from './ContextMenu/index.js';\nexport { default as Dialog } from './Dialog/index.js';\nexport { default as Editor } from './Editor/index.js';\nexport { default as Form } from './Form/index.js';\nexport { default as Select } from './Select/index.js';\nexport { default as Slider } from './Slider/index.js';\nexport { default as Tabs, type Tab } from './Tabs/index.js';\nexport { default as SegmentedControl } from './SegmentedControl/index.js';\nexport { default as Notification } from './Notification/index.js';\nexport * from './Toolbar/index.js';\n\nimport color from './utils/color.js';\nexport const effects = { color };\nexport { default as createStyledComponent } from './utils/createStyledComponent.js';\nexport {\n  listSchemes,\n  listThemes,\n  type ThemeName,\n  type ThemeFromProvider,\n  type SchemeName,\n} from './utils/theme.js';\nexport type { Theme } from './themes/default.js';\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/themes/default.ts",
    "content": "import type { Base16Theme } from 'react-base16-styling';\nimport * as CSS from 'csstype';\nimport * as themes from './index.js';\n\nexport interface Theme extends Base16Theme {\n  fontFamily: CSS.Property.FontFamily;\n  codeFontFamily: CSS.Property.FontFamily;\n  inputHeight: number;\n  inputBorderWidth: number;\n  inputBorderRadius: number;\n  spinnerSize: number;\n  inputPadding: number;\n  selectArrowWidth: number;\n  inputInternalHeight: number;\n  inputBorderColor: string;\n  inputFocusedStyle: string;\n  type?: keyof typeof themes;\n  light?: boolean;\n}\n\nexport default (colors: Base16Theme) => ({\n  ...colors,\n  fontFamily: \"'Source Sans Pro', sans-serif\",\n  codeFontFamily: \"'Source Code Pro', monospace\",\n  inputHeight: 30,\n  inputBorderWidth: 1,\n  inputBorderRadius: 4,\n  spinnerSize: 13, // Math.floor(theme.inputHeight / 2) - 2\n  inputPadding: 10, // theme.inputHeight / 3\n  selectArrowWidth: 4, // Math.floor(theme.inputHeight / 7)\n  inputInternalHeight: 28, // theme.inputHeight - theme.inputBorderWidth * 2\n  inputBorderColor: colors.base02,\n  inputFocusedStyle: `border-color: ${colors.base0D}`,\n});\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/themes/index.ts",
    "content": "export { default } from './default.js';\nexport { default as material } from './material.js';\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/themes/material.ts",
    "content": "import type { Base16Theme } from 'react-base16-styling';\n\nexport default (colors: Base16Theme) => ({\n  fontFamily: \"'Roboto', sans-serif\",\n  codeFontFamily: \"'Roboto Mono', monospace\",\n  inputPadding: 5,\n  inputBorderRadius: 0,\n  inputBorderColor: `transparent transparent ${colors.base02}`,\n  inputFocusedStyle: `box-shadow: inset 0 -2px 0 ${colors.base0D};`,\n});\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/utils/animations.ts",
    "content": "import { css, keyframes } from '@emotion/react';\nimport { Theme } from '../themes/default.js';\n\nexport const spin = keyframes`\n  to { transform: rotate(1turn); }\n`;\nexport const spinner = (theme: Theme) => css`\n  animation: ${spin} 400ms infinite linear;\n  width: ${theme.spinnerSize}px;\n  height: ${theme.spinnerSize}px;\n  box-sizing: border-box;\n  border-radius: 50%;\n  border: ${Math.floor(theme.spinnerSize / 8)}px solid ${theme.base02};\n  border-right-color: ${theme.base06};\n  display: inline-block;\n  position: relative;\n`;\n\nexport const fadeIn = keyframes`\n  from { opacity: 0; }\n  to { opacity: 1; }\n`;\n\n// Based on https://github.com/mladenplavsic/css-ripple-effect\nexport const ripple = (theme: Theme) => `\n  & {\n    position: relative;\n    overflow: hidden;\n  }\n\n  &:after {\n    content: \"\";\n    display: block;\n    position: absolute;\n    width: 100%;\n    height: 100%;\n    top: 0;\n    left: 0;\n    pointer-events: none;\n    background-image: radial-gradient(circle, ${theme.base07} 11%, transparent 11%);\n    background-repeat: no-repeat;\n    background-position: 50%;\n    transform: scale(10, 10);\n    opacity: 0;\n    transition: transform .5s, opacity 1s;\n  }\n\n  &:active:after {\n    transform: scale(0, 0);\n    opacity: .2;\n    transition: 0s;\n  }\n`;\n\nexport const animationCurve = 'cubic-bezier(0.4, 0, 0.2, 1)';\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/utils/autoPrefix.ts",
    "content": "export const prefixSelectors = (\n  tag: string,\n  selectors: string[],\n  style: string,\n) => selectors.map((selector) => `${tag}::-${selector} ${style}`);\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/utils/color.ts",
    "content": "import Color from 'color';\n\n/*\n  Apply color effects like\n    effect('#ffffff', 'darken', 0.5);\n    effect('#000000', 'lighten', 0.5);\n    effect('#000000', 'alpha', 0.5);\n*/\n\nexport default (\n  color: string,\n  effect: 'fade' | 'lighten' | 'alpha',\n  val: number,\n) => new Color(color)[effect](val).hsl().string();\n\n// TODO: memoize it\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/utils/createStyledComponent.ts",
    "content": "import React from 'react';\nimport styled, {\n  FunctionInterpolation,\n  StyledComponent,\n} from '@emotion/styled';\nimport { PropsOf } from '@emotion/react';\nimport type { Base16Theme } from 'react-base16-styling';\nimport getDefaultTheme, { Theme } from '../themes/default.js';\nimport { ThemeFromProvider } from './theme.js';\n\ntype StyleFunction<Props> = FunctionInterpolation<Props>;\n\ninterface StylesObject<Props> {\n  [type: string]: StyleFunction<Props>;\n}\n\ntype Styles<Props> = StylesObject<Props> | StyleFunction<Props>;\n\nfunction isStylesObject<Props>(\n  styles: Styles<Props>,\n): styles is StylesObject<Props> {\n  return typeof styles === 'object';\n}\n\nconst getStyle = <Props>(styles: Styles<Props>, type: string) =>\n  isStylesObject(styles) ? styles[type] || styles.default : styles;\n\nfunction isThemeFromProvider(\n  theme: Theme | Base16Theme,\n): theme is ThemeFromProvider {\n  return (theme as ThemeFromProvider).type !== undefined;\n}\n\nexport default function createStyledComponent<\n  C extends\n    | keyof React.JSX.IntrinsicElements\n    | React.JSXElementConstructor<any>,\n  O extends object,\n>(\n  styles: Styles<PropsOf<C> & O & { theme: Theme }>,\n  component?: C,\n): StyledComponent<PropsOf<C> & O & { theme?: Theme | Base16Theme }> {\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  return styled((component || 'div') as C)`\n    ${(props: PropsOf<C> & { theme: Theme | Base16Theme }) =>\n      isThemeFromProvider(props.theme as Theme | Base16Theme)\n        ? getStyle(styles, props.theme.type as string)\n        : // used outside of container (theme provider)\n          getStyle(\n            styles,\n            'default',\n          )({\n            ...props,\n            theme: getDefaultTheme(props.theme as Base16Theme),\n          })}\n  ` as StyledComponent<PropsOf<C> & O & { theme?: Theme | Base16Theme }>;\n}\n\n// TODO: memoize it?\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/utils/createThemedComponent.tsx",
    "content": "import React from 'react';\nimport { withTheme } from '@emotion/react';\nimport type { Base16Theme } from 'react-base16-styling';\nimport getDefaultTheme, { Theme } from '../themes/default.js';\n\nexport default <C extends React.ComponentType<any>>(\n  UnthemedComponent: React.ComponentProps<C> extends { theme?: Theme }\n    ? C\n    : never,\n) => {\n  return withTheme((props: { theme?: Theme }) => {\n    return props.theme && props.theme.type ? (\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      <UnthemedComponent {...props} />\n    ) : (\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      <UnthemedComponent\n        {...props}\n        theme={getDefaultTheme((props.theme ?? {}) as Base16Theme)}\n      />\n    );\n  });\n};\n\n// TODO: memoize it?\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/utils/invertColors.ts",
    "content": "import type { Base16Theme } from 'react-base16-styling';\n\nfunction invertColors(theme: Base16Theme) {\n  return {\n    ...theme,\n    base00: theme.base07,\n    base01: theme.base06,\n    base02: theme.base05,\n    base03: theme.base04,\n    base04: theme.base03,\n    base05: theme.base02,\n    base06: theme.base01,\n    base07: theme.base00,\n  };\n}\n\nexport default invertColors;\n"
  },
  {
    "path": "packages/redux-devtools-ui/src/utils/theme.ts",
    "content": "import { useEffect, useMemo, useState } from 'react';\nimport * as themes from '../themes/index.js';\nimport { base16Themes as baseSchemes } from 'react-base16-styling';\nimport * as additionalSchemes from '../colorSchemes/index.js';\nimport invertColors from '../utils/invertColors.js';\nimport { Theme as ThemeBase } from '../themes/default.js';\n\nconst defaultDarkScheme = baseSchemes.nicinabox;\n\nexport const schemes = { ...baseSchemes, ...additionalSchemes };\nexport const listSchemes = () => Object.keys(schemes).slice(1).sort(); // remove `__esModule`\nexport const listThemes = () => Object.keys(themes);\n\nexport type ThemeName = keyof typeof themes;\nexport type SchemeName = keyof typeof schemes;\n\nexport interface ThemeData {\n  theme: keyof typeof themes;\n  scheme: keyof typeof schemes;\n  colorPreference: 'auto' | 'light' | 'dark';\n}\n\nexport interface ThemeFromProvider extends ThemeBase {\n  type: keyof typeof themes;\n  light: boolean;\n}\n\nconst getTheme = (\n  type: keyof typeof themes,\n  scheme: keyof typeof schemes,\n  light: boolean,\n): ThemeFromProvider => {\n  let colors;\n  if (scheme === 'default') {\n    colors = light ? schemes.default : defaultDarkScheme;\n  } else {\n    colors = schemes[scheme];\n    if (light) colors = invertColors(colors);\n  }\n\n  let theme = {\n    type,\n    light,\n    ...themes.default(colors),\n  };\n  if (type !== 'default') {\n    theme = { ...theme, ...themes[type](colors) };\n  }\n\n  return theme;\n};\n\nexport const useTheme = ({\n  theme: type,\n  scheme,\n  colorPreference,\n}: ThemeData): ThemeFromProvider => {\n  const [prefersDarkColorScheme, setPrefersDarkColorScheme] = useState(\n    window.matchMedia('(prefers-color-scheme: dark)').matches,\n  );\n\n  useEffect(() => {\n    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n\n    const handleChange = ({ matches }: MediaQueryListEvent) => {\n      setPrefersDarkColorScheme(matches);\n    };\n\n    mediaQuery.addEventListener('change', handleChange);\n    return () => mediaQuery.removeEventListener('change', handleChange);\n  }, []);\n\n  const light = useMemo(\n    () =>\n      colorPreference === 'auto'\n        ? !prefersDarkColorScheme\n        : colorPreference === 'light',\n    [colorPreference, prefersDarkColorScheme],\n  );\n\n  return getTheme(type, scheme, light);\n};\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/Button.test.tsx",
    "content": "import { jest } from '@jest/globals';\nimport React from 'react';\nimport { render, screen } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\nimport { Button } from '../src/index.js';\n\ndescribe('Button', function () {\n  it('renders correctly', () => {\n    const { container } = render(<Button>Text</Button>);\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('should handle the click event', async () => {\n    const onClick = jest.fn();\n    render(<Button onClick={onClick}>ClickMe</Button>);\n\n    await userEvent.click(screen.getByRole('button'));\n    expect(onClick).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/Container.test.tsx",
    "content": "import { jest } from '@jest/globals';\nimport React from 'react';\nimport { render } from '@testing-library/react';\nimport { Container } from '../src/index.js';\n\nObject.defineProperty(window, 'matchMedia', {\n  writable: true,\n  value: jest.fn().mockImplementation((query) => ({\n    matches: false,\n    media: query,\n    onchange: null,\n    addListener: jest.fn(), // deprecated\n    removeListener: jest.fn(), // deprecated\n    addEventListener: jest.fn(),\n    removeEventListener: jest.fn(),\n    dispatchEvent: jest.fn(),\n  })),\n});\n\ndescribe('Container', function () {\n  it('renders correctly', () => {\n    const { container } = render(\n      <Container\n        themeData={{\n          theme: 'default',\n          scheme: 'default',\n          colorPreference: 'auto',\n        }}\n      >\n        Text\n      </Container>,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/ContextMenu.test.tsx",
    "content": "import { jest } from '@jest/globals';\nimport React from 'react';\nimport { render, screen } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\nimport { ContextMenu } from '../src/index.js';\nimport { items } from '../src/ContextMenu/data.js';\n\ndescribe('ContextMenu', function () {\n  it('renders correctly', () => {\n    const { container } = render(\n      <ContextMenu\n        items={items}\n        onClick={() => {\n          // noop\n        }}\n        x={100}\n        y={100}\n      />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n  it('should handle the click event', async () => {\n    const onClick = jest.fn();\n    render(\n      <ContextMenu items={items} onClick={onClick} x={100} y={100} visible />,\n    );\n\n    await userEvent.click(screen.getByRole('button', { name: 'Menu Item 1' }));\n    expect(onClick).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/Dialog.test.tsx",
    "content": "import { jest } from '@jest/globals';\nimport React from 'react';\nimport { render, screen } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\nimport { Dialog } from '../src/index.js';\n\ndescribe('Dialog', function () {\n  it('renders correctly', () => {\n    const { container } = render(\n      <Dialog\n        onDismiss={() => {\n          // noop\n        }}\n        onSubmit={() => {\n          // noop\n        }}\n      />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('renders with props', () => {\n    const { container } = render(\n      <Dialog\n        title=\"Dialog Title\"\n        open\n        fullWidth\n        onDismiss={() => {\n          // noop\n        }}\n        onSubmit={() => {\n          // noop\n        }}\n      >\n        Hello Dialog!\n      </Dialog>,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('renders modal', () => {\n    const { container } = render(\n      <Dialog\n        modal\n        onDismiss={() => {\n          // noop\n        }}\n        onSubmit={() => {\n          // noop\n        }}\n      />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('should handle dismiss event', async () => {\n    const onDismiss = jest.fn();\n    render(\n      <Dialog\n        open\n        onDismiss={onDismiss}\n        onSubmit={() => {\n          // noop\n        }}\n      />,\n    );\n\n    await userEvent.click(screen.getByRole('button', { name: 'Cancel' }));\n    expect(onDismiss).toHaveBeenCalled();\n  });\n\n  it('should handle submit event', async () => {\n    const onSubmit = jest.fn();\n    render(\n      <Dialog\n        open\n        onDismiss={() => {\n          // noop\n        }}\n        onSubmit={onSubmit}\n      />,\n    );\n\n    await userEvent.click(screen.getByRole('button', { name: 'Submit' }));\n    expect(onSubmit).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/Editor.test.tsx",
    "content": "import React from 'react';\nimport { render } from '@testing-library/react';\nimport { Editor } from '../src/index.js';\n\ndescribe('Editor', function () {\n  const { container } = render(<Editor value=\"var a = 1;\" />);\n\n  it('renders correctly', () => {\n    expect(container.firstChild).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/Form.test.tsx",
    "content": "import { jest } from '@jest/globals';\nimport React from 'react';\nimport { render, screen } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\nimport { Form } from '../src/index.js';\nimport { schema, uiSchema, formData } from '../src/Form/schema.js';\n\ndescribe('Form', function () {\n  let random: () => number;\n\n  beforeAll(() => {\n    random = Math.random;\n    Math.random = jest.fn(() => 0.25546350798039463);\n  });\n\n  afterAll(() => {\n    Math.random = random;\n    console.log(Math.random());\n  });\n\n  it('renders correctly', () => {\n    const { container } = render(\n      <Form formData={formData} schema={schema} uiSchema={uiSchema} />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('renders with primary button', () => {\n    const { container } = render(\n      <Form\n        primaryButton\n        submitText=\"Custom button\"\n        formData={formData}\n        schema={schema}\n        uiSchema={uiSchema}\n      />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('renders with no button', () => {\n    const { container } = render(\n      <Form formData={formData} schema={schema} uiSchema={uiSchema} noSubmit />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('should handle the submit event', async () => {\n    const onSubmit = jest.fn();\n    render(\n      <Form\n        formData={formData}\n        schema={schema}\n        uiSchema={uiSchema}\n        onSubmit={onSubmit}\n      />,\n    );\n\n    await userEvent.click(screen.getByRole('button', { name: 'Submit' }));\n    expect(onSubmit).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/Notification.test.tsx",
    "content": "import { jest } from '@jest/globals';\nimport React from 'react';\nimport { render, screen } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\nimport { Notification } from '../src/index.js';\n\ndescribe('Notification', function () {\n  it('renders correctly', () => {\n    const { container } = render(<Notification>Message</Notification>);\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('renders with props', () => {\n    const { container } = render(\n      <Notification\n        type=\"error\"\n        onClose={() => {\n          // noop\n        }}\n      >\n        Message\n      </Notification>,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('should handle the click event', async () => {\n    const onClose = jest.fn();\n    render(<Notification onClose={onClose}>Message</Notification>);\n\n    await userEvent.click(screen.getByRole('button'));\n    expect(onClose).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/SegmentedControl.test.tsx",
    "content": "import { jest } from '@jest/globals';\nimport React from 'react';\nimport { render, screen } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\nimport { SegmentedControl } from '../src/index.js';\n\ndescribe('SegmentedControl', function () {\n  it('renders correctly', () => {\n    const { container } = render(\n      <SegmentedControl\n        values={['Button1', 'Button2', 'Button3']}\n        selected=\"Button1\"\n        disabled={false}\n        onClick={() => {\n          // noop\n        }}\n      />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n  it('should handle the click event', async () => {\n    const onClick = jest.fn();\n    render(\n      <SegmentedControl\n        values={['Button1', 'Button2', 'Button3']}\n        selected=\"Button1\"\n        disabled={false}\n        onClick={onClick}\n      />,\n    );\n\n    await userEvent.click(screen.getByRole('button', { name: 'Button1' }));\n    expect(onClick).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/Select.test.tsx",
    "content": "import { jest } from '@jest/globals';\nimport React from 'react';\nimport { render, screen } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\nimport { Select } from '../src/index.js';\nimport { options } from '../src/Select/options.js';\n\ndescribe('Select', function () {\n  it('renders correctly', () => {\n    const { container } = render(\n      <Select\n        options={options}\n        onChange={() => {\n          // noop\n        }}\n      />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('renders with props', () => {\n    const { container } = render(\n      <Select\n        options={options}\n        onChange={() => {\n          // noop\n        }}\n        value={options.filter((option) => option.value === 'one')}\n        maxMenuHeight={20}\n        isClearable\n        isDisabled\n        isLoading\n        isMulti\n        isSearchable={false}\n        menuPlacement=\"top\"\n      />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('should select another option', async () => {\n    const onChange = jest.fn();\n    const { container } = render(\n      <Select options={options} onChange={onChange} />,\n    );\n\n    await userEvent.type(screen.getByRole('combobox'), 'two');\n    expect(container.firstChild).toMatchSnapshot();\n    await userEvent.type(screen.getByRole('combobox'), '{enter}');\n    expect(onChange).toHaveBeenCalled();\n  });\n\n  it(\"shouldn't find any results\", async () => {\n    const onChange = jest.fn();\n    const { container } = render(\n      <Select options={options} onChange={onChange} />,\n    );\n\n    await userEvent.type(screen.getByRole('combobox'), 'text');\n    expect(container.firstChild).toMatchSnapshot();\n    await userEvent.type(screen.getByRole('combobox'), '{enter}');\n    expect(onChange).not.toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/Slider.test.tsx",
    "content": "import { jest } from '@jest/globals';\nimport React from 'react';\nimport { fireEvent, render, screen } from '@testing-library/react';\nimport { Slider } from '../src/index.js';\n\ndescribe('Slider', function () {\n  it('renders correctly', () => {\n    const { container } = render(\n      <Slider\n        onChange={() => {\n          // noop\n        }}\n      />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('renders with props', () => {\n    const { container } = render(\n      <Slider\n        label=\"Hi\"\n        min={1}\n        max={10}\n        value={5}\n        disabled\n        onChange={() => {\n          // noop\n        }}\n      />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('should handle the change event', () => {\n    const onChange = jest.fn();\n    render(<Slider value={1} onChange={onChange} />);\n\n    fireEvent.change(screen.getByRole('slider'), { target: { value: '2' } });\n    expect(onChange).toHaveBeenCalled();\n    expect(onChange).toHaveBeenCalledWith(2);\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/Tabs.test.tsx",
    "content": "import { jest } from '@jest/globals';\nimport React from 'react';\nimport { render, screen } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\nimport { Tabs } from '../src/index.js';\nimport { tabs, simple10Tabs } from '../src/Tabs/data.js';\n\ndescribe('Tabs', function () {\n  it('renders correctly', () => {\n    const { container } = render(\n      <Tabs\n        tabs={tabs}\n        onClick={() => {\n          // noop\n        }}\n      />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('renders with props', () => {\n    const { container } = render(\n      <Tabs\n        tabs={tabs}\n        onClick={() => {\n          // noop\n        }}\n        selected=\"Tab2\"\n      />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('renders tabs without inner components', () => {\n    const { container } = render(\n      <Tabs\n        tabs={simple10Tabs}\n        onClick={() => {\n          // noop\n        }}\n        selected=\"5\"\n      />,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('should select tab', async () => {\n    const onClick = jest.fn();\n    render(<Tabs tabs={tabs} onClick={onClick} />);\n\n    await userEvent.click(screen.getByRole('button', { name: 'Tab1' }));\n    expect(onClick).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/Toolbar.test.tsx",
    "content": "import React from 'react';\nimport { render } from '@testing-library/react';\nimport { Toolbar, Divider, Spacer, Button } from '../src/index.js';\n\ndescribe('Toolbar', function () {\n  it('renders correctly', () => {\n    const { container } = render(\n      <Toolbar>\n        <Button>1</Button>\n        <Divider />\n        <Spacer />\n        <Button>2</Button>\n      </Toolbar>,\n    );\n    expect(container.firstChild).toMatchSnapshot();\n  });\n\n  it('renders with props', () => {\n    const { container } = render(<Toolbar borderPosition=\"top\" />);\n    expect(container.firstChild).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/__mocks__/styleMock.ts",
    "content": "export default {};\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/__snapshots__/Button.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing\n\nexports[`Button renders correctly 1`] = `\n<div\n  class=\"css-jg680o\"\n>\n  <button\n    class=\"css-g2zi5\"\n  >\n    Text\n  </button>\n</div>\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/__snapshots__/Container.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing\n\nexports[`Container renders correctly 1`] = `\n<div\n  class=\"css-jqr1ii\"\n>\n  Text\n</div>\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/__snapshots__/ContextMenu.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing\n\nexports[`ContextMenu renders correctly 1`] = `\n<div\n  class=\"css-1x2keqt\"\n  style=\"top: 100px; left: 100px;\"\n>\n  <button\n    value=\"Menu Item 1\"\n  >\n    Menu Item 1\n  </button>\n  <button\n    value=\"Menu Item 2\"\n  >\n    Menu Item 2\n  </button>\n  <button\n    value=\"Menu Item 3\"\n  >\n    Menu Item 3\n  </button>\n</div>\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/__snapshots__/Dialog.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing\n\nexports[`Dialog renders correctly 1`] = `\n<div\n  class=\"css-1nze9tl\"\n>\n  <div />\n  <div>\n    <div\n      class=\"mc-dialog--header\"\n    >\n      <div />\n      <button>\n        ×\n      </button>\n    </div>\n    <div\n      class=\"mc-dialog--body\"\n    />\n    <div\n      class=\"mc-dialog--footer\"\n    >\n      <div\n        class=\"css-jg680o\"\n      >\n        <button\n          class=\"css-g2zi5\"\n        >\n          Cancel\n        </button>\n      </div>\n      <div\n        class=\"css-jg680o\"\n      >\n        <button\n          class=\"css-1td9y62\"\n        >\n          Submit\n        </button>\n      </div>\n    </div>\n  </div>\n</div>\n`;\n\nexports[`Dialog renders modal 1`] = `\n<div\n  class=\"css-1nze9tl\"\n>\n  <div />\n  <div>\n    <div\n      class=\"mc-dialog--header\"\n    >\n      <div />\n    </div>\n    <div\n      class=\"mc-dialog--body\"\n    />\n    <div\n      class=\"mc-dialog--footer\"\n    >\n      <div\n        class=\"css-jg680o\"\n      >\n        <button\n          class=\"css-g2zi5\"\n        >\n          Cancel\n        </button>\n      </div>\n      <div\n        class=\"css-jg680o\"\n      >\n        <button\n          class=\"css-1td9y62\"\n        >\n          Submit\n        </button>\n      </div>\n    </div>\n  </div>\n</div>\n`;\n\nexports[`Dialog renders with props 1`] = `\n<div\n  class=\"css-1cbskzi\"\n  open=\"\"\n>\n  <div />\n  <div>\n    <div\n      class=\"mc-dialog--header\"\n    >\n      <div>\n        Dialog Title\n      </div>\n      <button>\n        ×\n      </button>\n    </div>\n    <div\n      class=\"mc-dialog--body\"\n    >\n      Hello Dialog!\n    </div>\n    <div\n      class=\"mc-dialog--footer\"\n    >\n      <div\n        class=\"css-jg680o\"\n      >\n        <button\n          class=\"css-g2zi5\"\n        >\n          Cancel\n        </button>\n      </div>\n      <div\n        class=\"css-jg680o\"\n      >\n        <button\n          class=\"css-1td9y62\"\n        >\n          Submit\n        </button>\n      </div>\n    </div>\n  </div>\n</div>\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/__snapshots__/Editor.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing\n\nexports[`Editor renders correctly 1`] = `\n<div\n  class=\"css-17hzfkk\"\n>\n  <div\n    class=\"cm-theme\"\n  >\n    <div\n      class=\"cm-editor ͼ1 ͼ3 ͼ4 ͼ1q ͼ16\"\n    >\n      <div\n        aria-live=\"polite\"\n        class=\"cm-announced\"\n      />\n      <div\n        class=\"cm-scroller\"\n        tabindex=\"-1\"\n      >\n        <div\n          aria-hidden=\"true\"\n          class=\"cm-gutters cm-gutters-before\"\n          style=\"min-height: 14px; position: sticky;\"\n        >\n          <div\n            class=\"cm-gutter cm-lineNumbers\"\n          >\n            <div\n              class=\"cm-gutterElement\"\n              style=\"height: 0px; visibility: hidden; pointer-events: none;\"\n            >\n              9\n            </div>\n            <div\n              class=\"cm-gutterElement cm-activeLineGutter\"\n              style=\"height: 14px;\"\n            >\n              1\n            </div>\n          </div>\n          <div\n            class=\"cm-gutter cm-foldGutter\"\n          >\n            <div\n              class=\"cm-gutterElement\"\n              style=\"height: 0px; visibility: hidden; pointer-events: none;\"\n            >\n              <span\n                title=\"Unfold line\"\n              >\n                ›\n              </span>\n            </div>\n            <div\n              class=\"cm-gutterElement cm-activeLineGutter\"\n              style=\"height: 14px;\"\n            />\n          </div>\n        </div>\n        <div\n          aria-multiline=\"true\"\n          autocapitalize=\"off\"\n          autocorrect=\"off\"\n          class=\"cm-content\"\n          contenteditable=\"true\"\n          data-language=\"javascript\"\n          role=\"textbox\"\n          spellcheck=\"false\"\n          style=\"tab-size: 4;\"\n          translate=\"no\"\n          writingsuggestions=\"false\"\n        >\n          <div\n            class=\"cm-line cm-activeLine\"\n          >\n            <span\n              class=\"ͼ19\"\n            >\n              var\n            </span>\n             \n            <span\n              class=\"ͼ1c\"\n            >\n              a\n            </span>\n             \n            <span\n              class=\"ͼ1f\"\n            >\n              =\n            </span>\n             \n            <span\n              class=\"ͼ1b\"\n            >\n              1\n            </span>\n            ;\n          </div>\n        </div>\n        <div\n          aria-hidden=\"true\"\n          class=\"cm-layer cm-layer-above cm-cursorLayer\"\n          style=\"z-index: 150; animation-duration: 1200ms;\"\n        />\n        <div\n          aria-hidden=\"true\"\n          class=\"cm-layer cm-selectionLayer\"\n          style=\"z-index: -2;\"\n        />\n      </div>\n    </div>\n  </div>\n</div>\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/__snapshots__/Form.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing\n\nexports[`Form renders correctly 1`] = `\n<form\n  class=\"css-yd7kx\"\n>\n  <div\n    class=\"form-group rjsf-field rjsf-field-object\"\n  >\n    <fieldset\n      id=\"root\"\n    >\n      <legend\n        id=\"root__title\"\n      >\n        Example form\n      </legend>\n      <div\n        class=\"field-description\"\n        id=\"root__description\"\n      >\n        A simple form example.\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-string\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_name\"\n        >\n          Full name\n          <span\n            class=\"required\"\n          >\n            *\n          </span>\n        </label>\n        <input\n          aria-describedby=\"root_name__error root_name__description root_name__help\"\n          class=\"form-control\"\n          id=\"root_name\"\n          label=\"Full name\"\n          name=\"root_name\"\n          placeholder=\"\"\n          required=\"\"\n          type=\"text\"\n          value=\"Chuck Norris\"\n        />\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-integer\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_age\"\n        >\n          Age\n        </label>\n        <input\n          aria-describedby=\"root_age__error root_age__description root_age__help\"\n          class=\"form-control\"\n          id=\"root_age\"\n          label=\"Age\"\n          name=\"root_age\"\n          placeholder=\"\"\n          type=\"number\"\n          value=\"75\"\n        />\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-string\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_bio\"\n        >\n          Bio\n        </label>\n        <textarea\n          aria-describedby=\"root_bio__error root_bio__description root_bio__help\"\n          class=\"form-control\"\n          id=\"root_bio\"\n          name=\"root_bio\"\n          placeholder=\"\"\n        >\n          Roundhouse kicking asses since 1940\n        </textarea>\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-string\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_password\"\n        >\n          Password\n        </label>\n        <input\n          aria-describedby=\"root_password__error root_password__description root_password__help\"\n          class=\"form-control\"\n          id=\"root_password\"\n          label=\"Password\"\n          name=\"root_password\"\n          placeholder=\"\"\n          type=\"password\"\n          value=\"noneed\"\n        />\n        <div\n          class=\"help-block\"\n          id=\"root_password__help\"\n        >\n          Hint: Make it strong!\n        </div>\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-array\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_multipleChoicesList\"\n        >\n          A multiple choices list\n        </label>\n        <div\n          class=\"checkboxes\"\n          id=\"root_multipleChoicesList\"\n        >\n          <div\n            class=\"checkbox \"\n          >\n            <label>\n              <span>\n                <input\n                  aria-describedby=\"root_multipleChoicesList__error root_multipleChoicesList__description root_multipleChoicesList__help\"\n                  id=\"root_multipleChoicesList-0\"\n                  name=\"root_multipleChoicesList\"\n                  type=\"checkbox\"\n                  value=\"0\"\n                />\n                <span>\n                  foo\n                </span>\n              </span>\n            </label>\n          </div>\n          <div\n            class=\"checkbox \"\n          >\n            <label>\n              <span>\n                <input\n                  aria-describedby=\"root_multipleChoicesList__error root_multipleChoicesList__description root_multipleChoicesList__help\"\n                  id=\"root_multipleChoicesList-1\"\n                  name=\"root_multipleChoicesList\"\n                  type=\"checkbox\"\n                  value=\"1\"\n                />\n                <span>\n                  bar\n                </span>\n              </span>\n            </label>\n          </div>\n          <div\n            class=\"checkbox \"\n          >\n            <label>\n              <span>\n                <input\n                  aria-describedby=\"root_multipleChoicesList__error root_multipleChoicesList__description root_multipleChoicesList__help\"\n                  id=\"root_multipleChoicesList-2\"\n                  name=\"root_multipleChoicesList\"\n                  type=\"checkbox\"\n                  value=\"2\"\n                />\n                <span>\n                  fuzz\n                </span>\n              </span>\n            </label>\n          </div>\n        </div>\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-number\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_numberEnum\"\n        >\n          Number enum\n        </label>\n        <div\n          class=\"css-18o3wl1-container\"\n          id=\"root_numberEnum\"\n        >\n          <span\n            class=\"css-1f43avz-a11yText-A11yText\"\n            id=\"react-select-2-live-region\"\n          />\n          <span\n            aria-atomic=\"false\"\n            aria-live=\"polite\"\n            aria-relevant=\"additions text\"\n            class=\"css-1f43avz-a11yText-A11yText\"\n            role=\"log\"\n          />\n          <div\n            class=\"css-10g0wlc-control\"\n          >\n            <div\n              class=\"css-1uzcsaf\"\n            >\n              <div\n                class=\"css-1m6ztbo-placeholder\"\n                id=\"react-select-2-placeholder\"\n              />\n              <div\n                class=\"css-fty6pr\"\n                data-value=\"\"\n              >\n                <input\n                  aria-activedescendant=\"\"\n                  aria-autocomplete=\"list\"\n                  aria-describedby=\"react-select-2-placeholder\"\n                  aria-expanded=\"false\"\n                  aria-haspopup=\"true\"\n                  aria-required=\"false\"\n                  autocapitalize=\"none\"\n                  autocomplete=\"off\"\n                  autocorrect=\"off\"\n                  class=\"\"\n                  id=\"react-select-2-input\"\n                  role=\"combobox\"\n                  spellcheck=\"false\"\n                  style=\"color: inherit; background: 0px; opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;\"\n                  tabindex=\"0\"\n                  type=\"text\"\n                  value=\"\"\n                />\n              </div>\n            </div>\n            <div\n              class=\"css-1wy0on6\"\n            >\n              <span\n                class=\"css-19norqf-indicatorSeparator\"\n              />\n              <div\n                aria-hidden=\"true\"\n                class=\"css-17vo4tq-indicatorContainer\"\n              >\n                <svg\n                  aria-hidden=\"true\"\n                  class=\"css-tj5bde-Svg\"\n                  focusable=\"false\"\n                  height=\"20\"\n                  viewBox=\"0 0 20 20\"\n                  width=\"20\"\n                >\n                  <path\n                    d=\"M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z\"\n                  />\n                </svg>\n              </div>\n            </div>\n          </div>\n          <input\n            name=\"numberEnum\"\n            type=\"hidden\"\n            value=\"\"\n          />\n        </div>\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-number\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_numberEnumRadio\"\n        >\n          Number enum\n        </label>\n        <div\n          class=\"field-radio-group\"\n          id=\"root_numberEnumRadio\"\n          role=\"radiogroup\"\n        >\n          <label\n            class=\"radio-inline \"\n          >\n            <span>\n              <input\n                aria-describedby=\"root_numberEnumRadio__error root_numberEnumRadio__description root_numberEnumRadio__help\"\n                id=\"root_numberEnumRadio-0\"\n                name=\"root_numberEnumRadio\"\n                type=\"radio\"\n                value=\"0\"\n              />\n              <span>\n                1\n              </span>\n            </span>\n          </label>\n          <label\n            class=\"radio-inline \"\n          >\n            <span>\n              <input\n                aria-describedby=\"root_numberEnumRadio__error root_numberEnumRadio__description root_numberEnumRadio__help\"\n                id=\"root_numberEnumRadio-1\"\n                name=\"root_numberEnumRadio\"\n                type=\"radio\"\n                value=\"1\"\n              />\n              <span>\n                2\n              </span>\n            </span>\n          </label>\n          <label\n            class=\"radio-inline \"\n          >\n            <span>\n              <input\n                aria-describedby=\"root_numberEnumRadio__error root_numberEnumRadio__description root_numberEnumRadio__help\"\n                id=\"root_numberEnumRadio-2\"\n                name=\"root_numberEnumRadio\"\n                type=\"radio\"\n                value=\"2\"\n              />\n              <span>\n                3\n              </span>\n            </span>\n          </label>\n        </div>\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-integer\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_integerRange\"\n        >\n          Integer range\n        </label>\n        <div\n          class=\"css-1vryedt\"\n        >\n          <div\n            class=\"css-nc7xvn\"\n          >\n            <input\n              id=\"root_integerRange\"\n              max=\"100\"\n              min=\"42\"\n              name=\"integerRange\"\n              placeholder=\"\"\n              type=\"range\"\n              uischema=\"[object Object]\"\n              value=\"52\"\n            />\n            <div>\n              52\n            </div>\n          </div>\n        </div>\n      </div>\n    </fieldset>\n  </div>\n  <div\n    class=\"css-q8f4aw\"\n  >\n    <button\n      class=\"css-g2zi5\"\n      type=\"submit\"\n    >\n      Submit\n    </button>\n  </div>\n</form>\n`;\n\nexports[`Form renders with no button 1`] = `\n<form\n  class=\"css-yd7kx\"\n>\n  <div\n    class=\"form-group rjsf-field rjsf-field-object\"\n  >\n    <fieldset\n      id=\"root\"\n    >\n      <legend\n        id=\"root__title\"\n      >\n        Example form\n      </legend>\n      <div\n        class=\"field-description\"\n        id=\"root__description\"\n      >\n        A simple form example.\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-string\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_name\"\n        >\n          Full name\n          <span\n            class=\"required\"\n          >\n            *\n          </span>\n        </label>\n        <input\n          aria-describedby=\"root_name__error root_name__description root_name__help\"\n          class=\"form-control\"\n          id=\"root_name\"\n          label=\"Full name\"\n          name=\"root_name\"\n          placeholder=\"\"\n          required=\"\"\n          type=\"text\"\n          value=\"Chuck Norris\"\n        />\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-integer\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_age\"\n        >\n          Age\n        </label>\n        <input\n          aria-describedby=\"root_age__error root_age__description root_age__help\"\n          class=\"form-control\"\n          id=\"root_age\"\n          label=\"Age\"\n          name=\"root_age\"\n          placeholder=\"\"\n          type=\"number\"\n          value=\"75\"\n        />\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-string\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_bio\"\n        >\n          Bio\n        </label>\n        <textarea\n          aria-describedby=\"root_bio__error root_bio__description root_bio__help\"\n          class=\"form-control\"\n          id=\"root_bio\"\n          name=\"root_bio\"\n          placeholder=\"\"\n        >\n          Roundhouse kicking asses since 1940\n        </textarea>\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-string\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_password\"\n        >\n          Password\n        </label>\n        <input\n          aria-describedby=\"root_password__error root_password__description root_password__help\"\n          class=\"form-control\"\n          id=\"root_password\"\n          label=\"Password\"\n          name=\"root_password\"\n          placeholder=\"\"\n          type=\"password\"\n          value=\"noneed\"\n        />\n        <div\n          class=\"help-block\"\n          id=\"root_password__help\"\n        >\n          Hint: Make it strong!\n        </div>\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-array\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_multipleChoicesList\"\n        >\n          A multiple choices list\n        </label>\n        <div\n          class=\"checkboxes\"\n          id=\"root_multipleChoicesList\"\n        >\n          <div\n            class=\"checkbox \"\n          >\n            <label>\n              <span>\n                <input\n                  aria-describedby=\"root_multipleChoicesList__error root_multipleChoicesList__description root_multipleChoicesList__help\"\n                  id=\"root_multipleChoicesList-0\"\n                  name=\"root_multipleChoicesList\"\n                  type=\"checkbox\"\n                  value=\"0\"\n                />\n                <span>\n                  foo\n                </span>\n              </span>\n            </label>\n          </div>\n          <div\n            class=\"checkbox \"\n          >\n            <label>\n              <span>\n                <input\n                  aria-describedby=\"root_multipleChoicesList__error root_multipleChoicesList__description root_multipleChoicesList__help\"\n                  id=\"root_multipleChoicesList-1\"\n                  name=\"root_multipleChoicesList\"\n                  type=\"checkbox\"\n                  value=\"1\"\n                />\n                <span>\n                  bar\n                </span>\n              </span>\n            </label>\n          </div>\n          <div\n            class=\"checkbox \"\n          >\n            <label>\n              <span>\n                <input\n                  aria-describedby=\"root_multipleChoicesList__error root_multipleChoicesList__description root_multipleChoicesList__help\"\n                  id=\"root_multipleChoicesList-2\"\n                  name=\"root_multipleChoicesList\"\n                  type=\"checkbox\"\n                  value=\"2\"\n                />\n                <span>\n                  fuzz\n                </span>\n              </span>\n            </label>\n          </div>\n        </div>\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-number\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_numberEnum\"\n        >\n          Number enum\n        </label>\n        <div\n          class=\"css-18o3wl1-container\"\n          id=\"root_numberEnum\"\n        >\n          <span\n            class=\"css-1f43avz-a11yText-A11yText\"\n            id=\"react-select-4-live-region\"\n          />\n          <span\n            aria-atomic=\"false\"\n            aria-live=\"polite\"\n            aria-relevant=\"additions text\"\n            class=\"css-1f43avz-a11yText-A11yText\"\n            role=\"log\"\n          />\n          <div\n            class=\"css-10g0wlc-control\"\n          >\n            <div\n              class=\"css-1uzcsaf\"\n            >\n              <div\n                class=\"css-1m6ztbo-placeholder\"\n                id=\"react-select-4-placeholder\"\n              />\n              <div\n                class=\"css-fty6pr\"\n                data-value=\"\"\n              >\n                <input\n                  aria-activedescendant=\"\"\n                  aria-autocomplete=\"list\"\n                  aria-describedby=\"react-select-4-placeholder\"\n                  aria-expanded=\"false\"\n                  aria-haspopup=\"true\"\n                  aria-required=\"false\"\n                  autocapitalize=\"none\"\n                  autocomplete=\"off\"\n                  autocorrect=\"off\"\n                  class=\"\"\n                  id=\"react-select-4-input\"\n                  role=\"combobox\"\n                  spellcheck=\"false\"\n                  style=\"color: inherit; background: 0px; opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;\"\n                  tabindex=\"0\"\n                  type=\"text\"\n                  value=\"\"\n                />\n              </div>\n            </div>\n            <div\n              class=\"css-1wy0on6\"\n            >\n              <span\n                class=\"css-19norqf-indicatorSeparator\"\n              />\n              <div\n                aria-hidden=\"true\"\n                class=\"css-17vo4tq-indicatorContainer\"\n              >\n                <svg\n                  aria-hidden=\"true\"\n                  class=\"css-tj5bde-Svg\"\n                  focusable=\"false\"\n                  height=\"20\"\n                  viewBox=\"0 0 20 20\"\n                  width=\"20\"\n                >\n                  <path\n                    d=\"M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z\"\n                  />\n                </svg>\n              </div>\n            </div>\n          </div>\n          <input\n            name=\"numberEnum\"\n            type=\"hidden\"\n            value=\"\"\n          />\n        </div>\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-number\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_numberEnumRadio\"\n        >\n          Number enum\n        </label>\n        <div\n          class=\"field-radio-group\"\n          id=\"root_numberEnumRadio\"\n          role=\"radiogroup\"\n        >\n          <label\n            class=\"radio-inline \"\n          >\n            <span>\n              <input\n                aria-describedby=\"root_numberEnumRadio__error root_numberEnumRadio__description root_numberEnumRadio__help\"\n                id=\"root_numberEnumRadio-0\"\n                name=\"root_numberEnumRadio\"\n                type=\"radio\"\n                value=\"0\"\n              />\n              <span>\n                1\n              </span>\n            </span>\n          </label>\n          <label\n            class=\"radio-inline \"\n          >\n            <span>\n              <input\n                aria-describedby=\"root_numberEnumRadio__error root_numberEnumRadio__description root_numberEnumRadio__help\"\n                id=\"root_numberEnumRadio-1\"\n                name=\"root_numberEnumRadio\"\n                type=\"radio\"\n                value=\"1\"\n              />\n              <span>\n                2\n              </span>\n            </span>\n          </label>\n          <label\n            class=\"radio-inline \"\n          >\n            <span>\n              <input\n                aria-describedby=\"root_numberEnumRadio__error root_numberEnumRadio__description root_numberEnumRadio__help\"\n                id=\"root_numberEnumRadio-2\"\n                name=\"root_numberEnumRadio\"\n                type=\"radio\"\n                value=\"2\"\n              />\n              <span>\n                3\n              </span>\n            </span>\n          </label>\n        </div>\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-integer\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_integerRange\"\n        >\n          Integer range\n        </label>\n        <div\n          class=\"css-1vryedt\"\n        >\n          <div\n            class=\"css-nc7xvn\"\n          >\n            <input\n              id=\"root_integerRange\"\n              max=\"100\"\n              min=\"42\"\n              name=\"integerRange\"\n              placeholder=\"\"\n              type=\"range\"\n              uischema=\"[object Object]\"\n              value=\"52\"\n            />\n            <div>\n              52\n            </div>\n          </div>\n        </div>\n      </div>\n    </fieldset>\n  </div>\n  <noscript />\n</form>\n`;\n\nexports[`Form renders with primary button 1`] = `\n<form\n  class=\"css-yd7kx\"\n>\n  <div\n    class=\"form-group rjsf-field rjsf-field-object\"\n  >\n    <fieldset\n      id=\"root\"\n    >\n      <legend\n        id=\"root__title\"\n      >\n        Example form\n      </legend>\n      <div\n        class=\"field-description\"\n        id=\"root__description\"\n      >\n        A simple form example.\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-string\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_name\"\n        >\n          Full name\n          <span\n            class=\"required\"\n          >\n            *\n          </span>\n        </label>\n        <input\n          aria-describedby=\"root_name__error root_name__description root_name__help\"\n          class=\"form-control\"\n          id=\"root_name\"\n          label=\"Full name\"\n          name=\"root_name\"\n          placeholder=\"\"\n          required=\"\"\n          type=\"text\"\n          value=\"Chuck Norris\"\n        />\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-integer\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_age\"\n        >\n          Age\n        </label>\n        <input\n          aria-describedby=\"root_age__error root_age__description root_age__help\"\n          class=\"form-control\"\n          id=\"root_age\"\n          label=\"Age\"\n          name=\"root_age\"\n          placeholder=\"\"\n          type=\"number\"\n          value=\"75\"\n        />\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-string\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_bio\"\n        >\n          Bio\n        </label>\n        <textarea\n          aria-describedby=\"root_bio__error root_bio__description root_bio__help\"\n          class=\"form-control\"\n          id=\"root_bio\"\n          name=\"root_bio\"\n          placeholder=\"\"\n        >\n          Roundhouse kicking asses since 1940\n        </textarea>\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-string\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_password\"\n        >\n          Password\n        </label>\n        <input\n          aria-describedby=\"root_password__error root_password__description root_password__help\"\n          class=\"form-control\"\n          id=\"root_password\"\n          label=\"Password\"\n          name=\"root_password\"\n          placeholder=\"\"\n          type=\"password\"\n          value=\"noneed\"\n        />\n        <div\n          class=\"help-block\"\n          id=\"root_password__help\"\n        >\n          Hint: Make it strong!\n        </div>\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-array\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_multipleChoicesList\"\n        >\n          A multiple choices list\n        </label>\n        <div\n          class=\"checkboxes\"\n          id=\"root_multipleChoicesList\"\n        >\n          <div\n            class=\"checkbox \"\n          >\n            <label>\n              <span>\n                <input\n                  aria-describedby=\"root_multipleChoicesList__error root_multipleChoicesList__description root_multipleChoicesList__help\"\n                  id=\"root_multipleChoicesList-0\"\n                  name=\"root_multipleChoicesList\"\n                  type=\"checkbox\"\n                  value=\"0\"\n                />\n                <span>\n                  foo\n                </span>\n              </span>\n            </label>\n          </div>\n          <div\n            class=\"checkbox \"\n          >\n            <label>\n              <span>\n                <input\n                  aria-describedby=\"root_multipleChoicesList__error root_multipleChoicesList__description root_multipleChoicesList__help\"\n                  id=\"root_multipleChoicesList-1\"\n                  name=\"root_multipleChoicesList\"\n                  type=\"checkbox\"\n                  value=\"1\"\n                />\n                <span>\n                  bar\n                </span>\n              </span>\n            </label>\n          </div>\n          <div\n            class=\"checkbox \"\n          >\n            <label>\n              <span>\n                <input\n                  aria-describedby=\"root_multipleChoicesList__error root_multipleChoicesList__description root_multipleChoicesList__help\"\n                  id=\"root_multipleChoicesList-2\"\n                  name=\"root_multipleChoicesList\"\n                  type=\"checkbox\"\n                  value=\"2\"\n                />\n                <span>\n                  fuzz\n                </span>\n              </span>\n            </label>\n          </div>\n        </div>\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-number\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_numberEnum\"\n        >\n          Number enum\n        </label>\n        <div\n          class=\"css-18o3wl1-container\"\n          id=\"root_numberEnum\"\n        >\n          <span\n            class=\"css-1f43avz-a11yText-A11yText\"\n            id=\"react-select-3-live-region\"\n          />\n          <span\n            aria-atomic=\"false\"\n            aria-live=\"polite\"\n            aria-relevant=\"additions text\"\n            class=\"css-1f43avz-a11yText-A11yText\"\n            role=\"log\"\n          />\n          <div\n            class=\"css-10g0wlc-control\"\n          >\n            <div\n              class=\"css-1uzcsaf\"\n            >\n              <div\n                class=\"css-1m6ztbo-placeholder\"\n                id=\"react-select-3-placeholder\"\n              />\n              <div\n                class=\"css-fty6pr\"\n                data-value=\"\"\n              >\n                <input\n                  aria-activedescendant=\"\"\n                  aria-autocomplete=\"list\"\n                  aria-describedby=\"react-select-3-placeholder\"\n                  aria-expanded=\"false\"\n                  aria-haspopup=\"true\"\n                  aria-required=\"false\"\n                  autocapitalize=\"none\"\n                  autocomplete=\"off\"\n                  autocorrect=\"off\"\n                  class=\"\"\n                  id=\"react-select-3-input\"\n                  role=\"combobox\"\n                  spellcheck=\"false\"\n                  style=\"color: inherit; background: 0px; opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;\"\n                  tabindex=\"0\"\n                  type=\"text\"\n                  value=\"\"\n                />\n              </div>\n            </div>\n            <div\n              class=\"css-1wy0on6\"\n            >\n              <span\n                class=\"css-19norqf-indicatorSeparator\"\n              />\n              <div\n                aria-hidden=\"true\"\n                class=\"css-17vo4tq-indicatorContainer\"\n              >\n                <svg\n                  aria-hidden=\"true\"\n                  class=\"css-tj5bde-Svg\"\n                  focusable=\"false\"\n                  height=\"20\"\n                  viewBox=\"0 0 20 20\"\n                  width=\"20\"\n                >\n                  <path\n                    d=\"M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z\"\n                  />\n                </svg>\n              </div>\n            </div>\n          </div>\n          <input\n            name=\"numberEnum\"\n            type=\"hidden\"\n            value=\"\"\n          />\n        </div>\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-number\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_numberEnumRadio\"\n        >\n          Number enum\n        </label>\n        <div\n          class=\"field-radio-group\"\n          id=\"root_numberEnumRadio\"\n          role=\"radiogroup\"\n        >\n          <label\n            class=\"radio-inline \"\n          >\n            <span>\n              <input\n                aria-describedby=\"root_numberEnumRadio__error root_numberEnumRadio__description root_numberEnumRadio__help\"\n                id=\"root_numberEnumRadio-0\"\n                name=\"root_numberEnumRadio\"\n                type=\"radio\"\n                value=\"0\"\n              />\n              <span>\n                1\n              </span>\n            </span>\n          </label>\n          <label\n            class=\"radio-inline \"\n          >\n            <span>\n              <input\n                aria-describedby=\"root_numberEnumRadio__error root_numberEnumRadio__description root_numberEnumRadio__help\"\n                id=\"root_numberEnumRadio-1\"\n                name=\"root_numberEnumRadio\"\n                type=\"radio\"\n                value=\"1\"\n              />\n              <span>\n                2\n              </span>\n            </span>\n          </label>\n          <label\n            class=\"radio-inline \"\n          >\n            <span>\n              <input\n                aria-describedby=\"root_numberEnumRadio__error root_numberEnumRadio__description root_numberEnumRadio__help\"\n                id=\"root_numberEnumRadio-2\"\n                name=\"root_numberEnumRadio\"\n                type=\"radio\"\n                value=\"2\"\n              />\n              <span>\n                3\n              </span>\n            </span>\n          </label>\n        </div>\n      </div>\n      <div\n        class=\"form-group rjsf-field rjsf-field-integer\"\n      >\n        <label\n          class=\"control-label\"\n          for=\"root_integerRange\"\n        >\n          Integer range\n        </label>\n        <div\n          class=\"css-1vryedt\"\n        >\n          <div\n            class=\"css-nc7xvn\"\n          >\n            <input\n              id=\"root_integerRange\"\n              max=\"100\"\n              min=\"42\"\n              name=\"integerRange\"\n              placeholder=\"\"\n              type=\"range\"\n              uischema=\"[object Object]\"\n              value=\"52\"\n            />\n            <div>\n              52\n            </div>\n          </div>\n        </div>\n      </div>\n    </fieldset>\n  </div>\n  <div\n    class=\"css-q8f4aw\"\n  >\n    <button\n      class=\"css-1td9y62\"\n      type=\"submit\"\n    >\n      Custom button\n    </button>\n  </div>\n</form>\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/__snapshots__/Notification.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing\n\nexports[`Notification renders correctly 1`] = `\n<div\n  class=\"css-105dgur\"\n  type=\"info\"\n>\n  <span>\n    Message\n  </span>\n</div>\n`;\n\nexports[`Notification renders with props 1`] = `\n<div\n  class=\"css-105dgur\"\n  type=\"error\"\n>\n  <svg\n    fill=\"currentColor\"\n    height=\"1em\"\n    stroke=\"currentColor\"\n    stroke-width=\"0\"\n    viewBox=\"0 0 24 24\"\n    width=\"1em\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n  >\n    <path\n      d=\"M0 0h24v24H0z\"\n      fill=\"none\"\n    />\n    <path\n      d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z\"\n    />\n  </svg>\n  <span>\n    Message\n  </span>\n  <button>\n    <svg\n      fill=\"currentColor\"\n      height=\"1em\"\n      stroke=\"currentColor\"\n      stroke-width=\"0\"\n      viewBox=\"0 0 24 24\"\n      width=\"1em\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n    >\n      <path\n        d=\"M0 0h24v24H0z\"\n        fill=\"none\"\n      />\n      <path\n        d=\"M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"\n      />\n    </svg>\n  </button>\n</div>\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/__snapshots__/SegmentedControl.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing\n\nexports[`SegmentedControl renders correctly 1`] = `\n<div\n  class=\"css-rlakr\"\n>\n  <button\n    data-selected=\"true\"\n    value=\"Button1\"\n  >\n    Button1\n  </button>\n  <button\n    value=\"Button2\"\n  >\n    Button2\n  </button>\n  <button\n    value=\"Button3\"\n  >\n    Button3\n  </button>\n</div>\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/__snapshots__/Select.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing\n\nexports[`Select renders correctly 1`] = `\n<div\n  class=\"css-18o3wl1-container\"\n>\n  <span\n    class=\"css-1f43avz-a11yText-A11yText\"\n    id=\"react-select-2-live-region\"\n  />\n  <span\n    aria-atomic=\"false\"\n    aria-live=\"polite\"\n    aria-relevant=\"additions text\"\n    class=\"css-1f43avz-a11yText-A11yText\"\n    role=\"log\"\n  />\n  <div\n    class=\"css-10g0wlc-control\"\n  >\n    <div\n      class=\"css-1uzcsaf\"\n    >\n      <div\n        class=\"css-1m6ztbo-placeholder\"\n        id=\"react-select-2-placeholder\"\n      >\n        Select...\n      </div>\n      <div\n        class=\"css-fty6pr\"\n        data-value=\"\"\n      >\n        <input\n          aria-activedescendant=\"\"\n          aria-autocomplete=\"list\"\n          aria-describedby=\"react-select-2-placeholder\"\n          aria-expanded=\"false\"\n          aria-haspopup=\"true\"\n          autocapitalize=\"none\"\n          autocomplete=\"off\"\n          autocorrect=\"off\"\n          class=\"\"\n          id=\"react-select-2-input\"\n          role=\"combobox\"\n          spellcheck=\"false\"\n          style=\"color: inherit; background: 0px; opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;\"\n          tabindex=\"0\"\n          type=\"text\"\n          value=\"\"\n        />\n      </div>\n    </div>\n    <div\n      class=\"css-1wy0on6\"\n    >\n      <span\n        class=\"css-19norqf-indicatorSeparator\"\n      />\n      <div\n        aria-hidden=\"true\"\n        class=\"css-17vo4tq-indicatorContainer\"\n      >\n        <svg\n          aria-hidden=\"true\"\n          class=\"css-tj5bde-Svg\"\n          focusable=\"false\"\n          height=\"20\"\n          viewBox=\"0 0 20 20\"\n          width=\"20\"\n        >\n          <path\n            d=\"M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z\"\n          />\n        </svg>\n      </div>\n    </div>\n  </div>\n</div>\n`;\n\nexports[`Select renders with props 1`] = `\n<div\n  class=\"css-lk03f7-container\"\n>\n  <span\n    class=\"css-1f43avz-a11yText-A11yText\"\n    id=\"react-select-3-live-region\"\n  />\n  <span\n    aria-atomic=\"false\"\n    aria-live=\"polite\"\n    aria-relevant=\"additions text\"\n    class=\"css-1f43avz-a11yText-A11yText\"\n    role=\"log\"\n  />\n  <div\n    aria-disabled=\"true\"\n    class=\"css-10g0wlc-control\"\n  >\n    <div\n      class=\"css-6dn868\"\n    >\n      <div\n        class=\"css-7ef4eb-multiValue\"\n      >\n        <div\n          class=\"css-1eqzlh8\"\n        >\n          One\n        </div>\n        <div\n          aria-label=\"Remove One\"\n          class=\"css-13dqakm\"\n          role=\"button\"\n        >\n          <svg\n            aria-hidden=\"true\"\n            class=\"css-tj5bde-Svg\"\n            focusable=\"false\"\n            height=\"14\"\n            viewBox=\"0 0 20 20\"\n            width=\"14\"\n          >\n            <path\n              d=\"M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z\"\n            />\n          </svg>\n        </div>\n      </div>\n      <input\n        aria-activedescendant=\"\"\n        aria-autocomplete=\"list\"\n        aria-expanded=\"false\"\n        aria-haspopup=\"true\"\n        aria-readonly=\"true\"\n        class=\"css-1s80ejz-dummyInput-DummyInput\"\n        disabled=\"\"\n        id=\"react-select-3-input\"\n        inputmode=\"none\"\n        role=\"combobox\"\n        tabindex=\"0\"\n        value=\"\"\n      />\n    </div>\n    <div\n      class=\"css-1wy0on6\"\n    >\n      <div\n        aria-hidden=\"true\"\n        class=\"css-1x631db-loadingIndicator\"\n      >\n        <span\n          class=\"css-1icxkl9-LoadingDot\"\n        />\n        <span\n          class=\"css-1oazjx7-LoadingDot\"\n        />\n        <span\n          class=\"css-1wonz24-LoadingDot\"\n        />\n      </div>\n      <span\n        class=\"css-19norqf-indicatorSeparator\"\n      />\n      <div\n        aria-hidden=\"true\"\n        class=\"css-17vo4tq-indicatorContainer\"\n      >\n        <svg\n          aria-hidden=\"true\"\n          class=\"css-tj5bde-Svg\"\n          focusable=\"false\"\n          height=\"20\"\n          viewBox=\"0 0 20 20\"\n          width=\"20\"\n        >\n          <path\n            d=\"M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z\"\n          />\n        </svg>\n      </div>\n    </div>\n  </div>\n</div>\n`;\n\nexports[`Select should select another option 1`] = `\n<div\n  class=\"css-18o3wl1-container\"\n>\n  <span\n    class=\"css-1f43avz-a11yText-A11yText\"\n    id=\"react-select-4-live-region\"\n  />\n  <span\n    aria-atomic=\"false\"\n    aria-live=\"polite\"\n    aria-relevant=\"additions text\"\n    class=\"css-1f43avz-a11yText-A11yText\"\n    role=\"log\"\n  >\n    <span\n      id=\"aria-selection\"\n    />\n    <span\n      id=\"aria-focused\"\n    />\n    <span\n      id=\"aria-results\"\n    >\n      1 result available for search term two.\n    </span>\n    <span\n      id=\"aria-guidance\"\n    >\n      Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu.\n    </span>\n  </span>\n  <div\n    class=\"css-mjg7mv-control\"\n  >\n    <div\n      class=\"css-1uzcsaf\"\n    >\n      <div\n        class=\"css-vtduo5\"\n        data-value=\"two\"\n      >\n        <input\n          aria-activedescendant=\"react-select-4-option-1\"\n          aria-autocomplete=\"list\"\n          aria-controls=\"react-select-4-listbox\"\n          aria-describedby=\"react-select-4-placeholder\"\n          aria-expanded=\"true\"\n          aria-haspopup=\"true\"\n          autocapitalize=\"none\"\n          autocomplete=\"off\"\n          autocorrect=\"off\"\n          class=\"\"\n          id=\"react-select-4-input\"\n          role=\"combobox\"\n          spellcheck=\"false\"\n          style=\"color: inherit; background: 0px; opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;\"\n          tabindex=\"0\"\n          type=\"text\"\n          value=\"two\"\n        />\n      </div>\n    </div>\n    <div\n      class=\"css-1wy0on6\"\n    >\n      <span\n        class=\"css-19norqf-indicatorSeparator\"\n      />\n      <div\n        aria-hidden=\"true\"\n        class=\"css-17vo4tq-indicatorContainer\"\n      >\n        <svg\n          aria-hidden=\"true\"\n          class=\"css-tj5bde-Svg\"\n          focusable=\"false\"\n          height=\"20\"\n          viewBox=\"0 0 20 20\"\n          width=\"20\"\n        >\n          <path\n            d=\"M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z\"\n          />\n        </svg>\n      </div>\n    </div>\n  </div>\n  <div\n    class=\"css-sromc4-menu\"\n  >\n    <div\n      aria-multiselectable=\"false\"\n      class=\"css-12gthpx\"\n      id=\"react-select-4-listbox\"\n      role=\"listbox\"\n    >\n      <div\n        aria-disabled=\"false\"\n        aria-selected=\"false\"\n        class=\"css-1t6re7j-option\"\n        id=\"react-select-4-option-1\"\n        role=\"option\"\n        tabindex=\"-1\"\n      >\n        Two\n      </div>\n    </div>\n  </div>\n</div>\n`;\n\nexports[`Select shouldn't find any results 1`] = `\n<div\n  class=\"css-18o3wl1-container\"\n>\n  <span\n    class=\"css-1f43avz-a11yText-A11yText\"\n    id=\"react-select-5-live-region\"\n  />\n  <span\n    aria-atomic=\"false\"\n    aria-live=\"polite\"\n    aria-relevant=\"additions text\"\n    class=\"css-1f43avz-a11yText-A11yText\"\n    role=\"log\"\n  >\n    <span\n      id=\"aria-selection\"\n    />\n    <span\n      id=\"aria-focused\"\n    />\n    <span\n      id=\"aria-results\"\n    >\n      0 results available for search term text.\n    </span>\n    <span\n      id=\"aria-guidance\"\n    >\n      Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu.\n    </span>\n  </span>\n  <div\n    class=\"css-mjg7mv-control\"\n  >\n    <div\n      class=\"css-1uzcsaf\"\n    >\n      <div\n        class=\"css-vtduo5\"\n        data-value=\"text\"\n      >\n        <input\n          aria-activedescendant=\"\"\n          aria-autocomplete=\"list\"\n          aria-controls=\"react-select-5-listbox\"\n          aria-describedby=\"react-select-5-placeholder\"\n          aria-expanded=\"true\"\n          aria-haspopup=\"true\"\n          autocapitalize=\"none\"\n          autocomplete=\"off\"\n          autocorrect=\"off\"\n          class=\"\"\n          id=\"react-select-5-input\"\n          role=\"combobox\"\n          spellcheck=\"false\"\n          style=\"color: inherit; background: 0px; opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;\"\n          tabindex=\"0\"\n          type=\"text\"\n          value=\"text\"\n        />\n      </div>\n    </div>\n    <div\n      class=\"css-1wy0on6\"\n    >\n      <span\n        class=\"css-19norqf-indicatorSeparator\"\n      />\n      <div\n        aria-hidden=\"true\"\n        class=\"css-17vo4tq-indicatorContainer\"\n      >\n        <svg\n          aria-hidden=\"true\"\n          class=\"css-tj5bde-Svg\"\n          focusable=\"false\"\n          height=\"20\"\n          viewBox=\"0 0 20 20\"\n          width=\"20\"\n        >\n          <path\n            d=\"M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z\"\n          />\n        </svg>\n      </div>\n    </div>\n  </div>\n  <div\n    class=\"css-sromc4-menu\"\n  >\n    <div\n      aria-multiselectable=\"false\"\n      class=\"css-12gthpx\"\n      id=\"react-select-5-listbox\"\n      role=\"listbox\"\n    >\n      <div\n        class=\"css-1ab4lkd\"\n      >\n        No options\n      </div>\n    </div>\n  </div>\n</div>\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/__snapshots__/Slider.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing\n\nexports[`Slider renders correctly 1`] = `\n<div\n  class=\"css-20crcy\"\n>\n  <input\n    max=\"100\"\n    min=\"0\"\n    type=\"range\"\n    value=\"0\"\n  />\n</div>\n`;\n\nexports[`Slider renders with props 1`] = `\n<div\n  class=\"css-1cg3ohj\"\n  disabled=\"\"\n>\n  <label>\n    Hi\n     \n  </label>\n  <input\n    disabled=\"\"\n    max=\"10\"\n    min=\"1\"\n    type=\"range\"\n    value=\"5\"\n  />\n</div>\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/__snapshots__/Tabs.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing\n\nexports[`Tabs renders correctly 1`] = `\n<div\n  class=\"css-1q9755x\"\n>\n  <div\n    class=\"css-1rbphu7\"\n  >\n    <div>\n      <button\n        value=\"Tab1\"\n      >\n        Tab1\n      </button>\n      <button\n        value=\"Tab2\"\n      >\n        Tab2\n      </button>\n      <button\n        value=\"Tab3\"\n      >\n        Tab3\n      </button>\n    </div>\n  </div>\n</div>\n`;\n\nexports[`Tabs renders tabs without inner components 1`] = `\n<div\n  class=\"css-1q9755x\"\n>\n  <div\n    class=\"css-1rbphu7\"\n  >\n    <div>\n      <button\n        value=\"1\"\n      >\n        Tab1\n      </button>\n      <button\n        value=\"2\"\n      >\n        Tab2\n      </button>\n      <button\n        value=\"3\"\n      >\n        Tab3\n      </button>\n      <button\n        value=\"4\"\n      >\n        Tab4\n      </button>\n      <button\n        data-selected=\"true\"\n        value=\"5\"\n      >\n        Tab5\n      </button>\n      <button\n        value=\"6\"\n      >\n        Tab6\n      </button>\n      <button\n        value=\"7\"\n      >\n        Tab7\n      </button>\n      <button\n        value=\"8\"\n      >\n        Tab8\n      </button>\n      <button\n        value=\"9\"\n      >\n        Tab9\n      </button>\n      <button\n        value=\"10\"\n      >\n        Tab10\n      </button>\n    </div>\n  </div>\n</div>\n`;\n\nexports[`Tabs renders with props 1`] = `\n<div\n  class=\"css-1q9755x\"\n>\n  <div\n    class=\"css-1rbphu7\"\n  >\n    <div>\n      <button\n        value=\"Tab1\"\n      >\n        Tab1\n      </button>\n      <button\n        data-selected=\"true\"\n        value=\"Tab2\"\n      >\n        Tab2\n      </button>\n      <button\n        value=\"Tab3\"\n      >\n        Tab3\n      </button>\n    </div>\n  </div>\n  <div>\n    <div\n      style=\"display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; font-size: 22px;\"\n    >\n      Selected \n      Tab2\n    </div>\n  </div>\n</div>\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/test/__snapshots__/Toolbar.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing\n\nexports[`Toolbar renders correctly 1`] = `\n<div\n  class=\"css-1vb2bz\"\n>\n  <div\n    class=\"css-jg680o\"\n  >\n    <button\n      class=\"css-g2zi5\"\n    >\n      1\n    </button>\n  </div>\n  <div\n    class=\"css-t7c7u\"\n  />\n  <div\n    class=\"css-w6gvpm\"\n  />\n  <div\n    class=\"css-jg680o\"\n  >\n    <button\n      class=\"css-g2zi5\"\n    >\n      2\n    </button>\n  </div>\n</div>\n`;\n\nexports[`Toolbar renders with props 1`] = `\n<div\n  class=\"css-1wu4lza\"\n/>\n`;\n"
  },
  {
    "path": "packages/redux-devtools-ui/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\",\n    \"types\": [\"node\"],\n    \"skipLibCheck\": true\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-ui/tsconfig.test.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"types\": [\"jest\"]\n  },\n  \"include\": [\"src\", \"test\"]\n}\n"
  },
  {
    "path": "packages/redux-devtools-utils/CHANGELOG.md",
    "content": "# Change Log\n\n## 4.0.0\n\n### Major Changes\n\n- 6481386: Convert remaining packages to ESM\n\n### Patch Changes\n\n- Updated dependencies [804d6bd]\n- Updated dependencies [6481386]\n  - @redux-devtools/core@5.0.0\n  - @redux-devtools/serialize@1.0.0\n\n## 3.1.1\n\n### Patch Changes\n\n- Updated dependencies [91f21b2]\n  - @redux-devtools/core@4.1.1\n\n## 3.1.0\n\n### Patch Changes\n\n- Updated dependencies [6830118]\n  - @redux-devtools/core@4.1.0\n\n## 3.0.0\n\n### Patch Changes\n\n- Updated dependencies [decc035]\n  - @redux-devtools/core@4.0.0\n\n## 2.1.0\n\n### Minor Changes\n\n- 6fc18ed7: Add new Redux version to peer dependencies\n\n### Patch Changes\n\n- 7f5bddbd: Widen peer dependencies\n- Updated dependencies [7f5bddbd]\n- Updated dependencies [6fc18ed7]\n  - @redux-devtools/serialize@0.4.2\n  - @redux-devtools/core@3.14.0\n\n## 2.0.2\n\n### Patch Changes\n\n- 42531c50: Bump versions\n- Updated dependencies [42531c50]\n  - @redux-devtools/core@3.13.3\n\n## 2.0.1\n\n### Patch Changes\n\n- a55ba302: Fix peer dependencies on @redux-devtools/core\n- Updated dependencies [a55ba302]\n  - @redux-devtools/core@3.13.1\n\n## 2.0.0\n\n### Patch Changes\n\n- Updated dependencies [8a7eae4]\n  - @redux-devtools/core@3.13.0\n\n## 1.2.1\n\n### Patch Changes\n\n- Updated dependencies [4891bf6]\n  - @redux-devtools/core@3.12.0\n\n## [1.0.0-6](https://github.com/reduxjs/redux-devtools/compare/@redux-devtools/utils@1.0.0-5...@redux-devtools/utils@1.0.0-6) (2021-03-06)\n\n**Note:** Version bump only for package @redux-devtools/utils\n\n## 1.0.0-5 (2021-03-06)\n\n**Note:** Version bump only for package @redux-devtools/utils\n"
  },
  {
    "path": "packages/redux-devtools-utils/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 Mihail Diordiev\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/redux-devtools-utils/eslint.config.mjs",
    "content": "import eslintJs from '../../eslint.js.config.base.mjs';\nimport eslintTs from '../../eslint.ts.config.base.mjs';\nimport eslintTsJest from '../../eslint.ts.jest.config.base.mjs';\n\nexport default [\n  ...eslintJs,\n  ...eslintTs(import.meta.dirname),\n  ...eslintTsJest(import.meta.dirname),\n  {\n    ignores: ['lib'],\n  },\n];\n"
  },
  {
    "path": "packages/redux-devtools-utils/package.json",
    "content": "{\n  \"name\": \"@redux-devtools/utils\",\n  \"version\": \"4.0.0\",\n  \"description\": \"Reusable functions of Redux DevTools\",\n  \"homepage\": \"https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-utils\",\n  \"bugs\": {\n    \"url\": \"https://github.com/reduxjs/redux-devtools/issues\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)\",\n  \"files\": [\n    \"lib\",\n    \"src\"\n  ],\n  \"exports\": \"./lib/index.js\",\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/reduxjs/redux-devtools.git\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\",\n    \"prepack\": \"pnpm run clean && pnpm run build\",\n    \"prepublish\": \"pnpm run type-check && pnpm run lint\"\n  },\n  \"dependencies\": {\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"@redux-devtools/serialize\": \"workspace:^\",\n    \"@types/get-params\": \"^0.1.2\",\n    \"get-params\": \"^0.1.2\",\n    \"immutable\": \"^5.1.5\",\n    \"jsan\": \"^3.1.14\",\n    \"nanoid\": \"^5.1.6\",\n    \"redux\": \"^5.0.1\"\n  },\n  \"devDependencies\": {\n    \"@types/jsan\": \"^3.1.5\",\n    \"@types/node\": \"^24.12.0\",\n    \"rimraf\": \"^6.1.3\",\n    \"typescript\": \"~5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"@redux-devtools/core\": \"workspace:^\",\n    \"immutable\": \"^5.1.5\",\n    \"redux\": \"^4.0.0 || ^5.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/redux-devtools-utils/src/catchErrors.ts",
    "content": "const ERROR = '@@redux-devtools/ERROR';\n\nexport interface ErrorAction {\n  type: typeof ERROR;\n  message?: Event | string;\n  url?: string | undefined;\n  lineNo?: number | undefined;\n  columnNo?: number | undefined;\n  stack?: string;\n  error?: Error;\n  isFatal?: boolean;\n  sourceURL?: string;\n  line?: number;\n  column?: number;\n}\n\nexport function catchErrors(sendError: (errorAction: ErrorAction) => void) {\n  if (typeof window === 'object' && typeof window.onerror === 'object') {\n    window.onerror = function (message, url, lineNo, columnNo, error) {\n      const errorAction: ErrorAction = {\n        type: ERROR,\n        message,\n        url,\n        lineNo,\n        columnNo,\n      };\n      if (error && error.stack) errorAction.stack = error.stack;\n      sendError(errorAction);\n      return false;\n    };\n  } else if (typeof global !== 'undefined' && (global as any).ErrorUtils) {\n    (global as any).ErrorUtils.setGlobalHandler(\n      (error: Error, isFatal: boolean) => {\n        sendError({ type: ERROR, error, isFatal });\n      },\n    );\n  }\n\n  /* eslint-disable no-console */\n  if (\n    typeof console === 'object' &&\n    typeof console.error === 'function' &&\n    !(console as any).beforeRemotedev\n  ) {\n    (console as any).beforeRemotedev = console.error.bind(console);\n    console.error = function () {\n      let errorAction: ErrorAction = { type: ERROR };\n      // eslint-disable-next-line prefer-rest-params\n      const error = arguments[0];\n      errorAction.message = error.message ? error.message : error;\n      if (error.sourceURL) {\n        errorAction = {\n          ...errorAction,\n          sourceURL: error.sourceURL,\n          line: error.line,\n          column: error.column,\n        };\n      }\n      if (error.stack) errorAction.stack = error.stack;\n      sendError(errorAction);\n      // eslint-disable-next-line prefer-rest-params\n      (console as any).beforeRemotedev.apply(null, arguments);\n    };\n  }\n  /* eslint-enable no-console */\n}\n"
  },
  {
    "path": "packages/redux-devtools-utils/src/filters.ts",
    "content": "import { PerformAction } from '@redux-devtools/core';\nimport { Action } from 'redux';\n\nexport interface State {\n  actionsById: { [actionId: number]: PerformAction<Action<string>> };\n  computedStates: { state: unknown; error?: string }[];\n  stagedActionIds: number[];\n}\n\nexport const FilterState = {\n  DO_NOT_FILTER: 'DO_NOT_FILTER',\n  DENYLIST_SPECIFIC: 'DENYLIST_SPECIFIC',\n  ALLOWLIST_SPECIFIC: 'ALLOWLIST_SPECIFIC',\n};\n\nexport function arrToRegex(v: string | string[]) {\n  return typeof v === 'string' ? v : v.join('|');\n}\n\nfunction filterActions(\n  actionsById: { [actionId: number]: PerformAction<Action<string>> },\n  actionSanitizer: ((action: Action<string>, id: number) => Action) | undefined,\n) {\n  if (!actionSanitizer) return actionsById;\n  return Object.fromEntries(\n    Object.entries(actionsById).map(([actionId, action]) => [\n      actionId,\n      {\n        ...action,\n        action: actionSanitizer(action.action, actionId as unknown as number),\n      },\n    ]),\n  );\n}\n\nfunction filterStates(\n  computedStates: { state: unknown; error?: string | undefined }[],\n  stateSanitizer: (state: unknown, actionId: number) => unknown,\n) {\n  if (!stateSanitizer) return computedStates;\n  return computedStates.map((state, idx) => ({\n    ...state,\n    state: stateSanitizer(state.state, idx),\n  }));\n}\n\nfunction isArray(arg: unknown): arg is readonly unknown[] {\n  return Array.isArray(arg);\n}\n\ninterface Config {\n  /**\n   * @deprecated Use actionsDenylist instead.\n   */\n  readonly actionsBlacklist?: string | readonly string[];\n  /**\n   * @deprecated Use actionsAllowlist instead.\n   */\n  readonly actionsWhitelist?: string | readonly string[];\n  readonly actionsDenylist?: string | readonly string[];\n  readonly actionsAllowlist?: string | readonly string[];\n}\n\nexport interface LocalFilter {\n  allowlist: string | undefined;\n  denylist: string | undefined;\n}\n\nexport function getLocalFilter(config: Config): LocalFilter | undefined {\n  const denylist = config.actionsDenylist ?? config.actionsBlacklist;\n  const allowlist = config.actionsAllowlist ?? config.actionsWhitelist;\n  if (denylist || allowlist) {\n    return {\n      allowlist: isArray(allowlist) ? allowlist.join('|') : allowlist,\n      denylist: isArray(denylist) ? denylist.join('|') : denylist,\n    };\n  }\n  return undefined;\n}\n\ninterface DevToolsOptions {\n  filter?:\n    | typeof FilterState.DO_NOT_FILTER\n    | typeof FilterState.DENYLIST_SPECIFIC\n    | typeof FilterState.ALLOWLIST_SPECIFIC;\n  allowlist?: string;\n  denylist?: string;\n}\nfunction getDevToolsOptions() {\n  return (\n    (typeof window !== 'undefined' &&\n      (window as { devToolsOptions?: DevToolsOptions }).devToolsOptions) ||\n    {}\n  );\n}\n\nexport function isFiltered(\n  action: PerformAction<Action<string>> | Action<string>,\n  localFilter?: LocalFilter,\n) {\n  const { type } = (action as PerformAction<Action<string>>).action || action;\n  const opts = getDevToolsOptions();\n  if (\n    (!localFilter &&\n      opts.filter &&\n      opts.filter === FilterState.DO_NOT_FILTER) ||\n    (type && typeof type.match !== 'function')\n  )\n    return false;\n\n  const { allowlist, denylist } = localFilter || opts;\n  return (\n    // eslint-disable-next-line @typescript-eslint/prefer-regexp-exec\n    (allowlist && !type.match(allowlist)) ||\n    // eslint-disable-next-line @typescript-eslint/prefer-regexp-exec\n    (denylist && type.match(denylist))\n  );\n}\n\nexport function filterStagedActions(\n  state: State,\n  filters: LocalFilter | undefined,\n) {\n  if (!filters) return state;\n\n  const filteredStagedActionIds: number[] = [];\n  const filteredComputedStates: {\n    state: unknown;\n    error?: string | undefined;\n  }[] = [];\n\n  state.stagedActionIds.forEach((id, idx) => {\n    if (!isFiltered(state.actionsById[id], filters)) {\n      filteredStagedActionIds.push(id);\n      filteredComputedStates.push(state.computedStates[idx]);\n    }\n  });\n\n  return {\n    ...state,\n    stagedActionIds: filteredStagedActionIds,\n    computedStates: filteredComputedStates,\n  };\n}\n\nexport function filterState(\n  state: State,\n  type: string,\n  localFilter: LocalFilter | undefined,\n  stateSanitizer: ((state: unknown, actionId: number) => unknown) | undefined,\n  actionSanitizer: ((action: Action<string>, id: number) => Action) | undefined,\n  nextActionId: number,\n  predicate?: (currState: unknown, currAction: Action<string>) => boolean,\n) {\n  if (type === 'ACTION')\n    return !stateSanitizer ? state : stateSanitizer(state, nextActionId - 1);\n  else if (type !== 'STATE') return state;\n\n  const { filter } = getDevToolsOptions();\n  if (\n    predicate ||\n    localFilter ||\n    (filter && filter !== FilterState.DO_NOT_FILTER)\n  ) {\n    const filteredStagedActionIds: number[] = [];\n    const filteredComputedStates: {\n      state: unknown;\n      error?: string | undefined;\n    }[] = [];\n    const sanitizedActionsById:\n      | {\n          [id: number]: PerformAction<Action<string>>;\n        }\n      | undefined = actionSanitizer && {};\n    const { actionsById } = state;\n    const { computedStates } = state;\n\n    state.stagedActionIds.forEach((id, idx) => {\n      const liftedAction = actionsById[id];\n      const currAction = liftedAction.action;\n      const liftedState = computedStates[idx];\n      const currState = liftedState.state;\n      if (idx) {\n        if (predicate && !predicate(currState, currAction)) return;\n        if (isFiltered(currAction, localFilter)) return;\n      }\n\n      filteredStagedActionIds.push(id);\n      filteredComputedStates.push(\n        stateSanitizer\n          ? { ...liftedState, state: stateSanitizer(currState, idx) }\n          : liftedState,\n      );\n      if (actionSanitizer) {\n        sanitizedActionsById![id] = {\n          ...liftedAction,\n          action: actionSanitizer(currAction, id),\n        };\n      }\n    });\n\n    return {\n      ...state,\n      actionsById: sanitizedActionsById || actionsById,\n      stagedActionIds: filteredStagedActionIds,\n      computedStates: filteredComputedStates,\n    };\n  }\n\n  if (!stateSanitizer && !actionSanitizer) return state;\n  return {\n    ...state,\n    actionsById: filterActions(state.actionsById, actionSanitizer),\n    computedStates: filterStates(state.computedStates, stateSanitizer!),\n  };\n}\n"
  },
  {
    "path": "packages/redux-devtools-utils/src/importState.ts",
    "content": "import jsan from 'jsan';\nimport { immutableSerialize } from '@redux-devtools/serialize';\nimport { Action } from 'redux';\nimport type Immutable from 'immutable';\nimport { PerformAction } from '@redux-devtools/core';\n\ninterface State {\n  actionsById: { [actionId: number]: PerformAction<Action<string>> };\n  computedStates: { state: unknown; error?: string }[];\n  committedState?: unknown;\n}\n\nexport function importState(\n  state: string,\n  {\n    serialize,\n  }: {\n    serialize?: {\n      immutable?: typeof Immutable;\n      refs?: (new (data: any) => unknown)[] | null;\n      reviver?: (key: string, value: unknown) => unknown;\n    };\n  },\n) {\n  if (!state) return undefined;\n  let parse = jsan.parse;\n  if (serialize) {\n    if (serialize.immutable) {\n      parse = (v) =>\n        jsan.parse(\n          v,\n          immutableSerialize(serialize.immutable!, serialize.refs).reviver,\n        );\n    } else if (serialize.reviver) {\n      parse = (v) => jsan.parse(v, serialize.reviver);\n    }\n  }\n\n  let preloadedState: State | undefined;\n  let nextLiftedState: State = parse(state) as State;\n  if (\n    (\n      nextLiftedState as unknown as {\n        payload?: string;\n        preloadedState?: string;\n      }\n    ).payload\n  ) {\n    if (\n      (\n        nextLiftedState as unknown as {\n          payload: string;\n          preloadedState?: string;\n        }\n      ).preloadedState\n    )\n      preloadedState = parse(\n        (\n          nextLiftedState as unknown as {\n            payload: string;\n            preloadedState: string;\n          }\n        ).preloadedState,\n      ) as State;\n    nextLiftedState = parse(\n      (\n        nextLiftedState as unknown as {\n          payload: string;\n        }\n      ).payload,\n    ) as State;\n  }\n\n  return { nextLiftedState, preloadedState };\n}\n"
  },
  {
    "path": "packages/redux-devtools-utils/src/index.ts",
    "content": "import getParams from 'get-params';\nimport jsan from 'jsan';\nimport { nanoid } from 'nanoid/non-secure';\nimport { immutableSerialize } from '@redux-devtools/serialize';\nimport type Immutable from 'immutable';\nimport { Action, ActionCreator } from 'redux';\n\nexport function generateId(id: string | undefined) {\n  return id || nanoid(7);\n}\n\nexport interface ActionCreatorObject {\n  readonly name: string;\n  readonly func: ActionCreator<Action<string>>;\n  readonly args: readonly string[];\n}\n\nfunction flatTree(\n  obj: { [key: string]: ActionCreator<Action<string>> },\n  namespace = '',\n) {\n  let functions: ActionCreatorObject[] = [];\n  Object.keys(obj).forEach((key) => {\n    const prop = obj[key];\n    if (typeof prop === 'function') {\n      functions.push({\n        name: namespace + (key || prop.name || 'anonymous'),\n        func: prop,\n        args: getParams(prop),\n      });\n    } else if (typeof prop === 'object') {\n      functions = functions.concat(flatTree(prop, namespace + key + '.'));\n    }\n  });\n  return functions;\n}\n\nexport function getMethods(obj: unknown) {\n  if (typeof obj !== 'object') return undefined;\n  let functions:\n    | {\n        name: string;\n        args: string[];\n      }[]\n    | undefined;\n  let m: { [key: string]: (...args: any[]) => unknown } | undefined;\n  if ((obj as any).__proto__) m = (obj as any).__proto__.__proto__;\n  if (!m) m = obj as any;\n\n  Object.getOwnPropertyNames(m).forEach((key) => {\n    const propDescriptor = Object.getOwnPropertyDescriptor(m, key);\n    if (!propDescriptor || 'get' in propDescriptor || 'set' in propDescriptor)\n      return;\n    const prop = m![key];\n    if (typeof prop === 'function' && key !== 'constructor') {\n      if (!functions) functions = [];\n      functions.push({\n        name: key || prop.name || 'anonymous',\n        args: getParams(prop),\n      });\n    }\n  });\n  return functions;\n}\n\nexport function getActionsArray(actionCreators: {\n  [key: string]: ActionCreator<Action<string>>;\n}) {\n  if (Array.isArray(actionCreators)) return actionCreators;\n  return flatTree(actionCreators);\n}\n\nconst interpretArg = (arg: string): unknown =>\n  // eslint-disable-next-line @typescript-eslint/no-implied-eval\n  new Function('return ' + arg)();\n\nfunction evalArgs(inArgs: string[], restArgs: string): unknown[] {\n  const args = inArgs.map(interpretArg);\n  if (!restArgs) return args;\n  const rest = interpretArg(restArgs);\n  if (Array.isArray(rest)) return args.concat(...(rest as unknown[]));\n  throw new Error('rest must be an array');\n}\n\nexport function evalAction(\n  action: string | { args: string[]; rest: string; selected: number },\n  actionCreators: readonly ActionCreatorObject[],\n) {\n  if (typeof action === 'string') {\n    // eslint-disable-next-line @typescript-eslint/no-implied-eval\n    return new Function('return ' + action)();\n  }\n\n  const actionCreator = actionCreators[action.selected].func;\n  const args = evalArgs(action.args, action.rest);\n  return actionCreator(...args);\n}\n\nexport function evalMethod(\n  action: string | { args: string[]; rest: string; name: string },\n  obj: unknown,\n) {\n  if (typeof action === 'string') {\n    // eslint-disable-next-line @typescript-eslint/no-implied-eval\n    return new Function('return ' + action).call(obj);\n  }\n\n  const args = evalArgs(action.args, action.rest);\n  // eslint-disable-next-line @typescript-eslint/no-implied-eval\n  return new Function('args', `return this.${action.name}(args)`).apply(\n    obj,\n    args,\n  );\n}\n/* eslint-enable */\n\nfunction tryCatchStringify(obj: unknown) {\n  try {\n    return JSON.stringify(obj);\n  } catch (err) {\n    /* eslint-disable no-console */\n    if (process.env.NODE_ENV !== 'production')\n      console.log('Failed to stringify', err);\n    /* eslint-enable no-console */\n    return jsan.stringify(\n      obj,\n      null as unknown as undefined,\n      null as unknown as undefined,\n      {\n        circular: '[CIRCULAR]',\n      } as unknown as boolean,\n    );\n  }\n}\n\nexport function stringify(\n  obj: unknown,\n  serialize?:\n    | {\n        replacer?: (key: string, value: unknown) => unknown;\n        options?: unknown | boolean;\n      }\n    | true,\n) {\n  if (typeof serialize === 'undefined') {\n    return tryCatchStringify(obj);\n  }\n  if (serialize === true) {\n    return jsan.stringify(\n      obj,\n      function (key, value) {\n        if (value && typeof (value as any).toJS === 'function')\n          return (value as any).toJS();\n        return value;\n      },\n      null as unknown as undefined,\n      true,\n    );\n  }\n  return jsan.stringify(\n    obj,\n    serialize.replacer,\n    null as unknown as undefined,\n    serialize.options as boolean,\n  );\n}\n\nexport function getSeralizeParameter(\n  config: {\n    serialize?:\n      | {\n          immutable?: typeof Immutable;\n          refs?: (new (data: any) => unknown)[] | null;\n          replacer?: (key: string, value: unknown) => unknown;\n          options?: unknown | boolean;\n        }\n      | boolean;\n  },\n  param: string,\n):\n  | {\n      replacer?: (key: string, value: unknown) => unknown;\n      options: unknown | boolean;\n    }\n  | undefined {\n  const serialize = config.serialize;\n  if (serialize) {\n    if (serialize === true) return { options: true };\n    if (serialize.immutable) {\n      return {\n        replacer: immutableSerialize(serialize.immutable, serialize.refs)\n          .replacer,\n        options: serialize.options || true,\n      };\n    }\n    if (!serialize.replacer) return { options: serialize.options };\n    return { replacer: serialize.replacer, options: serialize.options || true };\n  }\n\n  const value = (\n    config as {\n      [param: string]: {\n        replacer?: (key: string, value: unknown) => unknown;\n        options: unknown | boolean;\n      };\n    }\n  )[param];\n  if (typeof value === 'undefined') return undefined;\n  // eslint-disable-next-line no-console\n  console.warn(\n    `\\`${param}\\` parameter for Redux DevTools Extension is deprecated. Use \\`serialize\\` parameter instead:` +\n      ' https://github.com/zalmoxisus/redux-devtools-extension/releases/tag/v2.12.1',\n  );\n\n  return value;\n}\n\nexport function getStackTrace(\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  config: { trace?: () => {}; traceLimit: number },\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n  toExcludeFromTrace?: Function | undefined,\n) {\n  if (!config.trace) return undefined;\n  if (typeof config.trace === 'function') return config.trace();\n\n  let stack;\n  let extraFrames = 0;\n  let prevStackTraceLimit;\n  const traceLimit = config.traceLimit;\n  const error = Error();\n  if (Error.captureStackTrace) {\n    if (Error.stackTraceLimit < traceLimit) {\n      prevStackTraceLimit = Error.stackTraceLimit;\n      Error.stackTraceLimit = traceLimit;\n    }\n    Error.captureStackTrace(error, toExcludeFromTrace);\n  } else {\n    extraFrames = 3;\n  }\n  stack = error.stack;\n  if (prevStackTraceLimit) Error.stackTraceLimit = prevStackTraceLimit;\n  if (\n    extraFrames ||\n    typeof Error.stackTraceLimit !== 'number' ||\n    Error.stackTraceLimit > traceLimit\n  ) {\n    // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n    const frames = stack!.split('\\n');\n    if (frames.length > traceLimit) {\n      stack = frames\n        .slice(0, traceLimit + extraFrames + (frames[0] === 'Error' ? 1 : 0))\n        .join('\\n');\n    }\n  }\n  return stack;\n}\n\nexport * from './catchErrors.js';\nexport * from './filters.js';\nexport * from './importState.js';\n"
  },
  {
    "path": "packages/redux-devtools-utils/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.esm.react.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"lib\",\n    \"types\": [\"node\"]\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "patches/@dnd-kit__core.patch",
    "content": "diff --git a/dist/components/Accessibility/Accessibility.d.ts b/dist/components/Accessibility/Accessibility.d.ts\nindex bb8c25b3e818b31da14a1dc64c7d8cc4ad2c1b2f..dc8a50037b90a7a4044d54f2abdf58d1b3dc4bd3 100644\n--- a/dist/components/Accessibility/Accessibility.d.ts\n+++ b/dist/components/Accessibility/Accessibility.d.ts\n@@ -6,5 +6,5 @@ interface Props {\n     screenReaderInstructions?: ScreenReaderInstructions;\n     hiddenTextDescribedById: string;\n }\n-export declare function Accessibility({ announcements, container, hiddenTextDescribedById, screenReaderInstructions, }: Props): JSX.Element | null;\n+export declare function Accessibility({ announcements, container, hiddenTextDescribedById, screenReaderInstructions, }: Props): React.JSX.Element | null;\n export {};\ndiff --git a/dist/components/DragOverlay/DragOverlay.d.ts b/dist/components/DragOverlay/DragOverlay.d.ts\nindex 36fc7a419fac52cbe265c90106cddc43fe95dcb8..e98ba4a1b81a8266d2b9aa657d6a79f8b4176bb1 100644\n--- a/dist/components/DragOverlay/DragOverlay.d.ts\n+++ b/dist/components/DragOverlay/DragOverlay.d.ts\n@@ -5,7 +5,7 @@ import type { DropAnimation } from './hooks';\n export interface Props extends Pick<PositionedOverlayProps, 'adjustScale' | 'children' | 'className' | 'style' | 'transition'> {\n     dropAnimation?: DropAnimation | null | undefined;\n     modifiers?: Modifiers;\n-    wrapperElement?: keyof JSX.IntrinsicElements;\n+    wrapperElement?: keyof React.JSX.IntrinsicElements;\n     zIndex?: number;\n }\n-export declare const DragOverlay: React.MemoExoticComponent<({ adjustScale, children, dropAnimation: dropAnimationConfig, style, transition, modifiers, wrapperElement, className, zIndex, }: Props) => JSX.Element>;\n+export declare const DragOverlay: React.MemoExoticComponent<({ adjustScale, children, dropAnimation: dropAnimationConfig, style, transition, modifiers, wrapperElement, className, zIndex, }: Props) => React.JSX.Element>;\ndiff --git a/dist/components/DragOverlay/components/AnimationManager/AnimationManager.d.ts b/dist/components/DragOverlay/components/AnimationManager/AnimationManager.d.ts\nindex 8099a21266bdc99774a36a536428957338c4df41..1022ed4621ed50172909fae7ea695fb78a514091 100644\n--- a/dist/components/DragOverlay/components/AnimationManager/AnimationManager.d.ts\n+++ b/dist/components/DragOverlay/components/AnimationManager/AnimationManager.d.ts\n@@ -5,4 +5,4 @@ export interface Props {\n     animation: Animation;\n     children: React.ReactElement | null;\n }\n-export declare function AnimationManager({ animation, children }: Props): JSX.Element;\n+export declare function AnimationManager({ animation, children }: Props): React.JSX.Element;\ndiff --git a/dist/components/DragOverlay/components/NullifiedContextProvider/NullifiedContextProvider.d.ts b/dist/components/DragOverlay/components/NullifiedContextProvider/NullifiedContextProvider.d.ts\nindex cae101110ecb6fdabf90e0fd5018fe1e13512230..c8b9f458b41952bbde8549f0a29d32c4eb2d75a3 100644\n--- a/dist/components/DragOverlay/components/NullifiedContextProvider/NullifiedContextProvider.d.ts\n+++ b/dist/components/DragOverlay/components/NullifiedContextProvider/NullifiedContextProvider.d.ts\n@@ -2,5 +2,5 @@ import React from 'react';\n interface Props {\n     children: React.ReactNode;\n }\n-export declare function NullifiedContextProvider({ children }: Props): JSX.Element;\n+export declare function NullifiedContextProvider({ children }: Props): React.JSX.Element;\n export {};\ndiff --git a/dist/components/DragOverlay/components/PositionedOverlay/PositionedOverlay.d.ts b/dist/components/DragOverlay/components/PositionedOverlay/PositionedOverlay.d.ts\nindex 59dba0b1ca8e7b9fed4ea85036c8ad5c0e92caa6..badcc14baa5c99a4a16e6bcf47344deee88ae194 100644\n--- a/dist/components/DragOverlay/components/PositionedOverlay/PositionedOverlay.d.ts\n+++ b/dist/components/DragOverlay/components/PositionedOverlay/PositionedOverlay.d.ts\n@@ -3,7 +3,7 @@ import type { Transform } from '@dnd-kit/utilities';\n import type { ClientRect, UniqueIdentifier } from '../../../../types';\n declare type TransitionGetter = (activatorEvent: Event | null) => React.CSSProperties['transition'] | undefined;\n export interface Props {\n-    as: keyof JSX.IntrinsicElements;\n+    as: keyof React.JSX.IntrinsicElements;\n     activatorEvent: Event | null;\n     adjustScale?: boolean;\n     children?: React.ReactNode;\n"
  },
  {
    "path": "patches/@dnd-kit__sortable.patch",
    "content": "diff --git a/dist/components/SortableContext.d.ts b/dist/components/SortableContext.d.ts\nindex 718e8db4aa98759ac82b151650c15568d9a9f538..98d5b11a96d27f1f094bf3aeedc889e2c7325c93 100644\n--- a/dist/components/SortableContext.d.ts\n+++ b/dist/components/SortableContext.d.ts\n@@ -22,5 +22,5 @@ interface ContextDescriptor {\n     strategy: SortingStrategy;\n }\n export declare const Context: React.Context<ContextDescriptor>;\n-export declare function SortableContext({ children, id, items: userDefinedItems, strategy, disabled: disabledProp, }: Props): JSX.Element;\n+export declare function SortableContext({ children, id, items: userDefinedItems, strategy, disabled: disabledProp, }: Props): React.JSX.Element;\n export {};\n"
  },
  {
    "path": "patches/redux-persist.patch",
    "content": "diff --git a/CHANGELOG.md b/CHANGELOG.md\ndeleted file mode 100644\nindex 7e3bce49f30e7027c2688e7bb50429422213e576..0000000000000000000000000000000000000000\ndiff --git a/package.json b/package.json\nindex 6ce8011287adc33a92b206f3926702f7182e933c..0b4383f21d9800f31116c4aef95abefdf5e740c5 100644\n--- a/package.json\n+++ b/package.json\n@@ -5,6 +5,16 @@\n   \"main\": \"lib/index.js\",\n   \"module\": \"es/index.js\",\n   \"types\": \"./types/index.d.ts\",\n+  \"exports\": {\n+    \".\": {\n+      \"types\": \"./types/index.d.ts\",\n+      \"default\": \"./lib/index.js\"\n+    },\n+    \"./integration/react\": {\n+      \"types\": \"./types/integration/react.d.ts\",\n+      \"default\": \"./lib/integration/react.js\"\n+    }\n+  },\n   \"repository\": \"rt2zz/redux-persist\",\n   \"files\": [\n     \"es\",\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "packages:\n  - extension\n  - packages/*\n  - packages/d3-state-visualizer/examples/tree\n  - packages/react-dock/demo\n  - packages/react-json-tree/examples\n  - packages/redux-devtools/examples/counter\n  - packages/redux-devtools/examples/todomvc\n  - packages/redux-devtools-inspector-monitor/demo\n  - packages/redux-devtools-inspector-monitor-test-tab/demo\n  - packages/redux-devtools-rtk-query-monitor/demo\n  - packages/redux-devtools-slider-monitor/examples/todomvc\n\nonlyBuiltDependencies:\n  - '@apollo/protobufjs'\n  - '@swc/core'\n  - chromedriver\n  - electron\n  - esbuild\n  - msw\n  - sqlite3\n  - unrs-resolver\n\npatchedDependencies:\n  '@dnd-kit/core': patches/@dnd-kit__core.patch\n  '@dnd-kit/sortable': patches/@dnd-kit__sortable.patch\n  redux-persist: patches/redux-persist.patch\n"
  },
  {
    "path": "renovate.json",
    "content": "{\n  \"extends\": [\n    \"config:recommended\",\n    \"group:allNonMajor\",\n    \":maintainLockFilesWeekly\"\n  ],\n  \"rangeStrategy\": \"bump\",\n  \"postUpdateOptions\": [\"pnpmDedupe\"],\n  \"rebaseWhen\": \"conflicted\",\n  \"ignorePaths\": [\n    \"**/node_modules/**\",\n    \"extension/examples/**\",\n    \"packages/redux-devtools-remote/examples/**\"\n  ],\n  \"packageRules\": [\n    {\n      \"matchPackageNames\": [\"node\"],\n      \"enabled\": false\n    },\n    {\n      \"matchPackageNames\": [\"typescript\"],\n      \"matchUpdateTypes\": [\"major\", \"minor\"],\n      \"groupName\": \"typescript\"\n    },\n    {\n      \"matchPackageNames\": [\"source-map\", \"@types/source-map\"],\n      \"groupName\": \"source-map\"\n    },\n    {\n      \"matchPackageNames\": [\"msw\"],\n      \"groupName\": \"msw\"\n    },\n    {\n      \"matchPackageNames\": [\n        \"redux\",\n        \"redux-thunk\",\n        \"react-redux\",\n        \"@reduxjs/toolkit\",\n        \"@types/redux-logger\"\n      ],\n      \"matchUpdateTypes\": [\"major\"],\n      \"groupName\": \"redux\"\n    },\n    {\n      \"matchPackageNames\": [\"@types/redux-logger\"],\n      \"groupName\": \"redux\"\n    }\n  ]\n}\n"
  },
  {
    "path": "tsconfig.base.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es2020\",\n    \"moduleResolution\": \"bundler\",\n    \"declaration\": true,\n    \"strict\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"types\": []\n  }\n}\n"
  },
  {
    "path": "tsconfig.esm.base.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es2020\",\n    \"module\": \"node16\",\n    \"declaration\": true,\n    \"strict\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"types\": [],\n    \"isolatedModules\": true\n  }\n}\n"
  },
  {
    "path": "tsconfig.esm.react.base.json",
    "content": "{\n  \"extends\": \"./tsconfig.esm.base.json\",\n  \"compilerOptions\": {\n    \"jsx\": \"react\"\n  }\n}\n"
  },
  {
    "path": "tsconfig.react.base.json",
    "content": "{\n  \"extends\": \"./tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"jsx\": \"react\"\n  }\n}\n"
  }
]