├── .npmignore ├── .yarnrc.yml ├── src ├── ErrorBoundary │ ├── index.ts │ ├── error-boundary.spec.tsx │ ├── ErrorBoundary.ts │ └── README.md ├── Router │ ├── index.ts │ ├── RumRoute.tsx │ ├── RumRouteComponentWrapper.tsx │ ├── README.md │ └── rum-route.spec.tsx ├── RumComponentContext │ ├── index.ts │ ├── rum-component-context.ts │ ├── use-rum-error.ts │ ├── use-rum-action.ts │ ├── use-rum-action.spec.ts │ ├── use-rum-error.spec.ts │ ├── RumComponentContext.tsx │ ├── use-rum-action.spec.tsx │ └── README.md ├── index.ts └── utils │ └── getGlobalObject.ts ├── tsconfig.webpack.json ├── NOTICE ├── .gitignore ├── tsconfig.esm.json ├── jest.config.js ├── tsconfig.cjs.json ├── scripts └── build-env.js ├── tsconfig.json ├── tsconfig.base.json ├── .github ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE.md ├── webpack.config.js ├── README.md ├── webpack.base.js ├── package.json ├── CONTRIBUTING.md ├── LICENSE └── LICENSE-3rdparty.csv /.npmignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | -------------------------------------------------------------------------------- /src/ErrorBoundary/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ErrorBoundary' 2 | -------------------------------------------------------------------------------- /src/Router/index.ts: -------------------------------------------------------------------------------- 1 | export { RumRoute } from './RumRoute'; 2 | -------------------------------------------------------------------------------- /tsconfig.webpack.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "files": [] 4 | } 5 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Datadog rum-react-integration 2 | Copyright 2021-Present Datadog, Inc. 3 | 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bundle 2 | cjs 3 | esm 4 | node_modules 5 | coverage 6 | tunnel.log 7 | local.log 8 | specs.log 9 | /test-report/ 10 | browserstack.err 11 | yarn-error.log 12 | 13 | .DS_Store -------------------------------------------------------------------------------- /src/RumComponentContext/index.ts: -------------------------------------------------------------------------------- 1 | export { WithRumComponentContext, RumComponentContextProvider } from './RumComponentContext'; 2 | export { useRumError } from './use-rum-error'; 3 | export { useRumAction } from './use-rum-action'; 4 | -------------------------------------------------------------------------------- /tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "declaration": true, 6 | "module": "es6", 7 | "allowJs": true, 8 | "outDir": "./esm/" 9 | }, 10 | "include": ["./src"], 11 | "exclude": ["./src/**/*.spec.tsx"] 12 | } 13 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "roots": [ 3 | "/src" 4 | ], 5 | "testEnvironment": "jsdom", 6 | "testMatch": [ 7 | "**/__tests__/**/*.+(ts|tsx|js)", 8 | "**/?(*.)+(spec|test|unit).+(ts|tsx|js)" 9 | ], 10 | "transform": { 11 | "^.+\\.(ts|tsx)$": "ts-jest" 12 | }, 13 | } -------------------------------------------------------------------------------- /tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "declaration": true, 6 | "allowJs": true, 7 | "module": "commonjs", 8 | "outDir": "./cjs/" 9 | }, 10 | "include": ["./src"], 11 | "exclude": ["./src/**/*.spec.ts", "./src/**/*.spec.tsx"] 12 | } 13 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import type { RumPublicApi } from '@datadog/browser-rum-core' 2 | 3 | export { ErrorBoundary } from './ErrorBoundary' 4 | export { RumRoute } from './Router' 5 | export { WithRumComponentContext, RumComponentContextProvider, useRumError, useRumAction } from './RumComponentContext' 6 | 7 | declare global { 8 | interface Window { 9 | DD_RUM?: RumPublicApi & { 10 | startView?(name?: string): void; 11 | }; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /scripts/build-env.js: -------------------------------------------------------------------------------- 1 | const execSync = require('child_process').execSync 2 | 3 | let sdkVersion = '2.15.1' 4 | switch (process.env.BUILD_MODE) { 5 | case 'release': 6 | sdkVersion = lernaJson.version 7 | break 8 | case 'staging': 9 | const commitSha1 = execSync('git rev-parse HEAD').toString().trim() 10 | sdkVersion = `${lernaJson.version}+${commitSha1}` 11 | break 12 | default: 13 | sdkVersion = 'dev' 14 | break 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | // This tsconfig is only used for tooling (ex: typecheck in code editors / lint) 2 | { 3 | "extends": "./tsconfig.base.json", 4 | "compilerOptions": { 5 | "types": [ 6 | "node", 7 | "jest" 8 | ] 9 | }, 10 | "include": [ 11 | "packages", 12 | "scripts", 13 | "test", 14 | "src", 15 | ".eslintrc.js", 16 | "eslint-local-rules" 17 | ], 18 | "exclude": ["packages/*/cjs", "packages/*/esm", "packages/*/bundle", "test/e2e", "test/app", "developer-extension"] 19 | } 20 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "experimentalDecorators": true, 5 | "esModuleInterop": true, 6 | "importHelpers": true, 7 | "moduleResolution": "node", 8 | "resolveJsonModule": true, 9 | "strict": true, 10 | "target": "es5", 11 | "sourceMap": true, 12 | "jsx": "react-jsx", 13 | "types": [ 14 | "node", 15 | "jest" 16 | ], 17 | "lib": ["ES2016", "DOM"], 18 | 19 | "plugins": [ 20 | { 21 | "name": "typescript-tslint-plugin" 22 | } 23 | ] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Motivation 2 | 3 | 4 | 5 | ## Changes 6 | 7 | 8 | 9 | ## Testing 10 | 11 | 12 | 13 | --- 14 | 15 | I have gone over the [contributing](https://github.com/DataDog/rum-react-integration/blob/master/CONTRIBUTING.md) documentation. -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const webpackBase = require('./webpack.base') 4 | 5 | module.exports = (_env, argv) => 6 | webpackBase({ 7 | mode: argv.mode, 8 | entry: path.resolve(__dirname, 'src/index.ts'), 9 | filename: 'datadog-rum-react.js', 10 | externals: { 11 | 'react': { 12 | commonjs: 'react', 13 | commonjs2: 'react', 14 | amd: 'React', 15 | root: 'React' 16 | }, 17 | 'react-dom': { 18 | commonjs: 'react-dom', 19 | commonjs2: 'react-dom', 20 | amd: 'ReactDOM', 21 | root: 'ReactDOM' 22 | } 23 | }, 24 | }) 25 | -------------------------------------------------------------------------------- /src/Router/RumRoute.tsx: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react'; 2 | import { Route } from 'react-router-dom'; 3 | import type { RouteProps } from 'react-router-dom'; 4 | 5 | import { withRum } from './RumRouteComponentWrapper'; 6 | 7 | type RumRouteProps = RouteProps; 8 | 9 | export const RumRoute = ({ 10 | children, 11 | component, 12 | render, 13 | ...otherProps 14 | }: RumRouteProps) => { 15 | const RumComponent = useMemo(() => { 16 | // this is react-router priority 17 | return withRum(children ?? component ?? render); 18 | }, [children, component, render]); 19 | 20 | return ; 21 | }; 22 | -------------------------------------------------------------------------------- /src/RumComponentContext/rum-component-context.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface ComponentContext { 4 | /** 5 | * list of all parent components, separated by . 6 | */ 7 | componentBreadCrumbs: string; 8 | /** 9 | * last parent component, used in the use-rum-action hook to name the action 10 | */ 11 | component: string; 12 | /** 13 | * custom attributes passed to all actions under this context 14 | */ 15 | customAttributes?: object; 16 | } 17 | 18 | export const RumComponentContext = React.createContext({ 19 | componentBreadCrumbs: 'root', 20 | component: 'root' 21 | }); 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RUM React Integration 2 | 3 | ## Overview 4 | 5 | This package is used in conjunction with the [RUM SDK](https://github.com/DataDog/browser-sdk) to tighten RUM's integration with the [React library](https://reactjs.org/). 6 | 7 | ## Packages 8 | 9 | This repository contains several utilities: 10 | 11 | | Package | Docs | 12 | |----------------------|--------------------| 13 | | Rum Component Context| [![API][1]][01] | 14 | | Error Boundary | [![API][1]][02] | 15 | | React Router Tracker | [![API][1]][03] | 16 | 17 | [1]: https://github.githubassets.com/favicons/favicon.png 18 | [01]: https://github.com/DataDog/rum-react-integration/tree/master/src/RumComponentContext 19 | [02]: https://github.com/DataDog/rum-react-integration/tree/master/src/ErrorBoundary 20 | [03]: https://github.com/DataDog/rum-react-integration/tree/master/src/Router -------------------------------------------------------------------------------- /src/utils/getGlobalObject.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * inspired by https://mathiasbynens.be/notes/globalthis 3 | */ 4 | export function getGlobalObject(): T { 5 | if (typeof globalThis === 'object') { 6 | return (globalThis as unknown) as T 7 | } 8 | Object.defineProperty(Object.prototype, '_dd_temp_', { 9 | get() { 10 | return this as object 11 | }, 12 | configurable: true, 13 | }) 14 | // @ts-ignore _dd_temp is defined using defineProperty 15 | let globalObject: unknown = _dd_temp_ 16 | // @ts-ignore _dd_temp is defined using defineProperty 17 | delete Object.prototype._dd_temp_ 18 | if (typeof globalObject !== 'object') { 19 | // on safari _dd_temp_ is available on window but not globally 20 | // fallback on other browser globals check 21 | if (typeof self === 'object') { 22 | globalObject = self 23 | } else if (typeof window === 'object') { 24 | globalObject = window 25 | } else { 26 | globalObject = {} 27 | } 28 | } 29 | return globalObject as T 30 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Issue tracker is used for reporting bugs and requesting enhancements. 2 | 3 | ## Expected Behavior 4 | 5 | 6 | ## Current Behavior 7 | 8 | 9 | ## Possible Solution 10 | 11 | 12 | ## Steps to Reproduce 13 | 14 | 15 | 16 | ## Context (Environment) 17 | 18 | 19 | 20 | 21 | 22 | ## Detailed Description 23 | 24 | 25 | ## Possible Implementation 26 | -------------------------------------------------------------------------------- /src/RumComponentContext/use-rum-error.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | 3 | import { RumComponentContext } from './rum-component-context'; 4 | import { getGlobalObject } from '../utils/getGlobalObject'; 5 | 6 | /** 7 | * Utility to track errors in RUM with the component chain/breadcrumbs from automatically added 8 | * 9 | */ 10 | export const useRumError = () => { 11 | const componentContext = useContext(RumComponentContext); 12 | const RumGlobal = getGlobalObject().DD_RUM 13 | 14 | if (!RumGlobal) { 15 | console.warn( 16 | '@datadog/rum-react-integration: Datadog RUM SDK is not initialized.' 17 | ); 18 | return () => {}; 19 | } 20 | 21 | return (error: unknown, customAttributes: object | undefined, source: "custom" | "network" | "source" | undefined) => { 22 | RumGlobal.addError( 23 | error, 24 | { 25 | ...componentContext.customAttributes, 26 | ...customAttributes, 27 | react: { 28 | breadcrumbs: componentContext.componentBreadCrumbs, 29 | component: componentContext.component, 30 | ...(customAttributes as any)?.react 31 | } 32 | }, 33 | source 34 | ); 35 | }; 36 | }; 37 | -------------------------------------------------------------------------------- /src/ErrorBoundary/error-boundary.spec.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import { getGlobalObject } from '../utils/getGlobalObject'; 3 | import { ErrorBoundary } from './ErrorBoundary'; 4 | 5 | jest.mock('../utils/getGlobalObject', () => ({ 6 | getGlobalObject: jest.fn() 7 | })); 8 | 9 | const Throws = () => { 10 | throw new Error('Oh no!'); 11 | }; 12 | 13 | describe('ErrorBoundary', () => { 14 | let onErrorSpy: jest.Mock; 15 | let addErrorSpy: jest.Mock; 16 | 17 | let rumAgent: { 18 | addError: () => void 19 | }; 20 | 21 | beforeEach(() => { 22 | onErrorSpy = jest.fn(); 23 | addErrorSpy = jest.fn(); 24 | 25 | global.window.onerror = onErrorSpy; 26 | rumAgent = { 27 | addError: addErrorSpy, 28 | } as any; 29 | 30 | (getGlobalObject as jest.Mock).mockReturnValue({ 31 | DD_RUM: rumAgent 32 | }); 33 | }); 34 | 35 | afterEach(() => { 36 | jest.restoreAllMocks(); 37 | }); 38 | 39 | const ErrorRenderer = (error: Error) => ( 40 |

Pretty error displayed {error.message}

41 | ); 42 | 43 | it('sends errors to addError', () => { 44 | render( 45 | 46 | 47 | 48 | ); 49 | 50 | screen.getByText(/Pretty error displayed/i); 51 | expect(onErrorSpy).toHaveBeenCalled(); 52 | expect(addErrorSpy).toHaveBeenCalledTimes(1); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /src/RumComponentContext/use-rum-action.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | 3 | import { RumComponentContext } from './rum-component-context'; 4 | import { getGlobalObject } from '../utils/getGlobalObject'; 5 | 6 | /** 7 | * Utility to track actions in RUM with the component chain/breadcrumbs from automatically added 8 | * 9 | * add a "purpose" to the custom attributes to group the actions 10 | * 11 | * 12 | * @param purpose: explains the use case for the action, allows to split performance and user-tracking actions for example 13 | */ 14 | export const useRumAction = ( 15 | purpose: string = 'unknown' 16 | ) => { 17 | const componentContext = useContext(RumComponentContext); 18 | const RumGlobal = getGlobalObject().DD_RUM 19 | 20 | if (!RumGlobal) { 21 | console.warn( 22 | '@datadog/rum-react-integration: Datadog RUM SDK is not initialized.' 23 | ); 24 | return () => {}; 25 | } 26 | 27 | return (name: string, customAttributes?: object) => { 28 | RumGlobal.addAction(name, { 29 | purpose, 30 | ...componentContext.customAttributes, 31 | ...customAttributes, 32 | react: { 33 | breadcrumbs: componentContext.componentBreadCrumbs, 34 | component: componentContext.component, 35 | ...(customAttributes as any)?.react 36 | } 37 | }); 38 | }; 39 | }; 40 | -------------------------------------------------------------------------------- /webpack.base.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const TerserPlugin = require('terser-webpack-plugin') 3 | const buildEnv = require('./scripts/build-env') 4 | 5 | const tsconfigPath = path.join(__dirname, 'tsconfig.webpack.json') 6 | 7 | module.exports = ({ entry, mode, filename, types }) => ({ 8 | entry, 9 | mode, 10 | output: { 11 | filename, 12 | path: path.resolve('./bundle'), 13 | }, 14 | target: ['web', 'es5'], 15 | devtool: mode === 'development' ? 'inline-source-map' : false, 16 | module: { 17 | rules: [ 18 | { 19 | test: /\.(ts|js|tsx)$/, 20 | loader: 'ts-loader', 21 | exclude: /node_modules/, 22 | options: { 23 | configFile: tsconfigPath, 24 | onlyCompileBundledFiles: true, 25 | compilerOptions: { 26 | module: 'es6', 27 | allowJs: true, 28 | types: types || [], 29 | }, 30 | }, 31 | }, 32 | ], 33 | }, 34 | 35 | resolve: { 36 | extensions: ['.ts', '.tsx', '.js'], 37 | alias: { 38 | // The default "pako.esm.js" build is not transpiled to es5 39 | pako: 'pako/dist/pako.es5.js', 40 | // By default, a non-bundled version of sinon is pulled in, which require the nodejs 'util' 41 | // module. Since v5, webpack doesn't provide nodejs polyfills. Use a bundled version of sinon 42 | // which have its own 'util' module polyfill. 43 | sinon: 'sinon/pkg/sinon.js', 44 | }, 45 | }, 46 | 47 | optimization: { 48 | minimizer: [ 49 | new TerserPlugin({ 50 | extractComments: false, 51 | }), 52 | ], 53 | }, 54 | 55 | plugins: [] 56 | }) 57 | -------------------------------------------------------------------------------- /src/RumComponentContext/use-rum-action.spec.ts: -------------------------------------------------------------------------------- 1 | import { renderHook, act } from '@testing-library/react-hooks'; 2 | import * as React from 'react'; 3 | 4 | import { useRumAction } from './use-rum-action'; 5 | 6 | import { getGlobalObject } from '../utils/getGlobalObject'; 7 | 8 | jest.mock('../utils/getGlobalObject', () => ({ 9 | getGlobalObject: jest.fn() 10 | })); 11 | 12 | describe('useRumAction', () => { 13 | let rumAgent: { 14 | addAction: ()=>void 15 | }; 16 | let addActionSpy: jest.Mock; 17 | 18 | beforeEach(() => { 19 | addActionSpy = jest.fn(); 20 | rumAgent = { 21 | addAction: addActionSpy, 22 | } as any; 23 | 24 | (getGlobalObject as jest.Mock).mockReturnValue({ 25 | DD_RUM: rumAgent 26 | }); 27 | }); 28 | 29 | afterEach(() => { 30 | jest.restoreAllMocks(); 31 | }); 32 | 33 | it('should send an action with user-tracking purpose', () => { 34 | const { 35 | result: { current: addRumAction } 36 | } = renderHook(() => useRumAction("action-fou-tracking")); 37 | act(() => { 38 | addRumAction('test-element', { 39 | customAttr1: 'fou', 40 | customAttr2: 'fou' 41 | }); 42 | }); 43 | 44 | expect(rumAgent.addAction).toHaveBeenCalledTimes(1); 45 | expect( 46 | (rumAgent.addAction as jest.MockedFunction< 47 | typeof rumAgent.addAction 48 | >).mock.calls[0] 49 | ).toMatchInlineSnapshot(` 50 | Array [ 51 | "test-element", 52 | Object { 53 | "customAttr1": "fou", 54 | "customAttr2": "fou", 55 | "purpose": "action-fou-tracking", 56 | "react": Object { 57 | "breadcrumbs": "root", 58 | "component": "root", 59 | }, 60 | }, 61 | ] 62 | `); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@datadog/rum-react-integration", 3 | "version": "1.0.0-alpha", 4 | "private": true, 5 | "license": "Apache-2.0", 6 | "main": "cjs/index.js", 7 | "module": "esm/index.js", 8 | "types": "cjs/index.d.ts", 9 | "scripts": { 10 | "build": "run-p build:cjs build:esm build:bundle", 11 | "build:bundle": "rm -rf bundle && webpack --mode=production", 12 | "build:cjs": "rm -rf cjs && tsc -p tsconfig.cjs.json", 13 | "build:esm": "rm -rf esm && tsc -p tsconfig.esm.json", 14 | "format": "prettier --check .", 15 | "lint": "scripts/cli lint .", 16 | "prepare": "run-s build", 17 | "typecheck": "scripts/cli typecheck . && scripts/cli typecheck developer-extension", 18 | "test": "jest" 19 | }, 20 | "dependencies": { 21 | "tslib": "^1.10.0" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "https://github.com/DataDog/rum-react-integration.git" 26 | }, 27 | "peerDependencies": { 28 | "@datadog/browser-rum-core": "^2.15.1", 29 | "react": ">=16", 30 | "react-router-dom": "^5.0.0" 31 | }, 32 | "resolutions": { 33 | "@types/react": "16" 34 | }, 35 | "devDependencies": { 36 | "@datadog/browser-rum-core": "^2.15.1", 37 | "@testing-library/react": "12.0.0", 38 | "@testing-library/react-hooks": "7.0.1", 39 | "@types/jest": "^26.0.24", 40 | "@types/node": "^16.0.0", 41 | "@types/pako": "1.0.1", 42 | "@types/react": "16", 43 | "@types/react-dom": "16", 44 | "@types/react-router-dom": "^5.1.7", 45 | "@typescript-eslint/eslint-plugin": "4.15.0", 46 | "@typescript-eslint/parser": "4.15.0", 47 | "eslint": "7.20.0", 48 | "eslint-config-prettier": "7.2.0", 49 | "history": "4", 50 | "jest": "^27.0.6", 51 | "npm-run-all": "^4.1.5", 52 | "pako": "2.0.3", 53 | "prettier": "2.2.1", 54 | "react": "17.0.2", 55 | "react-dom": "17.0.2", 56 | "react-router-dom": "^5.0.0", 57 | "ts-jest": "^27.0.3", 58 | "ts-loader": "8.0.18", 59 | "typescript": "4.1.5", 60 | "webpack": "5.91.0", 61 | "webpack-cli": "^4.7.2" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/ErrorBoundary/ErrorBoundary.ts: -------------------------------------------------------------------------------- 1 | import { ReactNode, Component, isValidElement } from 'react'; 2 | 3 | import { getGlobalObject } from '../utils/getGlobalObject'; 4 | 5 | type FallbackRenderer = (error: Error) => React.ReactNode; 6 | 7 | interface ErrorBoundaryState { 8 | hasError: boolean; 9 | error?: Error; 10 | prevScope: string; 11 | } 12 | 13 | export interface ErrorBoundaryProps { 14 | fallback: ReactNode | FallbackRenderer; 15 | scope?: string; 16 | } 17 | 18 | /** 19 | * ErrorBoundary component sends enriched errors to RUM. 20 | */ 21 | export class ErrorBoundary extends Component< 22 | ErrorBoundaryProps, 23 | ErrorBoundaryState 24 | > { 25 | static defaultProps = { 26 | scope: 'error-boundary', 27 | }; 28 | 29 | constructor(props: any) { 30 | super(props); 31 | this.state = { hasError: false, prevScope: props.scope }; 32 | } 33 | 34 | static getDerivedStateFromError(error: Error) { 35 | // Update state so the next render will show the fallback UI. 36 | return { hasError: true, error }; 37 | } 38 | 39 | static getDerivedStateFromProps( 40 | props: ErrorBoundaryProps, 41 | state: ErrorBoundaryState 42 | ) { 43 | if (state.prevScope !== props.scope) { 44 | return { 45 | hasError: false, 46 | error: undefined, 47 | prevScope: props.scope, 48 | }; 49 | } 50 | 51 | return state; 52 | } 53 | 54 | componentDidCatch(error: Error) { 55 | const RumGlobal = getGlobalObject().DD_RUM; 56 | if (RumGlobal) { 57 | RumGlobal.addError( 58 | error, 59 | { 60 | scope: this.props.scope, 61 | }, 62 | 'source' 63 | ); 64 | } 65 | } 66 | 67 | render() { 68 | const { hasError, error } = this.state; 69 | const { fallback } = this.props; 70 | 71 | if (!hasError || !error) { 72 | return this.props.children; 73 | } 74 | 75 | if (isValidElement(fallback) || typeof fallback === 'string') { 76 | return fallback; 77 | } else if (typeof fallback === 'function') { 78 | return fallback(error); 79 | } 80 | 81 | return null; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/RumComponentContext/use-rum-error.spec.ts: -------------------------------------------------------------------------------- 1 | import { renderHook, act } from '@testing-library/react-hooks'; 2 | import * as React from 'react'; 3 | 4 | import { useRumError } from './use-rum-error'; 5 | 6 | import { getGlobalObject } from '../utils/getGlobalObject'; 7 | 8 | jest.mock('../utils/getGlobalObject', () => ({ 9 | getGlobalObject: jest.fn() 10 | })); 11 | 12 | describe('useRumError', () => { 13 | let rumAgent: { 14 | addError: ()=>void 15 | }; 16 | let addErrorSpy: jest.Mock; 17 | 18 | beforeEach(() => { 19 | addErrorSpy = jest.fn(); 20 | rumAgent = { 21 | addError: addErrorSpy, 22 | } as any; 23 | 24 | (getGlobalObject as jest.Mock).mockReturnValue({ 25 | DD_RUM: rumAgent 26 | }); 27 | }); 28 | 29 | afterEach(() => { 30 | jest.restoreAllMocks(); 31 | }); 32 | 33 | it('should send an error with custom attributes and given source', () => { 34 | const fakeError = { 35 | errorFou: 'fou', message: 'bar' 36 | }; 37 | const { 38 | result: { current: addRumError } 39 | } = renderHook(() => useRumError()); 40 | act(() => { 41 | addRumError(fakeError, { 42 | customAttr1: 'fou', 43 | customAttr2: 'fou' 44 | }, 45 | "network"); 46 | }); 47 | 48 | expect(rumAgent.addError).toHaveBeenCalledTimes(1); 49 | expect( 50 | (rumAgent.addError as jest.MockedFunction< 51 | typeof rumAgent.addError 52 | >).mock.calls[0] 53 | ).toMatchInlineSnapshot(` 54 | Array [ 55 | Object { 56 | "errorFou": "fou", 57 | "message": "bar", 58 | }, 59 | Object { 60 | "customAttr1": "fou", 61 | "customAttr2": "fou", 62 | "react": Object { 63 | "breadcrumbs": "root", 64 | "component": "root", 65 | }, 66 | }, 67 | "network", 68 | ] 69 | `); 70 | }); 71 | }); 72 | -------------------------------------------------------------------------------- /src/ErrorBoundary/README.md: -------------------------------------------------------------------------------- 1 | # Datadog RUM React Error Boundary 2 | 3 | ## Overview 4 | Error boundary ensure that your errors stay scoped in it, not breaking the full React tree in case of error. For every error caught, an [`Error`](https://docs.datadoghq.com/real_user_monitoring/#error-tracking-and-crash-reporting) event will be sent to your Datadog dashboards and RUM Explorer. 5 | 6 | ## Setup 7 | 1. Have Datadog RUM SDK up and running. [Instructions](https://github.com/DataDog/browser-sdk/blob/main/packages/rum/README.md); 8 | 2. Add this repository to your project with `yarn add https://github.com/DataDog/rum-react-integration-examples`; 9 | + Optionally, you can copy the contents of this repo and adapt it to your needs. 10 | 11 | ## Usage 12 | Import this utility with: 13 | ``` 14 | import { ErrorBoundary } from '@datadog/rum-react-integration'; 15 | ``` 16 | 17 | Components that are expected to [throw](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw) an [error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) can be wrapped with ErrorBoundary to avoid crashing the rest of application. 18 | 19 | ## Props 20 | `fallback: React.ReactNode | (error: Error) => React.ReactNode` 21 | > The render method called when an exception is thrown within the ErrorBoundary. It receives the Error instance that triggered it. 22 | 23 | `scope?: string` 24 | > An optional [context](https://docs.datadoghq.com/real_user_monitoring/browser/collecting_browser_errors/?tab=npm#collect-errors-manually) string sent to Datadog in order to easily filter or group the thrown Errors. 25 | 26 | ## Example 27 | 28 | ``` 29 | import "./App.css"; 30 | 31 | import { ErrorBoundary } from '@Datadog/rum-react-integration'; 32 | 33 | import { Gallery } from './Gallery'; 34 | export function App() { 35 | return ( 36 |
37 | 38 |
Houston we've got a problem with the gallery: {error.message}
} 40 | > 41 | 42 |
43 |
44 | ); 45 | } 46 | ``` 47 | 48 | ## Expected results 49 | Your errors will appear in Datadog's Dashboards and RUM Explorer, as they would appear by using [`addError`](https://docs.datadoghq.com/real_user_monitoring/browser/collecting_browser_errors/?tab=npm#collect-errors-manually). The wrapped UI in your application is expected to not crash, display any console errors, or not show any ominous error messages. -------------------------------------------------------------------------------- /src/Router/RumRouteComponentWrapper.tsx: -------------------------------------------------------------------------------- 1 | import { isValidElement, useRef } from 'react'; 2 | import type { RouteProps, RouteComponentProps } from 'react-router-dom'; 3 | import { getGlobalObject } from '../utils/getGlobalObject'; 4 | 5 | type RumRouteComponentType = 6 | | RouteProps['component'] 7 | | RouteProps['children'] 8 | | RouteProps['render']; 9 | 10 | function isClassComponent( 11 | component: RumRouteComponentType 12 | ): component is React.ComponentClass { 13 | return ( 14 | typeof component === 'function' && !!component.prototype?.isReactComponent 15 | ); 16 | } 17 | 18 | function isFunctionComponent( 19 | component: RumRouteComponentType 20 | ): component is React.FunctionComponent { 21 | return ( 22 | typeof component === 'function' && 23 | component.hasOwnProperty('props') && 24 | isValidElement(component) 25 | ); 26 | } 27 | 28 | function isReactRouterComponent( 29 | component: RumRouteComponentType 30 | ): component is RouteProps['component'] { 31 | return isClassComponent(component) || isFunctionComponent(component); 32 | } 33 | 34 | export const withRum = (component: RumRouteComponentType) => 35 | function RumView(props: RouteComponentProps) { 36 | useRef( 37 | (() => { 38 | if (!component) { 39 | return; 40 | } 41 | 42 | const globalObj = getGlobalObject(); 43 | 44 | if (!globalObj.DD_RUM) { 45 | console.warn( 46 | '@datadog/rum-react-integration: Datadog RUM SDK is not initialized.' 47 | ); 48 | return; 49 | } 50 | 51 | if (!globalObj.DD_RUM?.startView) { 52 | console.warn( 53 | '@datadog/rum-react-integration: Manual tracking not supported. Try updating the Datadog RUM SDK.' 54 | ); 55 | return; 56 | } 57 | 58 | const manualTracking = !!globalObj.DD_RUM?.getInitConfiguration() 59 | ?.trackViewsManually; 60 | if (!manualTracking) { 61 | console.warn( 62 | '@datadog/rum-react-integration: The trackViewsManually flag in RUM initialization must be set to %ctrue%c.', 63 | 'color:green', 64 | 'color:default' 65 | ); 66 | return; 67 | } 68 | 69 | globalObj.DD_RUM.startView(props.match.path); 70 | })() 71 | ); 72 | 73 | if (!component) { 74 | return <>{component}; 75 | } else if (isReactRouterComponent(component)) { 76 | const Component = component; 77 | return ; 78 | } else if (component instanceof Function) { 79 | return <>{component(props)}; 80 | } 81 | 82 | return <>{component}; 83 | }; 84 | -------------------------------------------------------------------------------- /src/RumComponentContext/RumComponentContext.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useMemo } from 'react'; 2 | 3 | import type { ComponentContext } from './rum-component-context'; 4 | import { RumComponentContext} from './rum-component-context'; 5 | 6 | /** 7 | * Context Provider to add a new component to the action breadcrumbs. Useful for class Components. 8 | */ 9 | export const RumComponentContextProvider: React.FunctionComponent<{ 10 | componentName: string; 11 | customAttributes?: object; 12 | }> = ({ 13 | componentName, 14 | customAttributes, 15 | children 16 | }) => { 17 | const parentContext = useContext(RumComponentContext); 18 | const newContext = useMemo( 19 | () => ({ 20 | component: componentName, 21 | customAttributes: { 22 | ...parentContext.customAttributes, 23 | ...customAttributes 24 | }, 25 | componentBreadCrumbs: `${parentContext.componentBreadCrumbs}.${componentName}` 26 | }), 27 | [ 28 | componentName, 29 | parentContext.componentBreadCrumbs, 30 | parentContext.customAttributes, 31 | customAttributes 32 | ] 33 | ); 34 | return ( 35 | 36 | {children} 37 | 38 | ); 39 | }; 40 | /** 41 | * Decorator to add a new component to the breadcrumbs when using useRumAction or useRumTracking action hooks 42 | * the decorator is better than a just component because it will add the context to everything in your component 43 | */ 44 | export function WithRumComponentContext( 45 | componentName: string, 46 | options: 47 | | { 48 | customAttributes?: object; 49 | } 50 | | undefined, 51 | Component: React.FunctionComponent 52 | ): React.FunctionComponent; 53 | export function WithRumComponentContext( 54 | componentName: string, 55 | Component: React.FunctionComponent 56 | ): React.FunctionComponent; 57 | export function WithRumComponentContext( 58 | componentName: string, 59 | options: any, 60 | Component?: React.FunctionComponent 61 | ): React.FunctionComponent { 62 | if (typeof Component === 'undefined') { 63 | return WithRumComponentContext(componentName, {}, options); 64 | } 65 | return (props: PropsType) => { 66 | return ( 67 | 71 | 72 | 73 | ); 74 | }; 75 | } 76 | -------------------------------------------------------------------------------- /src/RumComponentContext/use-rum-action.spec.tsx: -------------------------------------------------------------------------------- 1 | import { renderHook, act } from '@testing-library/react-hooks'; 2 | import React from 'react'; 3 | 4 | import { RumComponentContextProvider } from './RumComponentContext'; 5 | 6 | import { useRumAction } from './use-rum-action'; 7 | 8 | import { getGlobalObject } from '../utils/getGlobalObject'; 9 | 10 | jest.mock('../utils/getGlobalObject', () => ({ 11 | getGlobalObject: jest.fn() 12 | })); 13 | 14 | describe('useRumAction', () => { 15 | let rumAgent: { 16 | addAction: ()=>void 17 | }; 18 | let addActionSpy: jest.Mock; 19 | 20 | beforeEach(() => { 21 | addActionSpy = jest.fn(); 22 | rumAgent = { 23 | addAction: addActionSpy, 24 | } as any; 25 | 26 | (getGlobalObject as jest.Mock).mockReturnValue({ 27 | DD_RUM: rumAgent 28 | }); 29 | }); 30 | 31 | afterEach(() => { 32 | jest.restoreAllMocks(); 33 | }); 34 | 35 | it('should send an action with user-tracking purpose', () => { 36 | const { 37 | result: { current: addRumAction } 38 | } = renderHook(() => useRumAction("action-fou-tracking")); 39 | act(() => { 40 | addRumAction('test-element', { 41 | customAttr1: 'fou', 42 | customAttr2: 'fou' 43 | }); 44 | }); 45 | 46 | expect(rumAgent.addAction).toHaveBeenCalledTimes(1); 47 | expect( 48 | (rumAgent.addAction as jest.MockedFunction< 49 | typeof rumAgent.addAction 50 | >).mock.calls[0] 51 | ).toMatchInlineSnapshot(` 52 | Array [ 53 | "test-element", 54 | Object { 55 | "customAttr1": "fou", 56 | "customAttr2": "fou", 57 | "purpose": "action-fou-tracking", 58 | "react": Object { 59 | "breadcrumbs": "root", 60 | "component": "root", 61 | }, 62 | }, 63 | ] 64 | `); 65 | }); 66 | 67 | it('should use the context to fill element and breadcrumbs', () => { 68 | const wrapper: React.FunctionComponent = ({ children }) => ({children}); 69 | 70 | const { 71 | result: { current: addRumAction } 72 | } = renderHook(() => useRumAction("action-fou-tracking"), { wrapper }); 73 | act(() => { 74 | addRumAction('test-element', { 75 | customAttr1: 'fou', 76 | customAttr2: 'fou' 77 | }); 78 | }); 79 | 80 | expect(rumAgent.addAction).toHaveBeenCalledTimes(1); 81 | expect( 82 | (rumAgent.addAction as jest.MockedFunction< 83 | typeof rumAgent.addAction 84 | >).mock.calls[0] 85 | ).toMatchInlineSnapshot(` 86 | Array [ 87 | "test-element", 88 | Object { 89 | "customAttr1": "fou", 90 | "customAttr2": "fou", 91 | "purpose": "action-fou-tracking", 92 | "react": Object { 93 | "breadcrumbs": "root.ComponentToTrack", 94 | "component": "ComponentToTrack", 95 | }, 96 | }, 97 | ] 98 | `); 99 | }); 100 | }); 101 | -------------------------------------------------------------------------------- /src/Router/README.md: -------------------------------------------------------------------------------- 1 | # Datadog RUM React Router Integration 2 | 3 | ## Overview 4 | [Datadog Real User Monitoring](https://www.datadoghq.com/product/real-user-monitoring/) integration with React Router V5. With each route change, the RUM SDK automates the creation of a new RUM view with the route path as the view name. This improves the naming of your pages in the RUM product and results in simplified analysis. 5 | 6 | | Default RUM names | React-Router integration | 7 | |------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 8 | | ![default RUM view names)](https://p-qkfgo2.t2.n0.cdn.getcloudapp.com/items/jkuPxAbd/736233cf-b448-4b71-9cd1-52bb7183fc1c.png?v=d45828ff76ac00dec333aba5077781cb) | ![react router integration RUM view names)](https://p-qkfgo2.t2.n0.cdn.getcloudapp.com/items/yAurdJOW/8bacc9e5-5361-4836-9c85-ab8bb53ed40f.png?v=ab2dd75359a2cb3c16dc2c8c3a82493c) | 9 | 10 | ## Setup 11 | 1. [Set up RUM browser](https://docs.datadoghq.com/real_user_monitoring/browser/#setup). 12 | 2. Initialize RUM with `trackViewsManually: true`: 13 | ```javascript 14 | import { datadogRum } from '@datadog/browser-rum'; 15 | 16 | datadogRum.init({ 17 | ..., 18 | trackViewsManually: true, 19 | ... 20 | }); 21 | ``` 22 | 3. Include this repository in your project. (`yarn add https://github.com/DataDog/rum-react-integration-examples`). 23 | + Optionally, you can copy the contents of this repo and adapt it to your needs. 24 | 4. Replace all the occurences of `` with ``. 25 | 26 | **Note**: Without the change, existing react-router `` components do not trigger a new RUM view. Resources, actions and errors are still collected and attributed to the active RUM view. 27 | 28 | ## Importing the package 29 | Import this package with the following command: 30 | ```javascript 31 | import { RumRoute } from '@datadog/rum-react-integration'; 32 | ``` 33 | 34 | Alternatively, you may want to use an alias: 35 | ```javascript 36 | import { RumRoute as Route } from '@datadog/rum-react-integration'; 37 | ``` 38 | 39 | ## Props 40 | The `` component inherits the same props available on the original react-router `` component. Find more details in the [official react-router documentation](https://reactrouter.com/web/api/Route). 41 | 42 | ## Usage example 43 | ```jsx 44 | import "./App.css"; 45 | import { 46 | BrowserRouter as Router, 47 | } from 'react-router-dom'; 48 | import { RumRoute } from '@Datadog/rum-react-integration'; 49 | import { About } from './About'; 50 | import { Menu } from './Menu'; 51 | import { Gallery } from './Gallery'; 52 | export function App() { 53 | return ( 54 |
55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 |
68 | ); 69 | } 70 | ``` 71 | 72 | ### Notes on `trackViewsManually` 73 | By default, the RUM SDK automatically tracks page changes using the History API. `trackViewsManually` ensures you are delegating the responsibility of creating new RUM views to the router only. Not setting `trackViewsManually` results in most RUM views appearing twice. 74 | 75 | ### Notes on `React.StrictMode` 76 | If you are using [React.StrictMode](https://reactjs.org/docs/strict-mode.html), RUM views get duplicated **only in development mode, not in production mode**. This is due to [lifecycles being double invoked](https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects). -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Rum React Integration 2 | 3 | First of all, thanks for taking the time to contribute! 4 | 5 | This document provides some basic guidelines for contributing to this repository. To propose improvements, feel free to submit a pull request. 6 | 7 | ## Table of Contents 8 | - [Submitting issues](#submitting-issues) 9 | - [Pull Requests](#pull-requests) 10 | - [Suggesting Enhancements](#suggesting-enhancements) 11 | - [Before Submitting an Enhancement](#before-submitting-an-enhancement) 12 | - [How Do I Submit a Good Enhancement Suggestion?](#how-do-i-submit-a-good-enhancement-suggestion) 13 | - [Commit messages and Pull Request titles](#commit-messages-and-pull-request-titles) 14 | - [User-facing changes](#user-facing-changes) 15 | - [Internal changes](#internal-changes) 16 | - [Legal Notice](#legal-notice) 17 | 18 | ## Submitting issues 19 | 20 | Github issues are welcome, feel free to submit error reports and feature requests! Make sure to add 21 | enough details to explain your use case. If you require further assistance, you can also contact 22 | Datadog [support][1]. 23 | 24 | ## Pull Requests 25 | 26 | Have you fixed a bug or written a new feature and want to share it? Many thanks! 27 | 28 | In order to ease/speed up our review, here are some items you can check/improve when submitting your 29 | pull request: 30 | 31 | - Keep commits small and focused, rebase your branch if needed. 32 | - Write unit and e2e tests for the code you wrote. 33 | - Write meaningful [Commit messages and Pull Request 34 | titles](#commit-messages-and-pull-request-titles) 35 | 36 | ### Suggesting Enhancements 37 | 38 | This section guides you through submitting an enhancement suggestion, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions. 39 | 40 | #### Before Submitting an Enhancement 41 | 42 | - Make sure that you are using the latest version. 43 | - Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. 44 | - Be aware that this repository is only a showcase and container of usage examples for Datadog's RUM browser-sdk. If your changes are related to the SDK itself, please refer to https://github.com/DataDog/browser-sdk 45 | 46 | #### How Do I Submit a Good Enhancement Suggestion? 47 | 48 | Enhancement suggestions are tracked as [GitHub issues]([issues](https://github.com/DataDog/rum-react-integration/issues)). 49 | 50 | - Use a **clear and descriptive title** for the issue to identify the suggestion. 51 | - Provide a **step-by-step description of the suggested enhancement** in as many details as possible. 52 | - **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives do not work for you. 53 | - You may want to **include screenshots and animated GIFs** which help you demonstrate the steps or point out the part which the suggestion is related to. 54 | - **Explain why this enhancement would be useful** to most users. You may also want to point out the other projects that solved it better and which could serve as inspiration. 55 | 56 | 57 | ## Commit messages and Pull Request titles 58 | 59 | Messages should be concise but explanatory. We are using a convention inspired by [gitmoji][2], to 60 | label our Commit messages and Pull Request titles: 61 | 62 | ### User-facing changes 63 | 64 | 💥 - Breaking change. 65 | 66 | ✨ - New feature. 67 | 68 | 🐛 - Bug fix. 69 | 70 | ⚡️ - Performance improvement. 71 | 72 | 📝 - Documentation. 73 | 74 | ⚗ - Experimental. 75 | 76 | ### Internal changes 77 | 78 | 👷 - Updating project setup (continuous integration, build system, package dependencies...). 79 | 80 | ♻️ - Refactoring code. 81 | 82 | 🎨 - Improving structure / format of the code. 83 | 84 | ✅ - Updating tests. 85 | 86 | 👌 - Updating code due to code review changes. 87 | 88 | ## Legal Notice 89 | > When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license. 90 | 91 | [1]: https://docs.datadoghq.com/help/ 92 | [2]: https://gitmoji.carloscuesta.me/ -------------------------------------------------------------------------------- /src/RumComponentContext/README.md: -------------------------------------------------------------------------------- 1 | # Datadog React RUM Component Context provider 2 | 3 | ## Overview 4 | 5 | The RUM Component Context provider helps scoping the context of the RUM errors and actions. 6 | Users can then define a specific context for each of their React component by naming it and passing it some attributes. 7 | 8 | Once these contexts provided, any errors or actions generated within them will contain : 9 | - a component breadcrumbs path generated form the parent context names 10 | - Optional: some custom defined attributes 11 | 12 | ## Setup 13 | 14 | 1. Have Datadog RUM SDK up and running. [Instructions](https://github.com/DataDog/browser-sdk/blob/main/packages/rum/README.md); 15 | 2. Add this repository to your project with `yarn add https://github.com/DataDog/rum-react-integration-examples`; 16 | + Optionally, you can copy the contents of this repo and adapt it to your needs. 17 | 18 | ## Usage 19 | 20 | ### Set the context your React components. 21 | 22 | Wrap any React components in a `RumComponentContextProvider` or use the `WithRumComponentContext` component decorator and define their names and custom attributes. 23 | 24 | ### Generate RUM actions and errors using the custom React hook 25 | 26 | Use the provided custom hooks `useRumAction` and `useRumError` and their callback functions to generate actions and errors 27 | 28 | ## Props 29 | 30 | ### RumComponentContextProvider 31 | 32 | ``` 33 | componentName: string 34 | ``` 35 | > Set the current breadcrumbs step 36 | 37 | ``` 38 | customAttributes?: object; 39 | ``` 40 | > Optional property that will populate a custom field for each of the errors and actions under this context 41 | 42 | ### WithRumComponentContext (React component decorator alternative) 43 | 44 | ``` 45 | componentName: string 46 | ``` 47 | > Set the current breadcrumbs step 48 | 49 | ``` 50 | options: { customAttributes?: object; } | undefined 51 | ``` 52 | > Optional property that will populate a custom field for each of the errors and actions under this context 53 | 54 | ``` 55 | Component: React.FunctionComponent 56 | ``` 57 | > Child component that will wrapped in the RumComponentContextProvider 58 | 59 | ## Example 60 | 61 | ### WithRumComponentContext 62 | 63 | ``` 64 | import { useRumError, useRumAction, WithRumComponentContext } from '@datadog/rum-react-integration'; 65 | 66 | 67 | const App = WithRumComponentContext("AppComponent", () => { 68 | const addAction = useRumAction("trackingAppAction"); 69 | const addError = useRumError(); 70 | 71 | return ( 72 |
73 | 78 | 83 |
84 | ); 85 | }) 86 | ``` 87 | 88 | ### RumComponentContextProvider 89 | 90 | ``` 91 | import { useRumError, useRumAction, RumComponentContextProvider } from '@datadog/rum-react-integration'; 92 | 93 | export function App() { 94 | return ( 95 |
96 | 97 | 98 | 99 |
100 | ); 101 | } 102 | 103 | 104 | function FnComponent() { 105 | const addAction = useRumAction("trackingAppAction"); 106 | const addError = useRumError(); 107 | 108 | return ( 109 |
110 | 115 | 120 |
121 | ); 122 | } 123 | ``` 124 | 125 | ## Expected Results 126 | The usage of both `WithRumComponentContext` and `RumComponentContextProvider` will populate your RUM's [custom action events](https://docs.datadoghq.com/real_user_monitoring/guide/send-rum-custom-actions/) with the following fields: 127 | 128 | `purpose: string` 129 | A general category field that can be used to filter groups of actions. 130 | 131 | `react: { breadcrumbs: string }` 132 | A breadcrumb trail of `WithRumComponentContext` and `RumComponentContextProvider` componentName props, to give a better context for an Action event. 133 | 134 | `react: { component: string }` 135 | This is the current componentName available through the context provider. It should equal the last part of the breadcrumbs attribute -------------------------------------------------------------------------------- /src/Router/rum-route.spec.tsx: -------------------------------------------------------------------------------- 1 | import { RumRoute } from './RumRoute'; 2 | import { Router, Redirect, Route } from 'react-router-dom'; 3 | import type { RouteProps } from 'react-router-dom'; 4 | 5 | import { createMemoryHistory } from 'history'; 6 | import { getGlobalObject } from '../utils/getGlobalObject'; 7 | import { render, screen } from '@testing-library/react'; 8 | import { Component } from 'react'; 9 | 10 | const history = createMemoryHistory(); 11 | 12 | const defaultProps: RouteProps = {}; 13 | 14 | const globalObj = getGlobalObject(); 15 | 16 | describe('', () => { 17 | const buildSubject = (props = defaultProps) => { 18 | render( 19 | 20 | 21 | Home is where the heart is 22 | 23 | Here's some relevant info regarding planks and rope skipping 24 | Nice 25 | 26 | 27 | Last edited: yesterday 28 | 29 | 30 |
Footer
31 |
32 | ); 33 | }; 34 | 35 | beforeEach(() => { 36 | globalObj.DD_RUM = { 37 | getInitConfiguration: () => ({ trackViewsManually: true }), 38 | startView: () => {}, 39 | } as any; 40 | }); 41 | 42 | afterAll(() => { 43 | jest.restoreAllMocks(); 44 | }); 45 | 46 | describe('startView calls', () => { 47 | it('should be able call RUM startView through router redirect', () => { 48 | jest.spyOn(globalObj.DD_RUM!, 'startView'); 49 | buildSubject(); 50 | 51 | screen.getByText(/Home is where the heart is/i); 52 | 53 | expect(globalObj.DD_RUM?.startView).toHaveBeenCalledTimes(1); 54 | expect(globalObj.DD_RUM?.startView).toHaveBeenLastCalledWith('/home'); 55 | }); 56 | 57 | it('should call RUM startView through nested routes', () => { 58 | buildSubject(); 59 | 60 | jest.spyOn(globalObj.DD_RUM!, 'startView'); 61 | history.push('/thread/10/comment/20'); 62 | 63 | screen.getByText(/Nice/i); 64 | 65 | expect(globalObj.DD_RUM?.startView).toHaveBeenNthCalledWith( 66 | 1, 67 | '/thread/:threadId' 68 | ); 69 | expect(globalObj.DD_RUM?.startView).toHaveBeenNthCalledWith( 70 | 2, 71 | '/thread/:threadId/comment/:commentId' 72 | ); 73 | }); 74 | 75 | it('should call RUM startView when combining Route and RumRoute ', () => { 76 | buildSubject(); 77 | 78 | jest.spyOn(globalObj.DD_RUM!, 'startView'); 79 | history.push('/about/history'); 80 | 81 | screen.getByText(/Last edited: yesterday/i); 82 | 83 | expect(globalObj.DD_RUM?.startView).toHaveBeenNthCalledWith( 84 | 1, 85 | '/about/history' 86 | ); 87 | expect(globalObj.DD_RUM?.startView).not.toHaveBeenCalledWith('/about'); 88 | }); 89 | }); 90 | 91 | describe('ReactRouter children rendering', () => { 92 | it('should render strings', () => { 93 | buildSubject({ children: 'This is a string' }); 94 | history.push('/rumRoute'); 95 | 96 | screen.getByText(/This is a string/i); 97 | }); 98 | 99 | it('should render JSX', () => { 100 | buildSubject({ 101 | children:
This is a JSX children
, 102 | }); 103 | history.push('/rumRoute'); 104 | 105 | screen.getByText(/This is a JSX children/i); 106 | }); 107 | 108 | it('should render a React element', () => { 109 | const TestChildren = () =>
This is a React element
; 110 | buildSubject({ children: }); 111 | history.push('/rumRoute'); 112 | 113 | screen.getByText(/This is a React element/i); 114 | }); 115 | }); 116 | 117 | describe('ReactRouter render prop rendering', () => { 118 | it('should render strings', () => { 119 | buildSubject({ render: () => 'This is a string' }); 120 | history.push('/rumRoute'); 121 | 122 | screen.getByText(/This is a string/i); 123 | }); 124 | 125 | it('should render JSX', () => { 126 | buildSubject({ 127 | render: () =>
This is a JSX children
, 128 | }); 129 | history.push('/rumRoute'); 130 | 131 | screen.getByText(/This is a JSX children/i); 132 | }); 133 | 134 | it('should render a React element', () => { 135 | const TestChildren = () =>
This is a React element
; 136 | buildSubject({ render: () => }); 137 | history.push('/rumRoute'); 138 | 139 | screen.getByText(/This is a React element/i); 140 | }); 141 | }); 142 | 143 | describe('ReactRouter component prop rendering', () => { 144 | it('should render a React Functional Component', () => { 145 | const TestChildren = () => ( 146 |
This is a React Functional Component
147 | ); 148 | buildSubject({ render: () => }); 149 | history.push('/rumRoute'); 150 | 151 | screen.getByText(/This is a React Functional Component/i); 152 | }); 153 | 154 | it('should render a React Class Component', () => { 155 | const TestChildren = class Test extends Component { 156 | render() { 157 | return
This is a React Class Component
; 158 | } 159 | }; 160 | buildSubject({ render: () => }); 161 | history.push('/rumRoute'); 162 | 163 | screen.getByText(/This is a React Class Component/i); 164 | }); 165 | }); 166 | }); 167 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2021-Present Datadog, Inc. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /LICENSE-3rdparty.csv: -------------------------------------------------------------------------------- 1 | "module name","Origin","licenses","copyright" 2 | "@babel/code-frame@7.12.11","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 3 | "@babel/code-frame@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 4 | "@babel/compat-data@7.14.7","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 5 | "@babel/core@7.14.6","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 6 | "@babel/generator@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 7 | "@babel/helper-compilation-targets@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 8 | "@babel/helper-function-name@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 9 | "@babel/helper-get-function-arity@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 10 | "@babel/helper-hoist-variables@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 11 | "@babel/helper-member-expression-to-functions@7.14.7","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 12 | "@babel/helper-module-imports@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 13 | "@babel/helper-module-transforms@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 14 | "@babel/helper-optimise-call-expression@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 15 | "@babel/helper-plugin-utils@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 16 | "@babel/helper-replace-supers@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 17 | "@babel/helper-simple-access@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 18 | "@babel/helper-split-export-declaration@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 19 | "@babel/helper-validator-identifier@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 20 | "@babel/helper-validator-option@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 21 | "@babel/helpers@7.14.6","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 22 | "@babel/highlight@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 23 | "@babel/parser@7.14.7","npm","MIT","Copyright (C) 2012-2014 by various contributors (see AUTHORS)" 24 | "@babel/plugin-syntax-async-generators@7.8.4","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 25 | "@babel/plugin-syntax-bigint@7.8.3","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 26 | "@babel/plugin-syntax-class-properties@7.12.13","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 27 | "@babel/plugin-syntax-import-meta@7.10.4","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 28 | "@babel/plugin-syntax-json-strings@7.8.3","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 29 | "@babel/plugin-syntax-logical-assignment-operators@7.10.4","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 30 | "@babel/plugin-syntax-nullish-coalescing-operator@7.8.3","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 31 | "@babel/plugin-syntax-numeric-separator@7.10.4","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 32 | "@babel/plugin-syntax-object-rest-spread@7.8.3","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 33 | "@babel/plugin-syntax-optional-catch-binding@7.8.3","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 34 | "@babel/plugin-syntax-optional-chaining@7.8.3","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 35 | "@babel/plugin-syntax-top-level-await@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 36 | "@babel/plugin-syntax-typescript@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 37 | "@babel/runtime-corejs3@7.14.7","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 38 | "@babel/runtime@7.14.6","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 39 | "@babel/template@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 40 | "@babel/traverse@7.14.7","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 41 | "@babel/types@7.14.5","npm","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors" 42 | "@bcoe/v8-coverage@0.2.3","npm","MIT","Copyright © 2015-2017 Charles Samborski" 43 | "@datadog/browser-core@2.17.0","npm","Apache-2.0","" 44 | "@datadog/browser-rum-core@2.17.0","npm","Apache-2.0","" 45 | "@discoveryjs/json-ext@0.5.3","npm","MIT","Copyright (c) 2020 Roman Dvornov " 46 | "@eslint/eslintrc@0.3.0","npm","MIT","Copyright (c) 2020 ESLint" 47 | "@istanbuljs/load-nyc-config@1.1.0","npm","ISC","Copyright (c) 2019, Contributors" 48 | "@istanbuljs/schema@0.1.3","npm","MIT","Copyright (c) 2019 CFWare, LLC" 49 | "@jest/console@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 50 | "@jest/core@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 51 | "@jest/environment@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 52 | "@jest/fake-timers@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 53 | "@jest/globals@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 54 | "@jest/reporters@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 55 | "@jest/source-map@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 56 | "@jest/test-result@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 57 | "@jest/test-sequencer@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 58 | "@jest/transform@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 59 | "@jest/types@26.6.2","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 60 | "@jest/types@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 61 | "@nodelib/fs.scandir@2.1.5","npm","MIT","Copyright (c) Denis Malinochkin" 62 | "@nodelib/fs.stat@2.0.5","npm","MIT","Copyright (c) Denis Malinochkin" 63 | "@nodelib/fs.walk@1.2.8","npm","MIT","Copyright (c) Denis Malinochkin" 64 | "@sinonjs/commons@1.8.3","npm","BSD-3-Clause","Copyright (c) 2018, Sinon.JS. All rights reserved." 65 | "@sinonjs/fake-timers@7.1.2","npm","BSD-3-Clause","Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no. All rights reserved." 66 | "@testing-library/dom@8.1.0","npm","MIT","" 67 | "@testing-library/react-hooks@7.0.1","npm","MIT","" 68 | "@testing-library/react@12.0.0","npm","MIT","" 69 | "@tootallnate/once@1.1.2","npm","MIT","" 70 | "@types/aria-query@4.2.2","npm","MIT","" 71 | "@types/babel__core@7.1.15","npm","MIT","" 72 | "@types/babel__generator@7.6.3","npm","MIT","" 73 | "@types/babel__template@7.4.1","npm","MIT","" 74 | "@types/babel__traverse@7.14.2","npm","MIT","" 75 | "@types/eslint-scope@3.7.1","npm","MIT","" 76 | "@types/eslint@7.28.0","npm","MIT","" 77 | "@types/estree@0.0.46","npm","MIT","" 78 | "@types/estree@0.0.50","npm","MIT","" 79 | "@types/graceful-fs@4.1.5","npm","MIT","" 80 | "@types/history@4.7.9","npm","MIT","" 81 | "@types/istanbul-lib-coverage@2.0.3","npm","MIT","" 82 | "@types/istanbul-lib-report@3.0.0","npm","MIT","" 83 | "@types/istanbul-reports@3.0.1","npm","MIT","" 84 | "@types/jest@26.0.24","npm","MIT","" 85 | "@types/json-schema@7.0.8","npm","MIT","" 86 | "@types/node@16.3.2","npm","MIT","" 87 | "@types/pako@1.0.1","npm","MIT","" 88 | "@types/prettier@2.3.2","npm","MIT","" 89 | "@types/prop-types@15.7.4","npm","MIT","" 90 | "@types/react-dom@16.9.14","npm","MIT","" 91 | "@types/react-dom@17.0.9","npm","MIT","" 92 | "@types/react-router-dom@5.1.8","npm","MIT","" 93 | "@types/react-router@5.1.16","npm","MIT","" 94 | "@types/react-test-renderer@17.0.1","npm","MIT","" 95 | "@types/react@16.14.11","npm","MIT","" 96 | "@types/scheduler@0.16.2","npm","MIT","" 97 | "@types/stack-utils@2.0.1","npm","MIT","" 98 | "@types/yargs-parser@20.2.1","npm","MIT","" 99 | "@types/yargs@15.0.14","npm","MIT","" 100 | "@types/yargs@16.0.4","npm","MIT","" 101 | "@typescript-eslint/eslint-plugin@4.15.0","npm","MIT","Copyright (c) 2019 TypeScript ESLint and other contributors" 102 | "@typescript-eslint/experimental-utils@4.15.0","npm","MIT","Copyright (c) 2019 TypeScript ESLint and other contributors" 103 | "@typescript-eslint/parser@4.15.0","npm","BSD-2-Clause","" 104 | "@typescript-eslint/scope-manager@4.15.0","npm","MIT","Copyright (c) 2019 TypeScript ESLint and other contributors" 105 | "@typescript-eslint/types@4.15.0","npm","MIT","Copyright (c) 2019 TypeScript ESLint and other contributors" 106 | "@typescript-eslint/typescript-estree@4.15.0","npm","BSD-2-Clause","" 107 | "@typescript-eslint/visitor-keys@4.15.0","npm","MIT","Copyright (c) 2019 TypeScript ESLint and other contributors" 108 | "@webassemblyjs/ast@1.11.0","npm","MIT","Copyright (c) 2018 Sven Sauleau " 109 | "@webassemblyjs/floating-point-hex-parser@1.11.0","npm","MIT","Copyright (c) 2017 Mauro Bringolf" 110 | "@webassemblyjs/helper-api-error@1.11.0","npm","MIT","Copyright (c) 2018 Sven Sauleau " 111 | "@webassemblyjs/helper-buffer@1.11.0","npm","MIT","Copyright (c) 2018 Sven Sauleau " 112 | "@webassemblyjs/helper-numbers@1.11.0","npm","MIT","Copyright (c) 2018 Sven Sauleau " 113 | "@webassemblyjs/helper-wasm-bytecode@1.11.0","npm","MIT","Copyright (c) 2018 Sven Sauleau " 114 | "@webassemblyjs/helper-wasm-section@1.11.0","npm","MIT","Copyright (c) 2018 Sven Sauleau " 115 | "@webassemblyjs/ieee754@1.11.0","npm","MIT","Copyright (c) 2018 Sven Sauleau " 116 | "@webassemblyjs/leb128@1.11.0","npm","Apache-2.0","Copyright 2012 The Obvious Corporation.. http://obvious.com/" 117 | "@webassemblyjs/utf8@1.11.0","npm","MIT","Copyright (c) 2018 Sven Sauleau " 118 | "@webassemblyjs/wasm-edit@1.11.0","npm","MIT","Copyright (c) 2018 Sven Sauleau " 119 | "@webassemblyjs/wasm-gen@1.11.0","npm","MIT","Copyright (c) 2018 Sven Sauleau " 120 | "@webassemblyjs/wasm-opt@1.11.0","npm","MIT","Copyright (c) 2018 Sven Sauleau " 121 | "@webassemblyjs/wasm-parser@1.11.0","npm","MIT","Copyright (c) 2018 Sven Sauleau " 122 | "@webassemblyjs/wast-printer@1.11.0","npm","MIT","Copyright (c) 2018 Sven Sauleau " 123 | "@webpack-cli/configtest@1.0.4","npm","MIT","Copyright JS Foundation and other contributors" 124 | "@webpack-cli/info@1.3.0","npm","MIT","Copyright JS Foundation and other contributors" 125 | "@webpack-cli/serve@1.5.1","npm","MIT","Copyright JS Foundation and other contributors" 126 | "@xtuc/ieee754@1.2.0","npm","BSD-3-Clause","Copyright (c) 2008, Fair Oaks Labs, Inc.. All rights reserved." 127 | "@xtuc/long@4.2.2","npm","Apache-2.0","" 128 | "abab@2.0.5","npm","BSD-3-Clause","Copyright © 2019 W3C and Jeff Carpenter \" 129 | "acorn-globals@6.0.0","npm","MIT","Copyright (c) 2014 Forbes Lindesay" 130 | "acorn-jsx@5.3.2","npm","MIT","Copyright (C) 2012-2017 by Ingvar Stepanyan" 131 | "acorn-walk@7.2.0","npm","MIT","Copyright (C) 2012-2018 by various contributors (see AUTHORS)" 132 | "acorn@7.4.1","npm","MIT","Copyright (C) 2012-2018 by various contributors (see AUTHORS)" 133 | "acorn@8.4.1","npm","MIT","Copyright (C) 2012-2020 by various contributors (see AUTHORS)" 134 | "agent-base@6.0.2","npm","MIT","Copyright (c) 2013 Nathan Rajlich <nathan@tootallnate.net>" 135 | "ajv-keywords@3.5.2","npm","MIT","Copyright (c) 2016 Evgeny Poberezkin" 136 | "ajv@6.12.6","npm","MIT","Copyright (c) 2015-2017 Evgeny Poberezkin" 137 | "ajv@8.6.2","npm","MIT","Copyright (c) 2015-2021 Evgeny Poberezkin" 138 | "ansi-colors@4.1.1","npm","MIT","Copyright (c) 2015-present, Brian Woodward." 139 | "ansi-escapes@4.3.2","npm","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)" 140 | "ansi-regex@5.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 141 | "ansi-styles@3.2.1","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 142 | "ansi-styles@4.3.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 143 | "ansi-styles@5.2.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 144 | "anymatch@3.1.2","npm","ISC","Copyright (c) 2019 Elan Shanker, Paul Miller (https://paulmillr.com)" 145 | "argparse@1.0.10","npm","MIT","Copyright (C) 2012 by Vitaly Puzrin" 146 | "aria-query@4.2.2","npm","Apache-2.0","Copyright 2020 A11yance" 147 | "array-union@2.1.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 148 | "astral-regex@2.0.0","npm","MIT","Copyright (c) Kevin Mårtensson (github.com/kevva)" 149 | "asynckit@0.4.0","npm","MIT","Copyright (c) 2016 Alex Indigo" 150 | "babel-jest@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 151 | "babel-plugin-istanbul@6.0.0","npm","BSD-3-Clause","Copyright (c) 2016, Istanbul Code Coverage. All rights reserved." 152 | "babel-plugin-jest-hoist@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 153 | "babel-preset-current-node-syntax@1.0.1","npm","MIT","Copyright (c) 2020 Nicolò Ribaudo and other contributors" 154 | "babel-preset-jest@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 155 | "balanced-match@1.0.2","npm","MIT","Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>" 156 | "big.js@5.2.2","npm","MIT","Copyright (c) 2018 Michael Mclaughlin" 157 | "brace-expansion@1.1.11","npm","MIT","Copyright (c) 2013 Julian Gruber " 158 | "braces@3.0.2","npm","MIT","Copyright (c) 2014-2018, Jon Schlinkert." 159 | "browser-process-hrtime@1.0.0","npm","BSD-2-Clause","Copyright 2014 kumavis" 160 | "browserslist@4.16.6","npm","MIT","Copyright 2014 Andrey Sitnik and other contributors" 161 | "bs-logger@0.2.6","npm","MIT","Copyright (c) 2018 Huafu Gandon" 162 | "bser@2.1.1","npm","Apache-2.0","" 163 | "buffer-from@1.1.1","npm","MIT","Copyright (c) 2016, 2018 Linus Unnebäck" 164 | "call-bind@1.0.2","npm","MIT","Copyright (c) 2020 Jordan Harband" 165 | "callsites@3.1.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 166 | "camelcase@5.3.1","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 167 | "camelcase@6.2.0","npm","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)" 168 | "caniuse-lite@1.0.30001245","npm","CC-BY-4.0","" 169 | "chalk@2.4.2","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 170 | "chalk@4.1.1","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 171 | "char-regex@1.0.2","npm","MIT","Copyright (c) 2019 Richie Bendall" 172 | "chrome-trace-event@1.0.3","npm","MIT","Copyright (c) 2015 Joyent Inc. All rights reserved." 173 | "ci-info@3.2.0","npm","MIT","Copyright (c) 2016-2021 Thomas Watson Steen" 174 | "cjs-module-lexer@1.2.2","npm","MIT","Copyright (C) 2018-2020 Guy Bedford" 175 | "cliui@7.0.4","npm","ISC","Copyright (c) 2015, Contributors" 176 | "clone-deep@4.0.1","npm","MIT","Copyright (c) 2014-2018, Jon Schlinkert." 177 | "co@4.6.0","npm","MIT","Copyright (c) 2014 TJ Holowaychuk <tj@vision-media.ca>" 178 | "collect-v8-coverage@1.0.1","npm","MIT","Copyright (c) 2019 Simen Bekkhus" 179 | "color-convert@1.9.3","npm","MIT","Copyright (c) 2011-2016 Heather Arthur " 180 | "color-convert@2.0.1","npm","MIT","Copyright (c) 2011-2016 Heather Arthur " 181 | "color-name@1.1.3","npm","MIT","" 182 | "color-name@1.1.4","npm","MIT","" 183 | "colorette@1.2.2","npm","MIT","Copyright © Jorge Bucaran <>" 184 | "combined-stream@1.0.8","npm","MIT","Copyright (c) 2011 Debuggable Limited " 185 | "commander@2.20.3","npm","MIT","Copyright (c) 2011 TJ Holowaychuk " 186 | "commander@7.2.0","npm","MIT","Copyright (c) 2011 TJ Holowaychuk " 187 | "concat-map@0.0.1","npm","MIT","" 188 | "convert-source-map@1.8.0","npm","MIT","Copyright 2013 Thorsten Lorenz. . All rights reserved." 189 | "core-js-pure@3.15.2","npm","MIT","Copyright (c) 2014-2021 Denis Pushkarev" 190 | "core-util-is@1.0.2","npm","MIT","Copyright Node.js contributors. All rights reserved." 191 | "cross-spawn@6.0.5","npm","MIT","Copyright (c) 2018 Made With MOXY Lda " 192 | "cross-spawn@7.0.3","npm","MIT","Copyright (c) 2018 Made With MOXY Lda " 193 | "cssom@0.3.8","npm","MIT","Copyright (c) Nikita Vasilyev" 194 | "cssom@0.4.4","npm","MIT","Copyright (c) Nikita Vasilyev" 195 | "cssstyle@2.3.0","npm","MIT","Copyright (c) Chad Walker" 196 | "csstype@3.0.8","npm","MIT","Copyright (c) 2017-2018 Fredrik Nicol" 197 | "data-urls@2.0.0","npm","MIT","Copyright © 2017–2020 Domenic Denicola " 198 | "debug@4.3.2","npm","MIT","Copyright (c) 2014 TJ Holowaychuk " 199 | "decimal.js@10.3.1","npm","MIT","Copyright (c) 2021 Michael Mclaughlin" 200 | "dedent@0.7.0","npm","MIT","Copyright (c) 2015 Desmond Brand (dmnd@desmondbrand.com)" 201 | "deep-is@0.1.3","npm","MIT","Copyright (c) 2012, 2013 Thorsten Lorenz . Copyright (c) 2012 James Halliday . Copyright (c) 2009 Thomas Robinson <280north.com>" 202 | "deepmerge@4.2.2","npm","MIT","Copyright (c) 2012 James Halliday, Josh Duff, and other contributors" 203 | "define-properties@1.1.3","npm","MIT","Copyright (C) 2015 Jordan Harband" 204 | "delayed-stream@1.0.0","npm","MIT","Copyright (c) 2011 Debuggable Limited " 205 | "detect-newline@3.1.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 206 | "diff-sequences@26.6.2","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 207 | "diff-sequences@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 208 | "dir-glob@3.0.1","npm","MIT","Copyright (c) Kevin Mårtensson (github.com/kevva)" 209 | "doctrine@3.0.0","npm","Apache-2.0","" 210 | "dom-accessibility-api@0.5.6","npm","MIT","Copyright (c) 2020 Sebastian Silbermann" 211 | "domexception@2.0.1","npm","MIT","Copyright © 2017 Domenic Denicola" 212 | "electron-to-chromium@1.3.778","npm","ISC","Copyright 2018 Kilian Valkhof" 213 | "emittery@0.8.1","npm","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)" 214 | "emoji-regex@8.0.0","npm","MIT","Copyright Mathias Bynens " 215 | "emojis-list@3.0.0","npm","MIT","Copyright © 2015 Kiko Beats" 216 | "enhanced-resolve@4.5.0","npm","MIT","Copyright JS Foundation and other contributors" 217 | "enhanced-resolve@5.8.2","npm","MIT","Copyright JS Foundation and other contributors" 218 | "enquirer@2.3.6","npm","MIT","Copyright (c) 2016-present, Jon Schlinkert." 219 | "envinfo@7.8.1","npm","MIT","Copyright (c) 2018 Trevor Brindle" 220 | "errno@0.1.8","npm","MIT","" 221 | "error-ex@1.3.2","npm","MIT","Copyright (c) 2015 JD Ballard" 222 | "es-abstract@1.18.3","npm","MIT","Copyright (C) 2015 Jordan Harband" 223 | "es-module-lexer@0.4.1","npm","MIT","Copyright (C) 2018-2019 Guy Bedford" 224 | "es-to-primitive@1.2.1","npm","MIT","Copyright (c) 2015 Jordan Harband" 225 | "escalade@3.1.1","npm","MIT","Copyright (c) Luke Edwards (lukeed.com)" 226 | "escape-string-regexp@1.0.5","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 227 | "escape-string-regexp@2.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 228 | "escodegen@2.0.0","npm","BSD-2-Clause","Copyright (C) 2012 Yusuke Suzuki (twitter: @Constellation) and other contributors." 229 | "eslint-config-prettier@7.2.0","npm","MIT","Copyright (c) 2017, 2018, 2019, 2020, 2021 Simon Lydell and contributors" 230 | "eslint-scope@5.1.1","npm","BSD-2-Clause","Copyright JS Foundation and other contributors, https://js.foundation. Copyright (C) 2012-2013 Yusuke Suzuki (twitter: @Constellation) and other contributors." 231 | "eslint-utils@2.1.0","npm","MIT","Copyright (c) 2018 Toru Nagashima" 232 | "eslint-visitor-keys@1.3.0","npm","Apache-2.0","" 233 | "eslint-visitor-keys@2.1.0","npm","Apache-2.0","" 234 | "eslint@7.20.0","npm","MIT","Copyright JS Foundation and other contributors, https://js.foundation" 235 | "espree@7.3.1","npm","BSD-2-Clause","Copyright (c) Open JS Foundation. All rights reserved." 236 | "esprima@4.0.1","npm","BSD-2-Clause","Copyright JS Foundation and other contributors, https://js.foundation/" 237 | "esquery@1.4.0","npm","BSD-3-Clause","Copyright (c) 2013, Joel Feenstra. All rights reserved." 238 | "esrecurse@4.3.0","npm","BSD-2-Clause","Copyright (C) 2014 [Yusuke Suzuki](https://github.com/Constellation). (twitter: [@Constellation](https://twitter.com/Constellation)) and other contributors." 239 | "estraverse@4.3.0","npm","BSD-2-Clause","" 240 | "estraverse@5.2.0","npm","BSD-2-Clause","" 241 | "esutils@2.0.3","npm","BSD-2-Clause","" 242 | "events@3.3.0","npm","MIT","Copyright Joyent, Inc. and other Node contributors." 243 | "execa@5.1.1","npm","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)" 244 | "exit@0.1.2","npm","MIT","Copyright (c) 2013 ""Cowboy"" Ben Alman" 245 | "expect@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 246 | "fast-deep-equal@3.1.3","npm","MIT","Copyright (c) 2017 Evgeny Poberezkin" 247 | "fast-glob@3.2.7","npm","MIT","Copyright (c) Denis Malinochkin" 248 | "fast-json-stable-stringify@2.1.0","npm","MIT","Copyright (c) 2017 Evgeny Poberezkin. Copyright (c) 2013 James Halliday" 249 | "fast-levenshtein@2.0.6","npm","MIT","Copyright (c) 2013 [Ramesh Nair](http://www.hiddentao.com/)" 250 | "fastest-levenshtein@1.0.12","npm","MIT","Copyright (c) 2020 Kasper Unn Weihe" 251 | "fastq@1.11.1","npm","ISC","Copyright (c) 2015-2020, Matteo Collina " 252 | "fb-watchman@2.0.1","npm","Apache-2.0","" 253 | "file-entry-cache@6.0.1","npm","MIT","Copyright (c) 2015 Roy Riojas" 254 | "fill-range@7.0.1","npm","MIT","Copyright (c) 2014-present, Jon Schlinkert." 255 | "find-up@4.1.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 256 | "flat-cache@3.0.4","npm","MIT","Copyright (c) 2015 Roy Riojas" 257 | "flatted@3.2.1","npm","ISC","Copyright (c) 2018-2020, Andrea Giammarchi, @WebReflection" 258 | "form-data@3.0.1","npm","MIT","Copyright (c) 2012 Felix Geisendörfer (felix@debuggable.com) and contributors" 259 | "fs.realpath@1.0.0","npm","ISC","Copyright (c) Isaac Z. Schlueter and Contributors" 260 | "fsevents@2.3.2","npm","MIT","Copyright (C) 2010-2020 by Philipp Dunkel, Ben Noordhuis, Elan Shankar, Paul Miller" 261 | "function-bind@1.1.1","npm","MIT","Copyright (c) 2013 Raynos." 262 | "functional-red-black-tree@1.0.1","npm","MIT","Copyright (c) 2013 Mikola Lysenko" 263 | "gensync@1.0.0-beta.2","npm","MIT","Copyright 2018 Logan Smyth " 264 | "get-caller-file@2.0.5","npm","ISC","" 265 | "get-intrinsic@1.1.1","npm","MIT","Copyright (c) 2020 Jordan Harband" 266 | "get-package-type@0.1.0","npm","MIT","Copyright (c) 2020 CFWare, LLC" 267 | "get-stream@6.0.1","npm","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)" 268 | "glob-parent@5.1.2","npm","ISC","Copyright (c) 2015, 2019 Elan Shanker" 269 | "glob-to-regexp@0.4.1","npm","BSD-2-Clause","Copyright (c) 2013, Nick Fitzgerald" 270 | "glob@7.1.7","npm","ISC","Copyright (c) Isaac Z. Schlueter and Contributors" 271 | "globals@11.12.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 272 | "globals@12.4.0","npm","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)" 273 | "globby@11.0.4","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 274 | "graceful-fs@4.2.6","npm","ISC","Copyright (c) Isaac Z. Schlueter, Ben Noordhuis, and Contributors" 275 | "has-bigints@1.0.1","npm","MIT","Copyright (c) 2019 Jordan Harband" 276 | "has-flag@3.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 277 | "has-flag@4.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 278 | "has-symbols@1.0.2","npm","MIT","Copyright (c) 2016 Jordan Harband" 279 | "has@1.0.3","npm","MIT","Copyright (c) 2013 Thiago de Arruda" 280 | "history@4.10.1","npm","MIT","Copyright (c) React Training 2016-2018" 281 | "hosted-git-info@2.8.9","npm","ISC","Copyright (c) 2015, Rebecca Turner" 282 | "html-encoding-sniffer@2.0.1","npm","MIT","Copyright © 2016–2020 Domenic Denicola " 283 | "html-escaper@2.0.2","npm","MIT","Copyright (C) 2017-present by Andrea Giammarchi - @WebReflection" 284 | "http-proxy-agent@4.0.1","npm","MIT","Copyright (c) 2013 Nathan Rajlich <nathan@tootallnate.net>" 285 | "https-proxy-agent@5.0.0","npm","MIT","Copyright (c) 2013 Nathan Rajlich <nathan@tootallnate.net>" 286 | "human-signals@2.1.0","npm","Apache-2.0","" 287 | "iconv-lite@0.4.24","npm","MIT","Copyright (c) 2011 Alexander Shtuchkin" 288 | "ignore@4.0.6","npm","MIT","Copyright (c) 2013 Kael Zhang , contributors. http://kael.me/" 289 | "ignore@5.1.8","npm","MIT","Copyright (c) 2013 Kael Zhang , contributors. http://kael.me/" 290 | "import-fresh@3.3.0","npm","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)" 291 | "import-local@3.0.2","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 292 | "imurmurhash@0.1.4","npm","MIT","" 293 | "inflight@1.0.6","npm","ISC","Copyright (c) Isaac Z. Schlueter" 294 | "inherits@2.0.4","npm","ISC","Copyright (c) Isaac Z. Schlueter" 295 | "interpret@2.2.0","npm","MIT","Copyright (c) 2014-2018 Tyler Kellen , Blaine Bublitz , and Eric Schoffstall " 296 | "is-arrayish@0.2.1","npm","MIT","Copyright (c) 2015 JD Ballard" 297 | "is-bigint@1.0.2","npm","MIT","Copyright (c) 2018 Jordan Harband" 298 | "is-boolean-object@1.1.1","npm","MIT","Copyright (c) 2015 Jordan Harband" 299 | "is-callable@1.2.3","npm","MIT","Copyright (c) 2015 Jordan Harband" 300 | "is-ci@3.0.0","npm","MIT","Copyright (c) 2016-2021 Thomas Watson Steen" 301 | "is-core-module@2.5.0","npm","MIT","Copyright (c) 2014 Dave Justice" 302 | "is-date-object@1.0.4","npm","MIT","Copyright (c) 2015 Jordan Harband" 303 | "is-extglob@2.1.1","npm","MIT","Copyright (c) 2014-2016, Jon Schlinkert" 304 | "is-fullwidth-code-point@3.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 305 | "is-generator-fn@2.1.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 306 | "is-glob@4.0.1","npm","MIT","Copyright (c) 2014-2017, Jon Schlinkert." 307 | "is-negative-zero@2.0.1","npm","MIT","Copyright (c) 2014 Jordan Harband" 308 | "is-number-object@1.0.5","npm","MIT","Copyright (c) 2015 Jordan Harband" 309 | "is-number@7.0.0","npm","MIT","Copyright (c) 2014-present, Jon Schlinkert." 310 | "is-plain-object@2.0.4","npm","MIT","Copyright (c) 2014-2017, Jon Schlinkert." 311 | "is-potential-custom-element-name@1.0.1","npm","MIT","Copyright Mathias Bynens " 312 | "is-regex@1.1.3","npm","MIT","Copyright (c) 2014 Jordan Harband" 313 | "is-stream@2.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 314 | "is-string@1.0.6","npm","MIT","Copyright (c) 2015 Jordan Harband" 315 | "is-symbol@1.0.4","npm","MIT","Copyright (c) 2015 Jordan Harband" 316 | "is-typedarray@1.0.0","npm","MIT","" 317 | "isarray@1.0.0","npm","MIT","Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>" 318 | "isexe@2.0.0","npm","ISC","Copyright (c) Isaac Z. Schlueter and Contributors" 319 | "isobject@3.0.1","npm","MIT","Copyright (c) 2014-2017, Jon Schlinkert." 320 | "istanbul-lib-coverage@3.0.0","npm","BSD-3-Clause","Copyright 2012-2015 Yahoo! Inc.. All rights reserved." 321 | "istanbul-lib-instrument@4.0.3","npm","BSD-3-Clause","Copyright 2012-2015 Yahoo! Inc.. All rights reserved." 322 | "istanbul-lib-report@3.0.0","npm","BSD-3-Clause","Copyright 2012-2015 Yahoo! Inc.. All rights reserved." 323 | "istanbul-lib-source-maps@4.0.0","npm","BSD-3-Clause","Copyright 2015 Yahoo! Inc.. All rights reserved." 324 | "istanbul-reports@3.0.2","npm","BSD-3-Clause","Copyright 2012-2015 Yahoo! Inc.. All rights reserved." 325 | "jest-changed-files@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 326 | "jest-circus@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 327 | "jest-cli@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 328 | "jest-config@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 329 | "jest-diff@26.6.2","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 330 | "jest-diff@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 331 | "jest-docblock@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 332 | "jest-each@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 333 | "jest-environment-jsdom@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 334 | "jest-environment-node@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 335 | "jest-get-type@26.3.0","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 336 | "jest-get-type@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 337 | "jest-haste-map@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 338 | "jest-jasmine2@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 339 | "jest-leak-detector@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 340 | "jest-matcher-utils@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 341 | "jest-message-util@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 342 | "jest-mock@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 343 | "jest-pnp-resolver@1.2.2","npm","MIT","" 344 | "jest-regex-util@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 345 | "jest-resolve-dependencies@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 346 | "jest-resolve@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 347 | "jest-runner@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 348 | "jest-runtime@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 349 | "jest-serializer@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 350 | "jest-snapshot@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 351 | "jest-util@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 352 | "jest-validate@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 353 | "jest-watcher@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 354 | "jest-worker@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 355 | "jest@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 356 | "js-tokens@4.0.0","npm","MIT","Copyright (c) 2014, 2015, 2016, 2017, 2018 Simon Lydell" 357 | "js-yaml@3.14.1","npm","MIT","Copyright (C) 2011-2015 by Vitaly Puzrin" 358 | "jsdom@16.6.0","npm","MIT","Copyright (c) 2010 Elijah Insua" 359 | "jsesc@2.5.2","npm","MIT","Copyright Mathias Bynens " 360 | "json-parse-better-errors@1.0.2","npm","MIT","Copyright 2017 Kat Marchán" 361 | "json-schema-traverse@0.4.1","npm","MIT","Copyright (c) 2017 Evgeny Poberezkin" 362 | "json-schema-traverse@1.0.0","npm","MIT","Copyright (c) 2017 Evgeny Poberezkin" 363 | "json-stable-stringify-without-jsonify@1.0.1","npm","MIT","" 364 | "json5@2.2.0","npm","MIT","Copyright (c) 2012-2018 Aseem Kishore, and [others]." 365 | "kind-of@6.0.3","npm","MIT","Copyright (c) 2014-2017, Jon Schlinkert." 366 | "kleur@3.0.3","npm","MIT","Copyright (c) Luke Edwards (lukeed.com)" 367 | "leven@3.1.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 368 | "levn@0.3.0","npm","MIT","Copyright (c) George Zahariev" 369 | "levn@0.4.1","npm","MIT","Copyright (c) George Zahariev" 370 | "load-json-file@4.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 371 | "loader-runner@4.2.0","npm","MIT","Copyright (c) Tobias Koppers @sokra" 372 | "loader-utils@2.0.0","npm","MIT","Copyright JS Foundation and other contributors" 373 | "locate-path@5.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 374 | "lodash.clonedeep@4.5.0","npm","MIT","Copyright jQuery Foundation and other contributors " 375 | "lodash.truncate@4.4.2","npm","MIT","Copyright jQuery Foundation and other contributors " 376 | "lodash@4.17.21","npm","MIT","Copyright OpenJS Foundation and other contributors " 377 | "loose-envify@1.4.0","npm","MIT","Copyright (c) 2015 Andres Suarez " 378 | "lru-cache@6.0.0","npm","ISC","Copyright (c) Isaac Z. Schlueter and Contributors" 379 | "lz-string@1.4.4","npm","WTFPL","" 380 | "make-dir@3.1.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 381 | "make-error@1.3.6","npm","ISC","Copyright 2014 Julien Fontanet" 382 | "makeerror@1.0.11","npm","BSD-3-Clause","Copyright (c) 2014, Naitik Shah. All rights reserved." 383 | "memory-fs@0.5.0","npm","MIT","Copyright JS Foundation and other contributors" 384 | "memorystream@0.3.1","npm","MIT","Copyright (C) 2011 Dmitry Nizovtsev" 385 | "merge-stream@2.0.0","npm","MIT","Copyright (c) Stephen Sugden (stephensugden.com)" 386 | "merge2@1.4.1","npm","MIT","Copyright (c) 2014-2020 Teambition" 387 | "micromatch@4.0.4","npm","MIT","Copyright (c) 2014-present, Jon Schlinkert." 388 | "mime-db@1.48.0","npm","MIT","Copyright (c) 2014 Jonathan Ong me@jongleberry.com" 389 | "mime-types@2.1.31","npm","MIT","Copyright (c) 2014 Jonathan Ong . Copyright (c) 2015 Douglas Christopher Wilson " 390 | "mimic-fn@2.1.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 391 | "minimatch@3.0.4","npm","ISC","Copyright (c) Isaac Z. Schlueter and Contributors" 392 | "minimist@1.2.5","npm","MIT","" 393 | "mkdirp@1.0.4","npm","MIT","Copyright James Halliday (mail@substack.net) and Isaac Z. Schlueter (i@izs.me)" 394 | "ms@2.1.2","npm","MIT","Copyright (c) 2016 Zeit, Inc." 395 | "natural-compare@1.4.0","npm","MIT","Copyright (c) 2012-2015 Lauri Rooden <lauri@rooden.ee> . [The MIT License](http://lauri.rooden.ee/mit-license.txt)" 396 | "neo-async@2.6.2","npm","MIT","Copyright (c) 2014-2018 Suguru Motegi. Based on Async.js, Copyright Caolan McMahon" 397 | "nice-try@1.0.5","npm","MIT","Copyright (c) 2018 Tobias Reich" 398 | "node-int64@0.4.0","npm","MIT","Copyright (c) 2014 Robert Kieffer" 399 | "node-modules-regexp@1.0.0","npm","MIT","Copyright (c) James Talmage (github.com/jamestalmage)" 400 | "node-releases@1.1.73","npm","MIT","Copyright (c) 2017 Sergey Rubanov (https://github.com/chicoxyzzy)" 401 | "normalize-package-data@2.5.0","npm","BSD-2-Clause","Copyright (c) Meryn Stol (""Author""). All rights reserved." 402 | "normalize-path@3.0.0","npm","MIT","Copyright (c) 2014-2018, Jon Schlinkert." 403 | "npm-run-all@4.1.5","npm","MIT","Copyright (c) 2015 Toru Nagashima" 404 | "npm-run-path@4.0.1","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 405 | "nwsapi@2.2.0","npm","MIT","Copyright (c) 2007-2019 Diego Perini (http://www.iport.it/)" 406 | "object-assign@4.1.1","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 407 | "object-inspect@1.11.0","npm","MIT","Copyright (c) 2013 James Halliday" 408 | "object-keys@1.1.1","npm","MIT","Copyright (C) 2013 Jordan Harband" 409 | "object.assign@4.1.2","npm","MIT","Copyright (c) 2014 Jordan Harband" 410 | "once@1.4.0","npm","ISC","Copyright (c) Isaac Z. Schlueter and Contributors" 411 | "onetime@5.1.2","npm","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)" 412 | "optionator@0.8.3","npm","MIT","Copyright (c) George Zahariev" 413 | "optionator@0.9.1","npm","MIT","Copyright (c) George Zahariev" 414 | "p-each-series@2.2.0","npm","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)" 415 | "p-limit@2.3.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 416 | "p-limit@3.1.0","npm","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)" 417 | "p-locate@4.1.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 418 | "p-try@2.2.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 419 | "pako@2.0.3","npm","(MIT AND Zlib)","Copyright (C) 2014-2017 by Vitaly Puzrin and Andrei Tuputcyn" 420 | "parent-module@1.0.1","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 421 | "parse-json@4.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 422 | "parse5@6.0.1","npm","MIT","Copyright (c) 2013-2019 Ivan Nikulin (ifaaan@gmail.com, https://github.com/inikulin)" 423 | "path-exists@4.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 424 | "path-is-absolute@1.0.1","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 425 | "path-key@2.0.1","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 426 | "path-key@3.1.1","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 427 | "path-parse@1.0.7","npm","MIT","Copyright (c) 2015 Javier Blanco" 428 | "path-type@3.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 429 | "path-type@4.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 430 | "picomatch@2.3.0","npm","MIT","Copyright (c) 2017-present, Jon Schlinkert." 431 | "pidtree@0.3.1","npm","MIT","Copyright (c) 2018 Simone Primarosa" 432 | "pify@3.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 433 | "pirates@4.0.1","npm","MIT","Copyright (c) 2016-2018 Ari Porad" 434 | "pkg-dir@4.2.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 435 | "prelude-ls@1.1.2","npm","MIT","Copyright (c) George Zahariev" 436 | "prelude-ls@1.2.1","npm","MIT","Copyright (c) George Zahariev" 437 | "prettier@2.2.1","npm","MIT","Copyright © James Long and contributors" 438 | "pretty-format@26.6.2","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 439 | "pretty-format@27.0.6","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 440 | "process-nextick-args@2.0.1","npm","MIT","" 441 | "progress@2.0.3","npm","MIT","Copyright (c) 2017 TJ Holowaychuk " 442 | "prompts@2.4.1","npm","MIT","Copyright (c) 2018 Terkel Gjervig Nielsen" 443 | "prr@1.0.1","npm","MIT","Copyright (c) 2014 Rod Vagg. ---------------------------" 444 | "psl@1.8.0","npm","MIT","Copyright (c) 2017 Lupo Montero lupomontero@gmail.com" 445 | "punycode@2.1.1","npm","MIT","Copyright Mathias Bynens " 446 | "queue-microtask@1.2.3","npm","MIT","Copyright (c) Feross Aboukhadijeh" 447 | "randombytes@2.1.0","npm","MIT","Copyright (c) 2017 crypto-browserify" 448 | "react-dom@17.0.2","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 449 | "react-error-boundary@3.1.3","npm","MIT","" 450 | "react-is@17.0.2","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 451 | "react-router-dom@5.2.0","npm","MIT","Copyright (c) React Training 2016-2018" 452 | "react@17.0.2","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 453 | "read-pkg@3.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 454 | "readable-stream@2.3.7","npm","MIT","" 455 | "rechoir@0.7.0","npm","MIT","Copyright (c) 2014-2019 Tyler Kellen , Blaine Bublitz , and Eric Schoffstall " 456 | "regenerator-runtime@0.13.7","npm","MIT","Copyright (c) 2014-present, Facebook, Inc." 457 | "regexpp@3.2.0","npm","MIT","Copyright (c) 2018 Toru Nagashima" 458 | "require-directory@2.1.1","npm","MIT","Copyright (c) 2011 Troy Goode " 459 | "require-from-string@2.0.2","npm","MIT","Copyright (c) Vsevolod Strukchinsky (github.com/floatdrop)" 460 | "resolve-cwd@3.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 461 | "resolve-from@4.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 462 | "resolve-from@5.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 463 | "resolve-pathname@3.0.0","npm","MIT","Copyright (c) Michael Jackson 2016-2018" 464 | "resolve@1.20.0","npm","MIT","Copyright (c) 2012 James Halliday" 465 | "reusify@1.0.4","npm","MIT","Copyright (c) 2015 Matteo Collina" 466 | "rimraf@3.0.2","npm","ISC","Copyright (c) Isaac Z. Schlueter and Contributors" 467 | "run-parallel@1.2.0","npm","MIT","Copyright (c) Feross Aboukhadijeh" 468 | "safe-buffer@5.1.2","npm","MIT","Copyright (c) Feross Aboukhadijeh" 469 | "safe-buffer@5.2.1","npm","MIT","Copyright (c) Feross Aboukhadijeh" 470 | "safer-buffer@2.1.2","npm","MIT","Copyright (c) 2018 Nikita Skovoroda " 471 | "saxes@5.0.1","npm","ISC","" 472 | "scheduler@0.20.2","npm","MIT","Copyright (c) Facebook, Inc. and its affiliates." 473 | "schema-utils@3.1.0","npm","MIT","Copyright JS Foundation and other contributors" 474 | "semver@5.7.1","npm","ISC","Copyright (c) Isaac Z. Schlueter and Contributors" 475 | "semver@6.3.0","npm","ISC","Copyright (c) Isaac Z. Schlueter and Contributors" 476 | "semver@7.3.5","npm","ISC","Copyright (c) Isaac Z. Schlueter and Contributors" 477 | "serialize-javascript@6.0.0","npm","BSD-3-Clause","Copyright 2014 Yahoo! Inc.. All rights reserved." 478 | "shallow-clone@3.0.1","npm","MIT","Copyright (c) 2015-present, Jon Schlinkert." 479 | "shebang-command@1.2.0","npm","MIT","Copyright (c) Kevin Martensson (github.com/kevva)" 480 | "shebang-command@2.0.0","npm","MIT","Copyright (c) Kevin Mårtensson (github.com/kevva)" 481 | "shebang-regex@1.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 482 | "shebang-regex@3.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 483 | "shell-quote@1.7.2","npm","MIT","Copyright (c) 2013 James Halliday (mail@substack.net)" 484 | "signal-exit@3.0.3","npm","ISC","Copyright (c) 2015, Contributors" 485 | "sisteransi@1.0.5","npm","MIT","Copyright (c) 2018 Terkel Gjervig Nielsen" 486 | "slash@3.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 487 | "slice-ansi@4.0.0","npm","MIT","Copyright (c) DC . Copyright (c) Sindre Sorhus (https://sindresorhus.com)" 488 | "source-list-map@2.0.1","npm","MIT","Copyright 2017 JS Foundation" 489 | "source-map-support@0.5.19","npm","MIT","Copyright (c) 2014 Evan Wallace" 490 | "source-map@0.5.7","npm","BSD-3-Clause","" 491 | "source-map@0.6.1","npm","BSD-3-Clause","" 492 | "source-map@0.7.3","npm","BSD-3-Clause","" 493 | "spdx-correct@3.1.1","npm","Apache-2.0","" 494 | "spdx-exceptions@2.3.0","npm","CC-BY-3.0","" 495 | "spdx-expression-parse@3.0.1","npm","MIT","Copyright (c) 2015 Kyle E. Mitchell & other authors listed in AUTHORS" 496 | "spdx-license-ids@3.0.9","npm","CC0-1.0","" 497 | "sprintf-js@1.0.3","npm","BSD-3-Clause","Copyright (c) 2007-2014, Alexandru Marasteanu . All rights reserved." 498 | "stack-utils@2.0.3","npm","MIT","Copyright (c) Isaac Z. Schlueter , James Talmage (github.com/jamestalmage), and Contributors" 499 | "string-length@4.0.2","npm","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)" 500 | "string-width@4.2.2","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 501 | "string.prototype.padend@3.1.2","npm","MIT","Copyright (c) 2015 EcmaScript Shims" 502 | "string.prototype.trimend@1.0.4","npm","MIT","Copyright (c) 2017 Khaled Al-Ansari" 503 | "string.prototype.trimstart@1.0.4","npm","MIT","Copyright (c) 2017 Khaled Al-Ansari" 504 | "string_decoder@1.1.1","npm","MIT","" 505 | "strip-ansi@6.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 506 | "strip-bom@3.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 507 | "strip-bom@4.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 508 | "strip-final-newline@2.0.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 509 | "strip-json-comments@3.1.1","npm","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)" 510 | "supports-color@5.5.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 511 | "supports-color@7.2.0","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 512 | "supports-color@8.1.1","npm","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)" 513 | "supports-hyperlinks@2.2.0","npm","MIT","Copyright (c) James Talmage (github.com/jamestalmage)" 514 | "symbol-tree@3.2.4","npm","MIT","Copyright (c) 2015 Joris van der Wel" 515 | "table@6.7.1","npm","BSD-3-Clause","Copyright (c) 2018, Gajus Kuizinas (http://gajus.com/). All rights reserved." 516 | "tapable@1.1.3","npm","MIT","Copyright (c) Tobias Koppers @sokra" 517 | "tapable@2.2.0","npm","MIT","Copyright JS Foundation and other contributors" 518 | "terminal-link@2.1.1","npm","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)" 519 | "terser-webpack-plugin@5.1.4","npm","MIT","Copyright JS Foundation and other contributors" 520 | "terser@5.7.1","npm","BSD-2-Clause","Copyright 2012-2018 (c) Mihai Bazon " 521 | "test-exclude@6.0.0","npm","ISC","Copyright (c) 2016, Contributors" 522 | "text-table@0.2.0","npm","MIT","" 523 | "throat@6.0.1","npm","MIT","Copyright (c) 2013 Forbes Lindesay" 524 | "tiny-invariant@1.1.0","npm","MIT","Copyright (c) 2019 Alexander Reardon" 525 | "tiny-warning@1.0.3","npm","MIT","Copyright (c) 2019 Alexander Reardon" 526 | "tmpl@1.0.4","npm","BSD-3-Clause","Copyright (c) 2014, Naitik Shah. All rights reserved." 527 | "to-fast-properties@2.0.0","npm","MIT","Copyright (c) 2014 Petka Antonov. 2015 Sindre Sorhus" 528 | "to-regex-range@5.0.1","npm","MIT","Copyright (c) 2015-present, Jon Schlinkert." 529 | "tough-cookie@4.0.0","npm","BSD-3-Clause","Copyright (c) 2015, Salesforce.com, Inc.. All rights reserved." 530 | "tr46@2.1.0","npm","MIT","Copyright (c) 2016 Sebastian Mayr" 531 | "ts-jest@27.0.3","npm","MIT","Copyright (c) 2016-2018" 532 | "ts-loader@8.0.18","npm","MIT","Copyright (c) 2015 TypeStrong" 533 | "tsconfig-paths-webpack-plugin@3.5.1","npm","MIT","Copyright (c) 2016 Jonas Kello" 534 | "tsconfig-paths@3.10.1","npm","MIT","Copyright (c) 2016 Jonas Kello" 535 | "tslib@1.14.1","npm","0BSD","Copyright (c) Microsoft Corporation." 536 | "tsutils@3.21.0","npm","MIT","Copyright (c) 2017 Klaus Meinhardt" 537 | "type-check@0.3.2","npm","MIT","Copyright (c) George Zahariev" 538 | "type-check@0.4.0","npm","MIT","Copyright (c) George Zahariev" 539 | "type-detect@4.0.8","npm","MIT","Copyright (c) 2013 Jake Luer (http://alogicalparadox.com)" 540 | "type-fest@0.21.3","npm","(MIT OR CC0-1.0)","Copyright (c) Sindre Sorhus (https:/sindresorhus.com)" 541 | "type-fest@0.8.1","npm","(MIT OR CC0-1.0)","Copyright (c) Sindre Sorhus (sindresorhus.com)" 542 | "typedarray-to-buffer@3.1.5","npm","MIT","Copyright (c) Feross Aboukhadijeh" 543 | "typescript@4.1.5","npm","Apache-2.0","" 544 | "unbox-primitive@1.0.1","npm","MIT","Copyright (c) 2019 Jordan Harband" 545 | "universalify@0.1.2","npm","MIT","Copyright (c) 2017, Ryan Zimmerman " 546 | "uri-js@4.4.1","npm","BSD-2-Clause","Copyright 2011 Gary Court. All rights reserved." 547 | "util-deprecate@1.0.2","npm","MIT","Copyright (c) 2014 Nathan Rajlich " 548 | "v8-compile-cache@2.3.0","npm","MIT","Copyright (c) 2019 Andres Suarez" 549 | "v8-to-istanbul@8.0.0","npm","ISC","Copyright (c) 2017, Contributors" 550 | "validate-npm-package-license@3.0.4","npm","Apache-2.0","" 551 | "value-equal@1.0.1","npm","MIT","Copyright (c) Michael Jackson 2016-2018" 552 | "w3c-hr-time@1.0.2","npm","MIT","Copyright (c) 2017 Tiancheng ""Timothy"" Gu and other contributors" 553 | "w3c-xmlserializer@2.0.0","npm","MIT","Copyright © 2016 Sebastian Mayr" 554 | "walker@1.0.7","npm","Apache-2.0","Copyright 2013 Naitik Shah" 555 | "watchpack@2.2.0","npm","MIT","Copyright JS Foundation and other contributors" 556 | "webidl-conversions@5.0.0","npm","BSD-2-Clause","Copyright (c) 2014, Domenic Denicola. All rights reserved." 557 | "webidl-conversions@6.1.0","npm","BSD-2-Clause","Copyright (c) 2014, Domenic Denicola. All rights reserved." 558 | "webpack-cli@4.7.2","npm","MIT","Copyright JS Foundation and other contributors" 559 | "webpack-merge@5.8.0","npm","MIT","Copyright (c) 2015 Juho Vepsalainen" 560 | "webpack-sources@2.3.0","npm","MIT","Copyright (c) 2017 JS Foundation and other contributors" 561 | "webpack@5.28.0","npm","MIT","Copyright JS Foundation and other contributors" 562 | "whatwg-encoding@1.0.5","npm","MIT","Copyright © 2016–2018 Domenic Denicola " 563 | "whatwg-mimetype@2.3.0","npm","MIT","Copyright © 2017–2018 Domenic Denicola " 564 | "whatwg-url@8.7.0","npm","MIT","Copyright (c) 2015–2016 Sebastian Mayr" 565 | "which-boxed-primitive@1.0.2","npm","MIT","Copyright (c) 2019 Jordan Harband" 566 | "which@1.3.1","npm","ISC","Copyright (c) Isaac Z. Schlueter and Contributors" 567 | "which@2.0.2","npm","ISC","Copyright (c) Isaac Z. Schlueter and Contributors" 568 | "wildcard@2.0.0","npm","MIT","Copyright (c) 2017 Damon Oehlman " 569 | "word-wrap@1.2.3","npm","MIT","Copyright (c) 2014-2017, Jon Schlinkert" 570 | "wrap-ansi@7.0.0","npm","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)" 571 | "wrappy@1.0.2","npm","ISC","Copyright (c) Isaac Z. Schlueter and Contributors" 572 | "write-file-atomic@3.0.3","npm","ISC","Copyright (c) 2015, Rebecca Turner" 573 | "ws@7.5.3","npm","MIT","Copyright (c) 2011 Einar Otto Stangvik " 574 | "xml-name-validator@3.0.0","npm","Apache-2.0","" 575 | "xmlchars@2.2.0","npm","MIT","Copyright Louis-Dominique Dubeau and contributors to xmlchars" 576 | "y18n@5.0.8","npm","ISC","Copyright (c) 2015, Contributors" 577 | "yallist@4.0.0","npm","ISC","Copyright (c) Isaac Z. Schlueter and Contributors" 578 | "yargs-parser@20.2.9","npm","ISC","Copyright (c) 2016, Contributors" 579 | "yargs@16.2.0","npm","MIT","Copyright 2010 James Halliday (mail@substack.net); Modified work Copyright 2014 Contributors (ben@npmjs.com)" 580 | "yocto-queue@0.1.0","npm","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)" --------------------------------------------------------------------------------