├── .babelrc ├── .circleci └── config.yml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── LICENSE ├── README.md ├── package.json ├── renovate.json ├── rollup.config.js ├── src ├── index.ts └── plugins │ └── track-global-errors.ts ├── tsconfig.json ├── wallaby.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-typescript"], 3 | "plugins": ["@babel/plugin-proposal-class-properties"] 4 | } 5 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Javascript Node CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details 4 | # 5 | 6 | defaults: &defaults 7 | docker: 8 | - image: circleci/node:10.17 9 | working_directory: ~/repo 10 | 11 | version: 2 12 | jobs: 13 | setup: 14 | <<: *defaults 15 | steps: 16 | - checkout 17 | - restore_cache: 18 | name: Restore node modules 19 | keys: 20 | - v1-dependencies-{{ checksum "package.json" }} 21 | # fallback to using the latest cache if no exact match is found 22 | - v1-dependencies- 23 | - run: 24 | name: Install dependencies 25 | command: yarn install 26 | - save_cache: 27 | name: Save node modules 28 | paths: 29 | - node_modules 30 | key: v1-dependencies-{{ checksum "package.json" }} 31 | 32 | tests: 33 | <<: *defaults 34 | steps: 35 | - checkout 36 | - restore_cache: 37 | name: Restore node modules 38 | keys: 39 | - v1-dependencies-{{ checksum "package.json" }} 40 | # fallback to using the latest cache if no exact match is found 41 | - v1-dependencies- 42 | - run: 43 | name: Run lint 44 | command: yarn ci:lint 45 | - run: 46 | name: Run tests 47 | command: yarn ci:test 48 | 49 | build: 50 | <<: *defaults 51 | steps: 52 | - checkout 53 | - restore_cache: 54 | name: Restore node modules 55 | keys: 56 | - v1-dependencies-{{ checksum "package.json" }} 57 | # fallback to using the latest cache if no exact match is found 58 | - v1-dependencies- 59 | - run: 60 | name: Run Build 61 | command: yarn build 62 | - save_cache: 63 | name: Save node modules 64 | paths: 65 | - dist 66 | key: v1-build-{{ .Branch }}-{{ .Revision }} 67 | 68 | publish: 69 | <<: *defaults 70 | steps: 71 | - checkout 72 | - run: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc 73 | - restore_cache: 74 | name: Restore node modules 75 | keys: 76 | - v1-dependencies-{{ checksum "package.json" }} 77 | # fallback to using the latest cache if no exact match is found 78 | - v1-dependencies- 79 | - restore_cache: 80 | name: Restore build 81 | keys: 82 | - v1-build-{{ .Branch }}-{{ .Revision }} 83 | - run: 84 | name: Publish to NPM 85 | command: yarn ci:publish 86 | 87 | workflows: 88 | version: 2 89 | test_and_release: 90 | jobs: 91 | - setup 92 | - build: 93 | requires: 94 | - setup 95 | - publish: 96 | requires: 97 | - build 98 | filters: 99 | branches: 100 | only: 101 | - master 102 | - next 103 | - beta 104 | - alpha 105 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | coverage 4 | .nyc_output 5 | dist 6 | yarn-error.log 7 | .idea 8 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/.vscode 2 | **/android 3 | **/build 4 | **/compiled 5 | **/dist 6 | **/ios 7 | **/package.json 8 | **/release 9 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "semi": false, 4 | "trailingComma": "es5" 5 | } 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 - 3016 Infinite Red LLC. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [!WARNING] 2 | > Development has moved been out of this repository. Look for current development at https://github.com/infinitered/reactotron. 3 | 4 | # reactotron-react-js 5 | 6 | A development tool to explore, inspect, and diagnosis your React DOM/JS apps. 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reactotron-react-js", 3 | "version": "2.1.1", 4 | "description": "A development tool to explore, inspect, and diagnose your React JS/DOM apps.", 5 | "author": "Infinite Red", 6 | "license": "MIT", 7 | "bugs": { 8 | "url": "https://github.com/infinitered/reactotron/issues" 9 | }, 10 | "homepage": "https://github.com/infinitered/reactotron-react-js", 11 | "repository": "https://github.com/infinitered/reactotron-react-js", 12 | "files": [ 13 | "dist", 14 | "LICENSE", 15 | "README.md", 16 | "reactotron-react-js.d.ts" 17 | ], 18 | "main": "dist/index.js", 19 | "types": "./dist/types/index.d.ts", 20 | "scripts": { 21 | "test": "jest", 22 | "test:watch": "jest --watch --notify", 23 | "format": "prettier --write {**,.}/*.ts", 24 | "build": "npm-run-all clean tsc compile", 25 | "build:dev": "npm-run-all clean tsc compile:dev", 26 | "clean": "trash dist", 27 | "lint": "eslint src --ext .ts,.tsx", 28 | "compile": "NODE_ENV=production rollup -c", 29 | "compile:dev": "NODE_ENV=development rollup -c", 30 | "tsc": "tsc", 31 | "ci:lint": "yarn lint", 32 | "ci:test": "yarn test", 33 | "ci:publish": "yarn semantic-release", 34 | "semantic-release": "semantic-release" 35 | }, 36 | "dependencies": { 37 | "reactotron-core-client": "2.8.9", 38 | "stacktrace-js": "2.0.1" 39 | }, 40 | "devDependencies": { 41 | "@babel/core": "7.16.0", 42 | "@babel/plugin-proposal-class-properties": "7.16.0", 43 | "@babel/preset-env": "7.16.4", 44 | "@babel/preset-typescript": "7.16.0", 45 | "@semantic-release/git": "8.0.0", 46 | "@typescript-eslint/eslint-plugin": "4.33.0", 47 | "@typescript-eslint/parser": "4.33.0", 48 | "@types/react": "17.0.37", 49 | "babel-eslint": "10.1.0", 50 | "babel-jest": "27.4.2", 51 | "eslint": "7.32.0", 52 | "eslint-config-prettier": "8.3.0", 53 | "eslint-config-standard": "16.0.3", 54 | "eslint-plugin-import": "2.25.3", 55 | "eslint-plugin-node": "11.1.0", 56 | "eslint-plugin-promise": "5.2.0", 57 | "eslint-plugin-standard": "4.1.0", 58 | "jest": "27.4.3", 59 | "npm-run-all": "4.1.5", 60 | "prettier": "2.5.0", 61 | "rollup": "2.60.2", 62 | "rollup-plugin-babel": "4.4.0", 63 | "rollup-plugin-babel-minify": "10.0.0", 64 | "rollup-plugin-filesize": "9.1.1", 65 | "rollup-plugin-node-resolve": "5.2.0", 66 | "rollup-plugin-replace": "2.2.0", 67 | "rollup-plugin-resolve": "0.0.1-predev.1", 68 | "semantic-release": "16.0.4", 69 | "trash-cli": "4.0.0", 70 | "ts-jest": "27.0.7", 71 | "typescript": "4.5.2" 72 | }, 73 | "eslintConfig": { 74 | "parser": "@typescript-eslint/parser", 75 | "extends": [ 76 | "plugin:@typescript-eslint/recommended", 77 | "standard", 78 | "prettier" 79 | ], 80 | "parserOptions": { 81 | "ecmaFeatures": { 82 | "jsx": true 83 | }, 84 | "project": "./tsconfig.json" 85 | }, 86 | "plugins": [ 87 | "@typescript-eslint" 88 | ], 89 | "globals": { 90 | "__DEV__": false, 91 | "jasmine": false, 92 | "beforeAll": false, 93 | "afterAll": false, 94 | "beforeEach": false, 95 | "afterEach": false, 96 | "test": false, 97 | "expect": false, 98 | "describe": false, 99 | "jest": false, 100 | "it": false 101 | }, 102 | "rules": { 103 | "no-unused-vars": 0, 104 | "no-undef": 0, 105 | "space-before-function-paren": 0, 106 | "@typescript-eslint/indent": 0, 107 | "@typescript-eslint/explicit-member-accessibility": 0, 108 | "@typescript-eslint/explicit-function-return-type": 0, 109 | "@typescript-eslint/no-explicit-any": 0, 110 | "@typescript-eslint/no-object-literal-type-assertion": 0, 111 | "@typescript-eslint/no-empty-interface": 0, 112 | "@typescript-eslint/no-var-requires": 0, 113 | "@typescript-eslint/member-delimiter-style": 0 114 | } 115 | }, 116 | "jest": { 117 | "preset": "ts-jest", 118 | "testEnvironment": "node", 119 | "testMatch": [ 120 | "**/*.test.ts" 121 | ] 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["config:base"], 3 | "packageRules": [ 4 | { 5 | "depTypeList": ["devDependencies"], 6 | "automerge": true, 7 | "semanticCommits": true 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import resolve from "rollup-plugin-node-resolve" 2 | import babel from "rollup-plugin-babel" 3 | import replace from "rollup-plugin-replace" 4 | import filesize from "rollup-plugin-filesize" 5 | import minify from "rollup-plugin-babel-minify" 6 | 7 | const reactotronReactJsVersion = require("./package.json").version 8 | 9 | export default { 10 | input: "src/index.ts", 11 | output: { 12 | file: "dist/index.js", 13 | format: "cjs", 14 | exports: "named" 15 | }, 16 | plugins: [ 17 | resolve({ extensions: [".ts"] }), 18 | replace({ 19 | REACTOTRON_REACT_JS_VERSION: reactotronReactJsVersion, 20 | }), 21 | babel({ extensions: [".ts"], runtimeHelpers: true }), 22 | process.env.NODE_ENV === "production" 23 | ? minify({ 24 | comments: false, 25 | }) 26 | : null, 27 | filesize(), 28 | ], 29 | external: ["stacktrace-js", "reactotron-core-client"], 30 | } 31 | 32 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { createClient } from "reactotron-core-client" 2 | import trackGlobalErrors from "./plugins/track-global-errors" 3 | 4 | export { trackGlobalErrors } 5 | 6 | // --------------------- 7 | // DEFAULT CONFIGURATION 8 | // --------------------- 9 | 10 | const REACTOTRON_ASYNC_CLIENT_ID = "@REACTOTRON/clientId" 11 | 12 | function isBrowser() { 13 | return typeof window !== 'undefined' 14 | } 15 | 16 | /** 17 | * Safely get some information out the the window.navigator. 18 | * 19 | * @param {string} name The property to get. 20 | */ 21 | function getNavigatorProperty(name) { 22 | if (!name) return undefined 23 | if (!isBrowser()) return undefined 24 | if (!window.navigator && typeof window.navigator !== "object") return undefined 25 | return window.navigator[name] 26 | } 27 | 28 | const DEFAULTS = { 29 | createSocket: path => new WebSocket(path), // eslint-disable-line 30 | host: "localhost", 31 | port: 9090, 32 | name: "React JS App", 33 | client: {}, 34 | getClientId: () => { 35 | return Promise.resolve(localStorage.getItem(REACTOTRON_ASYNC_CLIENT_ID)) 36 | }, 37 | setClientId: (clientId: any) => { 38 | localStorage.setItem(REACTOTRON_ASYNC_CLIENT_ID, clientId) 39 | return Promise.resolve() 40 | }, 41 | }; 42 | 43 | if (isBrowser()) { 44 | DEFAULTS.client = { 45 | reactotronLibraryName: "reactotron-react-js", 46 | reactotronLibraryVersion: "REACTOTRON_REACT_JS_VERSION", 47 | platform: "browser", 48 | platformVersion: getNavigatorProperty("platform"), 49 | userAgent: getNavigatorProperty("userAgent"), 50 | screenWidth: (screen && screen.width) || undefined, 51 | screenHeight: (screen && screen.height) || undefined, 52 | screenScale: (window && window.devicePixelRatio) || 1, 53 | windowWidth: (window && window.innerWidth) || undefined, 54 | windowHeight: (window && window.innerHeight) || undefined, 55 | } 56 | } 57 | 58 | // ----------- 59 | // HERE WE GO! 60 | // ----------- 61 | // Create the default reactotron. 62 | export default createClient(DEFAULTS) 63 | -------------------------------------------------------------------------------- /src/plugins/track-global-errors.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Provides a global error handler to report errors with sourcemap lookup. 3 | */ 4 | import StackTrace from "stacktrace-js" 5 | 6 | // what to say whe we can't resolve source maps 7 | const CANNOT_RESOLVE_ERROR = 8 | 'Unable to resolve error. Either support CORS by changing webpack\'s devtool to "source-map" or run in offline mode.' 9 | 10 | // defaults 11 | const PLUGIN_DEFAULTS = { 12 | offline: false, // true = don't do source maps lookup cross domain 13 | } 14 | 15 | // our plugin entry point 16 | export default options => reactotron => { 17 | // setup configuration 18 | const config = Object.assign({}, PLUGIN_DEFAULTS, options || {}) 19 | 20 | // holds the previous window.onerror when needed 21 | let swizzledOnError = null 22 | let isSwizzled = false 23 | 24 | // the functionality of our window.onerror. 25 | // we could have used window.addEventListener("error", ...) but that doesn't work on all browsers 26 | function windowOnError(msg, file, line, col, error) { 27 | // resolve the stack trace 28 | StackTrace.fromError(error, { offline: config.offline }) 29 | // then try to send it up to the server 30 | .then(stackFrames => reactotron.error(msg, stackFrames)) 31 | // can't resolve, well, let the user know, but still upload something sane 32 | .catch(resolvingError => 33 | reactotron.error({ 34 | message: CANNOT_RESOLVE_ERROR, 35 | original: { msg, file, line, col, error }, 36 | resolvingError, 37 | }) 38 | ) 39 | 40 | // call back the previous window.onerror if we have one 41 | if (swizzledOnError) { 42 | swizzledOnError(msg, file, line, col, error) 43 | } 44 | } 45 | 46 | // swizzles window.onerror dropping in our new one 47 | function trackGlobalErrors() { 48 | if (isSwizzled) return 49 | swizzledOnError = window.onerror 50 | window.onerror = windowOnError 51 | isSwizzled = true 52 | } 53 | 54 | // restore the original 55 | function untrackGlobalErrors() { 56 | if (!swizzledOnError) return 57 | window.onerror = swizzledOnError 58 | isSwizzled = false 59 | } 60 | 61 | // auto start this 62 | trackGlobalErrors() 63 | 64 | // the reactotron plugin interface 65 | return { 66 | // attach these functions to the Reactotron 67 | features: { 68 | trackGlobalErrors, 69 | untrackGlobalErrors, 70 | }, 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": false, 4 | "declaration": true, 5 | "declarationDir": "dist/types", 6 | "emitDeclarationOnly": true, 7 | "emitDecoratorMetadata": true, 8 | "allowSyntheticDefaultImports": true, 9 | "experimentalDecorators": true, 10 | "module": "es2015", 11 | "moduleResolution": "node", 12 | "noImplicitAny": false, 13 | "noImplicitReturns": true, 14 | "noImplicitThis": true, 15 | "noUnusedLocals": true, 16 | "sourceMap": true, 17 | "target": "es5", 18 | "lib": ["dom", "es2015"], 19 | "types": ["react"] 20 | }, 21 | "exclude": ["node_modules"], 22 | "include": ["src"] 23 | } 24 | -------------------------------------------------------------------------------- /wallaby.js: -------------------------------------------------------------------------------- 1 | module.exports = function(wallaby) { 2 | return { 3 | files: ["src/**/*.ts", "!src/**/*.test.ts"], 4 | 5 | tests: ["src/**/*.test.ts"], 6 | 7 | compilers: { 8 | "**/*.ts": wallaby.compilers.babel(), 9 | }, 10 | 11 | env: { 12 | type: "node", 13 | runner: "node", 14 | }, 15 | 16 | testFramework: "jest", 17 | } 18 | } 19 | --------------------------------------------------------------------------------