You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1 line
75 KiB
Plaintext
1 line
75 KiB
Plaintext
{"version":3,"sources":["components/BreakPoint.tsx","lib/utils.ts","lib/message.ts","components/FlowPreview.tsx","components/EditFlow.tsx","components/ViewFlow.tsx","lib/flow.ts","lib/connection.ts","App.tsx","reportWebVitals.ts","index.tsx"],"names":["BreakPoint","props","state","show","rule","method","url","action","haveRules","handleClose","bind","handleShow","handleSave","this","setState","rules","push","onSave","length","variant","Button","size","onClick","Modal","onHide","Header","closeButton","Title","Body","Form","Group","as","Row","Label","column","sm","Col","Control","value","onChange","e","target","parseInt","Footer","React","Component","isTextBody","payload","header","test","join","getSize","len","isNaN","toFixed","arrayBufferToBase64","buf","binary","bytes","Uint8Array","byteLength","i","String","fromCharCode","btoa","bufHexView","str","viewStr","toString","padStart","MessageType","FlowPreview","nextProps","isSelected","objA","objB","keysA","Object","keys","keysB","key","undefined","shallowEqual","flow","fp","classNames","waitIntercept","className","onShowDetail","no","host","path","contentType","statusCode","costTime","SendMessageType","allMessageBytes","CONN","CONN_CLOSE","REQUEST","REQUEST_BODY","RESPONSE","RESPONSE_BODY","buildMessageEdit","messageType","DROP_REQUEST","DROP_RESPONSE","view","set","TextEncoder","encode","id","body","CHANGE_REQUEST","request","CHANGE_RESPONSE","Error","response","ArrayBuffer","bodyLen","headerBytes","JSON","stringify","data","view2","DataView","setUint32","EditFlow","alertMsg","content","msg","firstLine","headerLines","map","valstr","bodyLines","TextDecoder","decode","stringifyRequest","stringifyResponse","when","firstIndex","indexOf","slice","split","secondIndex","vals","proto","parseRequest","showAlert","onChangeRequest","parseResponse","onChangeResponse","msgType","onMessage","rows","Alert","ViewFlow","flowTab","copied","requestBodyViewTab","responseBodyLineBreak","style","color","pv","previewResponseBody","type","src","keyStyle","stringStyle","valueStyle","booleanStyle","previewRequestBody","hexviewResponseBody","conn","getConn","serverConn","address","peername","clientConn","searchItems","search","searchParams","forEach","onClose","onReRenderFlows","padding","disabled","curl","fetchToCurl","headers","reduce","obj","requestBody","copy","setTimeout","marginBottom","isTextRequest","requestBodyPreview","isTextResponse","FormCheck","inline","checked","label","whiteSpace","responseBody","preview","hexview","detail","Flow","connMgr","connId","_size","headerContentLengthExist","startTime","Date","now","endTime","status","_isTextRequest","_isTextResponse","_requestBody","_hexviewRequestBody","_responseBody","_previewResponseBody","_previewRequestBody","_hexviewResponseBody","curNo","flowRequestMsg","URL","pathname","includes","startsWith","hexviewRequestBody","get","FlowManager","items","_map","filterText","filterTimer","num","max","Map","text","trim","endsWith","reg","RegExp","filter","item","err","oldest","shift","delete","callback","clearTimeout","ConnectionManager","wsReconnIntervals","App","flowMgr","ws","wsUnmountClose","tableBottomRef","wsReconnCount","flows","showList","wsStatus","createRef","initWs","close","document","WebSocket","binaryType","onopen","onerror","evt","console","error","onclose","waitSeconds","info","onmessage","meta","Int8Array","resp","contentStr","parse","parseMessage","add","shouldScroll","current","element","viewWidth","window","innerWidth","documentElement","clientWidth","viewHeight","innerHeight","clientHeight","getBoundingClientRect","top","right","bottom","left","isInViewPort","scrollIntoView","behavior","addRequestBody","addResponse","addResponseBody","clear","placeholder","changeFilterLazy","CHANGE_BREAK_POINT_RULES","rulesBytes","buildMessageMeta","send","Table","striped","bordered","tableLayout","width","f","ref","height","visibility","reportWebVitals","onPerfEntry","Function","then","getCLS","getFID","getFCP","getLCP","getTTFB","ReactDOM","render","StrictMode","getElementById"],"mappings":"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","file":"static/js/main.2abbef8f.chunk.js","sourcesContent":["import React from 'react'\nimport Button from 'react-bootstrap/Button'\nimport Modal from 'react-bootstrap/Modal'\nimport Form from 'react-bootstrap/Form'\nimport Row from 'react-bootstrap/Row'\nimport Col from 'react-bootstrap/Col'\n\ntype Method = 'ALL' | 'GET' | 'POST' | 'PUT' | 'DELETE' | ''\ntype Action = 1 | 2 | 3\ninterface IRule {\n method: Method\n url: string\n action: Action\n}\n\ninterface IState {\n show: boolean\n rule: IRule\n haveRules: boolean\n}\n\ninterface IProps {\n onSave: (rules: IRule[]) => void\n}\n\nclass BreakPoint extends React.Component<IProps, IState> {\n constructor(props: IProps) {\n super(props)\n\n this.state = {\n show: false,\n\n rule: {\n method: 'ALL',\n url: '',\n action: 1,\n },\n\n haveRules: false,\n }\n\n this.handleClose = this.handleClose.bind(this)\n this.handleShow = this.handleShow.bind(this)\n this.handleSave = this.handleSave.bind(this)\n }\n\n handleClose() {\n this.setState({ show: false })\n }\n\n handleShow() {\n this.setState({ show: true })\n }\n\n handleSave() {\n const { rule } = this.state\n const rules: IRule[] = []\n if (rule.url) {\n rules.push({\n method: rule.method === 'ALL' ? '' : rule.method,\n url: rule.url,\n action: rule.action,\n })\n }\n\n this.props.onSave(rules)\n this.handleClose()\n\n this.setState({ haveRules: rules.length ? true : false })\n }\n\n render() {\n const { rule, haveRules } = this.state\n const variant = haveRules ? 'success' : 'primary'\n\n return (\n <div>\n <Button variant={variant} size=\"sm\" onClick={this.handleShow}>BreakPoint</Button>\n\n <Modal show={this.state.show} onHide={this.handleClose}>\n <Modal.Header closeButton>\n <Modal.Title>Set BreakPoint</Modal.Title>\n </Modal.Header>\n\n <Modal.Body>\n <Form.Group as={Row}>\n <Form.Label column sm={2}>Method</Form.Label>\n <Col sm={10}>\n <Form.Control as=\"select\" value={rule.method} onChange={e => { this.setState({ rule: { ...rule, method: e.target.value as Method } }) }}>\n <option>ALL</option>\n <option>GET</option>\n <option>POST</option>\n <option>PUT</option>\n <option>DELETE</option>\n </Form.Control>\n </Col>\n </Form.Group>\n\n <Form.Group as={Row}>\n <Form.Label column sm={2}>URL</Form.Label>\n <Col sm={10}><Form.Control value={rule.url} onChange={e => { this.setState({ rule: { ...rule, url: e.target.value } }) }} /></Col>\n </Form.Group>\n\n <Form.Group as={Row}>\n <Form.Label column sm={2}>Action</Form.Label>\n <Col sm={10}>\n <Form.Control as=\"select\" value={rule.action} onChange={e => { this.setState({ rule: { ...rule, action: parseInt(e.target.value) as Action } }) }}>\n <option value=\"1\">Request</option>\n <option value=\"2\">Response</option>\n <option value=\"3\">Both</option>\n </Form.Control>\n </Col>\n </Form.Group>\n </Modal.Body>\n\n <Modal.Footer>\n <Button variant=\"secondary\" onClick={this.handleClose}>\n Close\n </Button>\n <Button variant=\"primary\" onClick={this.handleSave}>\n Save\n </Button>\n </Modal.Footer>\n </Modal>\n </div>\n )\n }\n}\n\nexport default BreakPoint\n","import type { IRequest, IResponse } from './flow'\n\nexport const isTextBody = (payload: IRequest | IResponse) => {\n if (!payload) return false\n if (!payload.header) return false\n if (!payload.header['Content-Type']) return false\n\n return /text|javascript|json|x-www-form-urlencoded|xml|form-data/.test(payload.header['Content-Type'].join(''))\n}\n\nexport const getSize = (len: number) => {\n if (!len) return '0'\n if (isNaN(len)) return '0'\n if (len <= 0) return '0'\n\n if (len < 1024) return `${len} B`\n if (len < 1024 * 1024) return `${(len / 1024).toFixed(2)} KB`\n return `${(len / (1024 * 1024)).toFixed(2)} MB`\n}\n\nexport const shallowEqual = (objA: any, objB: any) => {\n if (objA === objB) return true\n\n const keysA = Object.keys(objA)\n const keysB = Object.keys(objB)\n if (keysA.length !== keysB.length) return false\n\n for (let i = 0; i < keysA.length; i++) {\n const key = keysA[i]\n if (objB[key] === undefined || objA[key] !== objB[key]) return false\n }\n return true\n}\n\nexport const arrayBufferToBase64 = (buf: ArrayBuffer) => {\n let binary = ''\n const bytes = new Uint8Array(buf)\n const len = bytes.byteLength\n for (let i = 0; i < len; i++) {\n binary += String.fromCharCode(bytes[i])\n }\n return btoa(binary)\n}\n\nexport const bufHexView = (buf: ArrayBuffer) => {\n let str = ''\n const bytes = new Uint8Array(buf)\n const len = bytes.byteLength\n\n let viewStr = ''\n\n str += '00000000: '\n for (let i = 0; i < len; i++) {\n str += bytes[i].toString(16).padStart(2, '0') + ' '\n\n if (bytes[i] >= 32 && bytes[i] <= 126) {\n viewStr += String.fromCharCode(bytes[i])\n } else {\n viewStr += '.'\n }\n\n if ((i + 1) % 16 === 0) {\n str += ' ' + viewStr\n viewStr = ''\n str += `\\n${(i + 1).toString(16).padStart(8, '0')}: `\n } else if ((i + 1) % 8 === 0) {\n str += ' '\n }\n }\n\n // 补充最后一行的空白\n if (viewStr.length > 0) {\n for (let i = viewStr.length; i < 16; i++) {\n str += ' ' + ' '\n if ((i + 1) % 8 === 0) str += ' '\n }\n str += ' ' + viewStr\n }\n\n return str\n}\n\n// https://github.com/febobo/web-interview/issues/84\nexport function isInViewPort(element: HTMLElement) {\n const viewWidth = window.innerWidth || document.documentElement.clientWidth\n const viewHeight = window.innerHeight || document.documentElement.clientHeight\n const {\n top,\n right,\n bottom,\n left,\n } = element.getBoundingClientRect()\n\n return (\n top >= 0 &&\n left >= 0 &&\n right <= viewWidth &&\n bottom <= viewHeight\n )\n}\n","import type { IConnection } from './connection'\nimport type { Flow, IFlowRequest, IRequest, IResponse } from './flow'\n\nexport enum MessageType {\n CONN = 0,\n CONN_CLOSE = 5,\n REQUEST = 1,\n REQUEST_BODY = 2,\n RESPONSE = 3,\n RESPONSE_BODY = 4,\n}\n\nconst allMessageBytes = [\n MessageType.CONN,\n MessageType.CONN_CLOSE,\n MessageType.REQUEST,\n MessageType.REQUEST_BODY,\n MessageType.RESPONSE,\n MessageType.RESPONSE_BODY,\n]\n\nexport interface IMessage {\n type: MessageType\n id: string\n waitIntercept: boolean\n content?: ArrayBuffer | IFlowRequest | IResponse | IConnection\n}\n\n// type: 0/1/2/3/4\n// messageFlow\n// version 1 byte + type 1 byte + id 36 byte + waitIntercept 1 byte + content left bytes\nexport const parseMessage = (data: ArrayBuffer): IMessage | null => {\n if (data.byteLength < 39) return null\n const meta = new Int8Array(data.slice(0, 39))\n const version = meta[0]\n if (version !== 2) return null\n const type = meta[1] as MessageType\n if (!allMessageBytes.includes(type)) return null\n const id = new TextDecoder().decode(data.slice(2, 38))\n const waitIntercept = meta[38] === 1\n\n const resp: IMessage = {\n type,\n id,\n waitIntercept,\n }\n if (data.byteLength === 39) return resp\n if (type === MessageType.REQUEST_BODY || type === MessageType.RESPONSE_BODY) {\n resp.content = data.slice(39)\n return resp\n }\n\n const contentStr = new TextDecoder().decode(data.slice(39))\n let content: any\n try {\n content = JSON.parse(contentStr)\n } catch (err) {\n return null\n }\n\n resp.content = content\n return resp\n}\n\nexport enum SendMessageType {\n CHANGE_REQUEST = 11,\n CHANGE_RESPONSE = 12,\n DROP_REQUEST = 13,\n DROP_RESPONSE = 14,\n CHANGE_BREAK_POINT_RULES = 21,\n}\n\n// type: 11/12/13/14\n// messageEdit\n// version 1 byte + type 1 byte + id 36 byte + header len 4 byte + header content bytes + body len 4 byte + [body content bytes]\nexport const buildMessageEdit = (messageType: SendMessageType, flow: Flow) => {\n if (messageType === SendMessageType.DROP_REQUEST || messageType === SendMessageType.DROP_RESPONSE) {\n const view = new Uint8Array(38)\n view[0] = 1\n view[1] = messageType\n view.set(new TextEncoder().encode(flow.id), 2)\n return view\n }\n\n let header: Omit<IRequest, 'body'> | Omit<IResponse, 'body'>\n let body: ArrayBuffer | Uint8Array | undefined\n\n if (messageType === SendMessageType.CHANGE_REQUEST) {\n ({ body, ...header } = flow.request)\n } else if (messageType === SendMessageType.CHANGE_RESPONSE) {\n ({ body, ...header } = flow.response as IResponse)\n } else {\n throw new Error('invalid message type')\n }\n\n if (body instanceof ArrayBuffer) body = new Uint8Array(body)\n const bodyLen = (body && body.byteLength) ? body.byteLength : 0\n\n if ('Content-Encoding' in header.header) delete header.header['Content-Encoding']\n if ('Transfer-Encoding' in header.header) delete header.header['Transfer-Encoding']\n header.header['Content-Length'] = [String(bodyLen)]\n\n const headerBytes = new TextEncoder().encode(JSON.stringify(header))\n const len = 2 + 36 + 4 + headerBytes.byteLength + 4 + bodyLen\n const data = new ArrayBuffer(len)\n const view = new Uint8Array(data)\n view[0] = 1\n view[1] = messageType\n view.set(new TextEncoder().encode(flow.id), 2)\n view.set(headerBytes, 2 + 36 + 4)\n if (bodyLen) view.set(body as Uint8Array, 2 + 36 + 4 + headerBytes.byteLength + 4)\n\n const view2 = new DataView(data)\n view2.setUint32(2 + 36, headerBytes.byteLength)\n view2.setUint32(2 + 36 + 4 + headerBytes.byteLength, bodyLen)\n\n return view\n}\n\n// type: 21\n// messageMeta\n// version 1 byte + type 1 byte + content left bytes\nexport const buildMessageMeta = (messageType: SendMessageType, rules: any) => {\n if (messageType !== SendMessageType.CHANGE_BREAK_POINT_RULES) {\n throw new Error('invalid message type')\n }\n\n const rulesBytes = new TextEncoder().encode(JSON.stringify(rules))\n const view = new Uint8Array(2 + rulesBytes.byteLength)\n view[0] = 1\n view[1] = messageType\n view.set(rulesBytes, 2)\n\n return view\n}\n","import React from 'react'\nimport { shallowEqual } from '../lib/utils'\nimport type { IFlowPreview } from '../lib/flow'\n\ninterface IProps {\n flow: IFlowPreview\n isSelected: boolean\n onShowDetail: () => void\n}\n\nclass FlowPreview extends React.Component<IProps> {\n shouldComponentUpdate(nextProps: IProps) {\n if (nextProps.isSelected === this.props.isSelected && shallowEqual(nextProps.flow, this.props.flow)) {\n return false\n }\n return true\n }\n\n render() {\n const fp = this.props.flow\n\n const classNames = []\n if (this.props.isSelected) classNames.push('tr-selected')\n if (fp.waitIntercept) classNames.push('tr-wait-intercept')\n\n return (\n <tr className={classNames.length ? classNames.join(' ') : undefined}\n onClick={() => {\n this.props.onShowDetail()\n }}\n >\n <td>{fp.no}</td>\n <td>{fp.method}</td>\n <td>{fp.host}</td>\n <td>{fp.path}</td>\n <td>{fp.contentType}</td>\n <td>{fp.statusCode}</td>\n <td>{fp.size}</td>\n <td>{fp.costTime}</td>\n </tr>\n )\n }\n}\n\nexport default FlowPreview\n","import React from 'react'\nimport Button from 'react-bootstrap/Button'\nimport Modal from 'react-bootstrap/Modal'\nimport Form from 'react-bootstrap/Form'\nimport Alert from 'react-bootstrap/Alert'\nimport { SendMessageType, buildMessageEdit } from '../lib/message'\nimport { isTextBody } from '../lib/utils'\nimport type { Flow, Header, IRequest, IResponse } from '../lib/flow'\n\nconst stringifyRequest = (request: IRequest) => {\n const firstLine = `${request.method} ${request.url}`\n const headerLines = Object.keys(request.header).map(key => {\n const valstr = request.header[key].join(' \\t ') // for parse convenience\n return `${key}: ${valstr}`\n }).join('\\n')\n\n let bodyLines = ''\n if (request.body && isTextBody(request)) bodyLines = new TextDecoder().decode(request.body)\n\n return `${firstLine}\\n\\n${headerLines}\\n\\n${bodyLines}`\n}\n\nconst parseRequest = (content: string): IRequest | undefined => {\n const firstIndex = content.indexOf('\\n\\n')\n if (firstIndex <= 0) return\n\n const firstLine = content.slice(0, firstIndex)\n const [method, url] = firstLine.split(' ')\n if (!method || !url) return\n\n const secondIndex = content.indexOf('\\n\\n', firstIndex + 2)\n if (secondIndex <= 0) return\n const headerLines = content.slice(firstIndex + 2, secondIndex)\n const header: Header = {}\n for (const line of headerLines.split('\\n')) {\n const [key, vals] = line.split(': ')\n if (!key || !vals) return\n header[key] = vals.split(' \\t ')\n }\n\n const bodyLines = content.slice(secondIndex + 2)\n let body: ArrayBuffer | undefined\n if (bodyLines) body = new TextEncoder().encode(bodyLines)\n\n return {\n method,\n url,\n proto: '',\n header,\n body,\n }\n}\n\nconst stringifyResponse = (response: IResponse) => {\n const firstLine = `${response.statusCode}`\n const headerLines = Object.keys(response.header).map(key => {\n const valstr = response.header[key].join(' \\t ') // for parse convenience\n return `${key}: ${valstr}`\n }).join('\\n')\n\n let bodyLines = ''\n if (response.body && isTextBody(response)) bodyLines = new TextDecoder().decode(response.body)\n\n return `${firstLine}\\n\\n${headerLines}\\n\\n${bodyLines}`\n}\n\nconst parseResponse = (content: string): IResponse | undefined => {\n const firstIndex = content.indexOf('\\n\\n')\n if (firstIndex <= 0) return\n\n const firstLine = content.slice(0, firstIndex)\n const statusCode = parseInt(firstLine)\n if (isNaN(statusCode)) return\n\n const secondIndex = content.indexOf('\\n\\n', firstIndex + 2)\n if (secondIndex <= 0) return\n const headerLines = content.slice(firstIndex + 2, secondIndex)\n const header: Header = {}\n for (const line of headerLines.split('\\n')) {\n const [key, vals] = line.split(': ')\n if (!key || !vals) return\n header[key] = vals.split(' \\t ')\n }\n\n const bodyLines = content.slice(secondIndex + 2)\n let body: ArrayBuffer | undefined\n if (bodyLines) body = new TextEncoder().encode(bodyLines)\n\n return {\n statusCode,\n header,\n body,\n }\n}\n\n\ninterface IProps {\n flow: Flow\n onChangeRequest: (request: IRequest) => void\n onChangeResponse: (response: IResponse) => void\n onMessage: (msg: ArrayBufferLike) => void\n}\n\ninterface IState {\n show: boolean\n alertMsg: string\n content: string\n}\n\nclass EditFlow extends React.Component<IProps, IState> {\n constructor(props: IProps) {\n super(props)\n\n this.state = {\n show: false,\n alertMsg: '',\n content: '',\n }\n\n this.handleClose = this.handleClose.bind(this)\n this.handleShow = this.handleShow.bind(this)\n this.handleSave = this.handleSave.bind(this)\n }\n\n showAlert(msg: string) {\n this.setState({ alertMsg: msg })\n }\n\n handleClose() {\n this.setState({ show: false })\n }\n\n handleShow() {\n const { flow } = this.props\n const when = flow.response ? 'response' : 'request'\n\n let content = ''\n if (when === 'request') {\n content = stringifyRequest(flow.request)\n } else {\n content = stringifyResponse(flow.response as IResponse)\n }\n\n this.setState({ show: true, alertMsg: '', content })\n }\n\n handleSave() {\n const { flow } = this.props\n const when = flow.response ? 'response' : 'request'\n\n const { content } = this.state\n\n if (when === 'request') {\n const request = parseRequest(content)\n if (!request) {\n this.showAlert('parse error')\n return\n }\n\n this.props.onChangeRequest(request)\n this.handleClose()\n } else {\n const response = parseResponse(content)\n if (!response) {\n this.showAlert('parse error')\n return\n }\n\n this.props.onChangeResponse(response)\n this.handleClose()\n }\n }\n\n render() {\n const { flow } = this.props\n if (!flow.waitIntercept) return null\n\n const { alertMsg } = this.state\n\n const when = flow.response ? 'response' : 'request'\n\n return (\n <div className=\"flow-wait-area\">\n\n <Button size=\"sm\" onClick={this.handleShow}>Edit</Button>\n\n <Button size=\"sm\" onClick={() => {\n const msgType = when === 'response' ? SendMessageType.CHANGE_RESPONSE : SendMessageType.CHANGE_REQUEST\n const msg = buildMessageEdit(msgType, flow)\n this.props.onMessage(msg)\n }}>Continue</Button>\n\n <Button size=\"sm\" onClick={() => {\n const msgType = when === 'response' ? SendMessageType.DROP_RESPONSE : SendMessageType.DROP_REQUEST\n const msg = buildMessageEdit(msgType, flow)\n this.props.onMessage(msg)\n }}>Drop</Button>\n\n\n <Modal size=\"lg\" show={this.state.show} onHide={this.handleClose}>\n <Modal.Header closeButton>\n <Modal.Title>Edit {when === 'request' ? 'Request' : 'Response'}</Modal.Title>\n </Modal.Header>\n\n <Modal.Body>\n <Form.Group>\n <Form.Control as=\"textarea\" rows={10} value={this.state.content} onChange={e => { this.setState({ content: e.target.value }) }} />\n </Form.Group>\n {\n !alertMsg ? null : <Alert variant=\"danger\">{alertMsg}</Alert>\n }\n </Modal.Body>\n\n <Modal.Footer>\n <Button variant=\"secondary\" onClick={this.handleClose}>\n Close\n </Button>\n <Button variant=\"primary\" onClick={this.handleSave}>\n Save\n </Button>\n </Modal.Footer>\n </Modal>\n\n </div>\n )\n }\n}\n\nexport default EditFlow\n","import React from 'react'\nimport Button from 'react-bootstrap/Button'\nimport FormCheck from 'react-bootstrap/FormCheck'\nimport fetchToCurl from 'fetch-to-curl'\nimport copy from 'copy-to-clipboard'\nimport JSONPretty from 'react-json-pretty'\nimport { isTextBody } from '../lib/utils'\nimport type { Flow, IResponse } from '../lib/flow'\nimport EditFlow from './EditFlow'\n\ninterface Iprops {\n flow: Flow | null\n onClose: () => void\n onReRenderFlows: () => void\n onMessage: (msg: ArrayBufferLike) => void\n}\n\ninterface IState {\n flowTab: 'Headers' | 'Preview' | 'Response' | 'Hexview' | 'Detail'\n copied: boolean\n requestBodyViewTab: 'Raw' | 'Preview'\n responseBodyLineBreak: boolean\n}\n\nclass ViewFlow extends React.Component<Iprops, IState> {\n constructor(props: Iprops) {\n super(props)\n\n this.state = {\n flowTab: 'Detail',\n copied: false,\n requestBodyViewTab: 'Raw',\n responseBodyLineBreak: false,\n }\n }\n\n preview() {\n const { flow } = this.props\n if (!flow) return null\n const response = flow.response\n if (!response) return null\n\n if (!(response.body && response.body.byteLength)) {\n return <div style={{ color: 'gray' }}>No response</div>\n }\n\n const pv = flow.previewResponseBody()\n if (!pv) return <div style={{ color: 'gray' }}>Not support preview</div>\n\n if (pv.type === 'image') {\n return <img src={`data:image/png;base64,${pv.data}`} />\n }\n else if (pv.type === 'json') {\n return <div><JSONPretty data={pv.data} keyStyle={'color: rgb(130,40,144);'} stringStyle={'color: rgb(153,68,60);'} valueStyle={'color: rgb(25,1,199);'} booleanStyle={'color: rgb(94,105,192);'} /></div>\n }\n\n return <div style={{ color: 'gray' }}>Not support preview</div>\n }\n\n requestBodyPreview() {\n const { flow } = this.props\n if (!flow) return null\n\n const pv = flow.previewRequestBody()\n if (!pv) return <div style={{ color: 'gray' }}>Not support preview</div>\n\n if (pv.type === 'json') {\n return <div><JSONPretty data={pv.data} keyStyle={'color: rgb(130,40,144);'} stringStyle={'color: rgb(153,68,60);'} valueStyle={'color: rgb(25,1,199);'} booleanStyle={'color: rgb(94,105,192);'} /></div>\n }\n else if (pv.type === 'binary') {\n return <div><pre>{pv.data}</pre></div>\n }\n\n return <div style={{ color: 'gray' }}>Not support preview</div>\n }\n\n hexview() {\n const { flow } = this.props\n if (!flow) return null\n const response = flow.response\n if (!response) return null\n\n if (!(response.body && response.body.byteLength)) {\n return <div style={{ color: 'gray' }}>No response</div>\n }\n\n return <pre>{flow.hexviewResponseBody()}</pre>\n }\n\n detail() {\n const { flow } = this.props\n if (!flow) return null\n\n const conn = flow.getConn()\n if (!conn) return null\n\n return (\n <div>\n <div className=\"header-block\">\n <p>Server Connection</p>\n <div className=\"header-block-content\">\n <p>Address: {conn.serverConn.address}</p>\n <p>Resolved Address: {conn.serverConn.peername}</p>\n </div>\n </div>\n <div className=\"header-block\">\n <p>Client Connection</p>\n <div className=\"header-block-content\">\n <p>Address: {conn.clientConn.address}</p>\n </div>\n </div>\n </div>\n )\n }\n\n render() {\n if (!this.props.flow) return null\n\n const flow = this.props.flow\n const flowTab = this.state.flowTab\n\n const request = flow.request\n const response: IResponse = (flow.response || {}) as any\n\n // Query String Parameters\n const searchItems: Array<{ key: string; value: string }> = []\n if (flow.url && flow.url.search) {\n flow.url.searchParams.forEach((value, key) => {\n searchItems.push({ key, value })\n })\n }\n\n return (\n <div className=\"flow-detail\">\n <div className=\"header-tabs\">\n <span onClick={() => { this.props.onClose() }}>x</span>\n <span className={flowTab === 'Detail' ? 'selected' : undefined} onClick={() => { this.setState({ flowTab: 'Detail' }) }}>Detail</span>\n <span className={flowTab === 'Headers' ? 'selected' : undefined} onClick={() => { this.setState({ flowTab: 'Headers' }) }}>Headers</span>\n <span className={flowTab === 'Preview' ? 'selected' : undefined} onClick={() => { this.setState({ flowTab: 'Preview' }) }}>Preview</span>\n <span className={flowTab === 'Response' ? 'selected' : undefined} onClick={() => { this.setState({ flowTab: 'Response' }) }}>Response</span>\n <span className={flowTab === 'Hexview' ? 'selected' : undefined} onClick={() => { this.setState({ flowTab: 'Hexview' }) }}>Hexview</span>\n\n <EditFlow\n flow={flow}\n onChangeRequest={request => {\n flow.request.method = request.method\n flow.request.url = request.url\n flow.request.header = request.header\n if (isTextBody(flow.request)) flow.request.body = request.body\n this.props.onReRenderFlows()\n }}\n onChangeResponse={response => {\n if (!flow.response) flow.response = {} as IResponse\n\n flow.response.statusCode = response.statusCode\n flow.response.header = response.header\n if (isTextBody(flow.response)) flow.response.body = response.body\n this.props.onReRenderFlows()\n }}\n onMessage={msg => {\n this.props.onMessage(msg)\n flow.waitIntercept = false\n this.props.onReRenderFlows()\n }}\n />\n\n </div>\n\n <div style={{ padding: '20px' }}>\n {\n !(flowTab === 'Headers') ? null :\n <div>\n <p><Button size=\"sm\" variant={this.state.copied ? 'success' : 'primary'} disabled={this.state.copied} onClick={() => {\n const curl = fetchToCurl({\n url: flow.request.url,\n method: flow.request.method,\n headers: Object.keys(flow.request.header).reduce((obj: any, key: string) => {\n obj[key] = flow.request.header[key][0]\n return obj\n }, {}),\n body: flow.requestBody(),\n })\n copy(curl)\n\n this.setState({ copied: true }, () => {\n setTimeout(() => {\n this.setState({ copied: false })\n }, 1000)\n })\n\n }}>{this.state.copied ? 'Copied' : 'Copy as cURL'}</Button></p>\n\n <div className=\"header-block\">\n <p>General</p>\n <div className=\"header-block-content\">\n <p>Request URL: {request.url}</p>\n <p>Request Method: {request.method}</p>\n <p>Status Code: {`${response.statusCode || '(pending)'}`}</p>\n </div>\n </div>\n\n {\n !(response.header) ? null :\n <div className=\"header-block\">\n <p>Response Headers</p>\n <div className=\"header-block-content\">\n {\n Object.keys(response.header).map(key => {\n return (\n <p key={key}>{key}: {response.header[key].join(' ')}</p>\n )\n })\n }\n </div>\n </div>\n }\n\n <div className=\"header-block\">\n <p>Request Headers</p>\n <div className=\"header-block-content\">\n {\n !(request.header) ? null :\n Object.keys(request.header).map(key => {\n return (\n <p key={key}>{key}: {request.header[key].join(' ')}</p>\n )\n })\n }\n </div>\n </div>\n\n {\n !(searchItems.length) ? null :\n <div className=\"header-block\">\n <p>Query String Parameters</p>\n <div className=\"header-block-content\">\n {\n searchItems.map(({ key, value }) => {\n return (\n <p key={key}>{key}: {value}</p>\n )\n })\n }\n </div>\n </div>\n }\n\n {\n !(request.body && request.body.byteLength) ? null :\n <div className=\"header-block\">\n <p>Request Body</p>\n <div className=\"header-block-content\">\n <div>\n <div className=\"request-body-detail\" style={{ marginBottom: '15px' }}>\n <span className={this.state.requestBodyViewTab === 'Raw' ? 'selected' : undefined} onClick={() => { this.setState({ requestBodyViewTab: 'Raw' }) }}>Raw</span>\n <span className={this.state.requestBodyViewTab === 'Preview' ? 'selected' : undefined} onClick={() => { this.setState({ requestBodyViewTab: 'Preview' }) }}>Preview</span>\n </div>\n\n {\n !(this.state.requestBodyViewTab === 'Raw') ? null :\n <div>\n {\n !(flow.isTextRequest()) ? <span style={{ color: 'gray' }}>Not text Request</span> : flow.requestBody()\n }\n </div>\n }\n\n {\n !(this.state.requestBodyViewTab === 'Preview') ? null :\n <div>{this.requestBodyPreview()}</div>\n }\n </div>\n </div>\n </div>\n }\n\n </div>\n }\n\n {\n !(flowTab === 'Response') ? null :\n !(response.body && response.body.byteLength) ? <div style={{ color: 'gray' }}>No response</div> :\n !(flow.isTextResponse()) ? <div style={{ color: 'gray' }}>Not text response</div> :\n <div>\n <div style={{ marginBottom: '20px' }}>\n <FormCheck\n inline\n type=\"checkbox\"\n checked={this.state.responseBodyLineBreak}\n onChange={e => {\n this.setState({ responseBodyLineBreak: e.target.checked })\n }}\n label=\"自动换行\"></FormCheck>\n </div>\n <div style={{ whiteSpace: this.state.responseBodyLineBreak ? 'pre-wrap' : 'pre' }}>\n {flow.responseBody()}\n </div>\n </div>\n }\n\n {\n !(flowTab === 'Preview') ? null :\n <div>{this.preview()}</div>\n }\n\n {\n !(flowTab === 'Hexview') ? null :\n <div>{this.hexview()}</div>\n }\n\n {\n !(flowTab === 'Detail') ? null :\n <div>{this.detail()}</div>\n }\n </div>\n\n </div>\n )\n }\n}\n\nexport default ViewFlow\n","import type { ConnectionManager, IConnection } from './connection'\nimport { IMessage, MessageType } from './message'\nimport { arrayBufferToBase64, bufHexView, getSize, isTextBody } from './utils'\n\nexport type Header = Record<string, string[]>\n\nexport interface IRequest {\n method: string\n url: string\n proto: string\n header: Header\n body?: ArrayBuffer\n}\n\nexport interface IFlowRequest {\n connId: string\n request: IRequest\n}\n\nexport interface IResponse {\n statusCode: number\n header: Header\n body?: ArrayBuffer\n}\n\nexport interface IPreviewBody {\n type: 'image' | 'json' | 'binary'\n data: string | null\n}\n\nexport interface IFlowPreview {\n no: number\n id: string\n waitIntercept: boolean\n host: string\n path: string\n method: string\n statusCode: string\n size: string\n costTime: string\n contentType: string\n}\n\nexport class Flow {\n public no: number\n public id: string\n public connId: string\n public waitIntercept: boolean\n public request: IRequest\n public response: IResponse | null = null\n\n public url: URL\n private path: string\n private _size = 0\n private size = '0'\n private headerContentLengthExist = false\n private contentType = ''\n\n private startTime = Date.now()\n private endTime = 0\n private costTime = '(pending)'\n\n public static curNo = 0\n\n private status: MessageType = MessageType.REQUEST\n\n private _isTextRequest: boolean | null\n private _isTextResponse: boolean | null\n private _requestBody: string | null\n private _hexviewRequestBody: string | null = null\n private _responseBody: string | null\n\n private _previewResponseBody: IPreviewBody | null = null\n private _previewRequestBody: IPreviewBody | null = null\n private _hexviewResponseBody: string | null = null\n\n private connMgr: ConnectionManager;\n private conn: IConnection | undefined;\n\n constructor(msg: IMessage, connMgr: ConnectionManager) {\n this.no = ++Flow.curNo\n this.id = msg.id\n this.waitIntercept = msg.waitIntercept\n\n const flowRequestMsg = msg.content as IFlowRequest\n this.connId = flowRequestMsg.connId\n this.request = flowRequestMsg.request\n\n this.url = new URL(this.request.url)\n this.path = this.url.pathname + this.url.search\n\n this._isTextRequest = null\n this._isTextResponse = null\n this._requestBody = null\n this._responseBody = null\n\n this.connMgr = connMgr\n }\n\n public addRequestBody(msg: IMessage): Flow {\n this.status = MessageType.REQUEST_BODY\n this.waitIntercept = msg.waitIntercept\n this.request.body = msg.content as ArrayBuffer\n return this\n }\n\n public addResponse(msg: IMessage): Flow {\n this.status = MessageType.RESPONSE\n this.waitIntercept = msg.waitIntercept\n this.response = msg.content as IResponse\n\n if (this.response && this.response.header) {\n if (this.response.header['Content-Type'] != null) {\n this.contentType = this.response.header['Content-Type'][0].split(';')[0]\n if (this.contentType.includes('javascript')) this.contentType = 'javascript'\n }\n if (this.response.header['Content-Length'] != null) {\n this.headerContentLengthExist = true\n this._size = parseInt(this.response.header['Content-Length'][0])\n this.size = getSize(this._size)\n }\n }\n\n return this\n }\n\n public addResponseBody(msg: IMessage): Flow {\n this.status = MessageType.RESPONSE_BODY\n this.waitIntercept = msg.waitIntercept\n if (this.response) this.response.body = msg.content as ArrayBuffer\n this.endTime = Date.now()\n this.costTime = String(this.endTime - this.startTime) + ' ms'\n\n if (!this.headerContentLengthExist && this.response && this.response.body) {\n this._size = this.response.body.byteLength\n this.size = getSize(this._size)\n }\n return this\n }\n\n public preview(): IFlowPreview {\n return {\n no: this.no,\n id: this.id,\n waitIntercept: this.waitIntercept,\n host: this.url.host,\n path: this.path,\n method: this.request.method,\n statusCode: this.response ? String(this.response.statusCode) : '(pending)',\n size: this.size,\n costTime: this.costTime,\n contentType: this.contentType,\n }\n }\n\n public isTextRequest(): boolean {\n if (this._isTextRequest !== null) return this._isTextRequest\n this._isTextRequest = isTextBody(this.request)\n return this._isTextRequest\n }\n\n public requestBody(): string {\n if (this._requestBody !== null) return this._requestBody\n if (!this.isTextRequest()) {\n this._requestBody = ''\n return this._requestBody\n }\n if (this.status < MessageType.REQUEST_BODY) return ''\n this._requestBody = new TextDecoder().decode(this.request.body)\n return this._requestBody\n }\n\n public hexviewRequestBody(): string | null {\n if (this._hexviewRequestBody !== null) return this._hexviewRequestBody\n if (this.status < MessageType.REQUEST_BODY) return null\n if (!(this.request?.body?.byteLength)) return null\n\n this._hexviewRequestBody = bufHexView(this.request.body)\n return this._hexviewRequestBody\n }\n\n public isTextResponse(): boolean | null {\n if (this.status < MessageType.RESPONSE) return null\n if (this._isTextResponse !== null) return this._isTextResponse\n this._isTextResponse = isTextBody(this.response as IResponse)\n return this._isTextResponse\n }\n\n public responseBody(): string {\n if (this._responseBody !== null) return this._responseBody\n if (this.status < MessageType.RESPONSE) return ''\n if (!this.isTextResponse()) {\n this._responseBody = ''\n return this._responseBody\n }\n if (this.status < MessageType.RESPONSE_BODY) return ''\n this._responseBody = new TextDecoder().decode(this.response?.body)\n return this._responseBody\n }\n\n public previewResponseBody(): IPreviewBody | null {\n if (this._previewResponseBody) return this._previewResponseBody\n\n if (this.status < MessageType.RESPONSE_BODY) return null\n if (!(this.response?.body?.byteLength)) return null\n\n let contentType: string | undefined\n if (this.response.header['Content-Type']) contentType = this.response.header['Content-Type'][0]\n if (!contentType) return null\n\n if (contentType.startsWith('image/')) {\n this._previewResponseBody = {\n type: 'image',\n data: arrayBufferToBase64(this.response.body),\n }\n }\n else if (contentType.includes('application/json')) {\n this._previewResponseBody = {\n type: 'json',\n data: this.responseBody(),\n }\n }\n\n return this._previewResponseBody\n }\n\n public previewRequestBody(): IPreviewBody | null {\n if (this._previewRequestBody) return this._previewRequestBody\n\n if (this.status < MessageType.REQUEST_BODY) return null\n if (!(this.request.body?.byteLength)) return null\n\n if (!this.isTextRequest()) {\n this._previewRequestBody = {\n type: 'binary',\n data: this.hexviewRequestBody(),\n }\n } else if (/json/.test(this.request.header['Content-Type'].join(''))) {\n this._previewRequestBody = {\n type: 'json',\n data: this.requestBody(),\n }\n }\n\n return this._previewRequestBody\n }\n\n public hexviewResponseBody(): string | null {\n if (this._hexviewResponseBody !== null) return this._hexviewResponseBody\n\n if (this.status < MessageType.RESPONSE_BODY) return null\n if (!(this.response?.body?.byteLength)) return null\n\n this._hexviewResponseBody = bufHexView(this.response.body)\n return this._hexviewResponseBody\n }\n\n public getConn(): IConnection | undefined {\n if (this.conn) return this.conn\n this.conn = this.connMgr.get(this.connId)\n return this.conn\n }\n}\n\nexport class FlowManager {\n private items: Flow[]\n private _map: Map<string, Flow>\n private filterText: string\n private filterTimer: number | null\n private num: number\n private max: number\n\n constructor() {\n this.items = []\n this._map = new Map()\n this.filterText = ''\n this.filterTimer = null\n this.num = 0\n\n this.max = 1000\n }\n\n showList() {\n let text = this.filterText\n if (text) text = text.trim()\n if (!text) return this.items\n\n // regexp\n if (text.startsWith('/') && text.endsWith('/')) {\n text = text.slice(1, text.length - 1).trim()\n if (!text) return this.items\n try {\n const reg = new RegExp(text)\n return this.items.filter(item => {\n return reg.test(item.request.url)\n })\n } catch (err) {\n return this.items\n }\n }\n\n return this.items.filter(item => {\n return item.request.url.includes(text)\n })\n }\n\n add(item: Flow) {\n item.no = ++this.num\n this.items.push(item)\n this._map.set(item.id, item)\n\n if (this.items.length > this.max) {\n const oldest = this.items.shift()\n if (oldest) this._map.delete(oldest.id)\n }\n }\n\n get(id: string) {\n return this._map.get(id)\n }\n\n changeFilter(text: string) {\n this.filterText = text\n }\n\n changeFilterLazy(text: string, callback: () => void) {\n if (this.filterTimer) {\n clearTimeout(this.filterTimer)\n this.filterTimer = null\n }\n\n this.filterTimer = setTimeout(() => {\n this.filterText = text\n callback()\n }, 300) as any\n }\n\n clear() {\n this.items = []\n this._map = new Map()\n }\n}\n","export interface IConnection {\n clientConn: {\n id: string\n tls: boolean\n address: string\n }\n serverConn: {\n id: string\n address: string\n peername: string\n }\n}\n\nexport class ConnectionManager {\n private _map: Map<string, IConnection>\n\n constructor() {\n this._map = new Map()\n }\n\n get(id: string) {\n return this._map.get(id)\n }\n\n add(id: string, conn: IConnection) {\n this._map.set(id, conn)\n }\n\n delete(id: string) {\n this._map.delete(id)\n }\n}\n","import React from 'react'\nimport Table from 'react-bootstrap/Table'\nimport Form from 'react-bootstrap/Form'\nimport Button from 'react-bootstrap/Button'\nimport './App.css'\n\nimport BreakPoint from './components/BreakPoint'\nimport FlowPreview from './components/FlowPreview'\nimport ViewFlow from './components/ViewFlow'\n\nimport { Flow, FlowManager } from './lib/flow'\nimport { parseMessage, SendMessageType, buildMessageMeta, MessageType } from './lib/message'\nimport { isInViewPort } from './lib/utils'\nimport { ConnectionManager, IConnection } from './lib/connection'\n\ninterface IState {\n flows: Flow[]\n flow: Flow | null\n wsStatus: 'open' | 'close' | 'connecting'\n}\n\nconst wsReconnIntervals = [1, 1, 2, 2, 4, 4, 8, 8, 16, 16, 32, 32]\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\ninterface IProps {}\n\nclass App extends React.Component<IProps, IState> {\n private connMgr: ConnectionManager\n private flowMgr: FlowManager\n private ws: WebSocket | null\n private wsUnmountClose: boolean\n private tableBottomRef: React.RefObject<HTMLDivElement>\n\n private wsReconnCount = -1\n\n constructor(props: IProps) {\n super(props)\n\n this.connMgr = new ConnectionManager()\n this.flowMgr = new FlowManager()\n\n this.state = {\n flows: this.flowMgr.showList(),\n flow: null,\n wsStatus: 'close',\n }\n\n this.ws = null\n this.wsUnmountClose = false\n this.tableBottomRef = React.createRef<HTMLDivElement>()\n }\n\n componentDidMount() {\n this.initWs()\n }\n\n componentWillUnmount() {\n if (this.ws) {\n this.wsUnmountClose = true\n this.ws.close()\n this.ws = null\n }\n }\n\n initWs() {\n if (this.ws) return\n\n this.setState({ wsStatus: 'connecting' })\n\n let host\n if (process.env.NODE_ENV === 'development') {\n host = 'localhost:9081'\n } else {\n host = new URL(document.URL).host\n }\n this.ws = new WebSocket(`ws://${host}/echo`)\n this.ws.binaryType = 'arraybuffer'\n\n this.ws.onopen = () => {\n this.wsReconnCount = -1\n this.setState({ wsStatus: 'open' })\n }\n\n this.ws.onerror = evt => {\n console.error('ERROR:', evt)\n this.ws?.close()\n }\n\n this.ws.onclose = () => {\n this.setState({ wsStatus: 'close' })\n if (this.wsUnmountClose) return\n\n this.wsReconnCount++\n this.ws = null\n const waitSeconds = wsReconnIntervals[this.wsReconnCount] || wsReconnIntervals[wsReconnIntervals.length - 1]\n console.info(`will reconnect after ${waitSeconds} seconds`)\n setTimeout(() => {\n this.initWs()\n }, waitSeconds * 1000)\n }\n\n this.ws.onmessage = evt => {\n const msg = parseMessage(evt.data)\n if (!msg) {\n console.error('parse error:', evt.data)\n return\n }\n // console.log('msg:', msg)\n\n if (msg.type === MessageType.CONN) {\n this.connMgr.add(msg.id, msg.content as IConnection)\n this.setState({ flows: this.state.flows })\n }\n else if (msg.type === MessageType.CONN_CLOSE) {\n this.connMgr.delete(msg.id)\n }\n else if (msg.type === MessageType.REQUEST) {\n const flow = new Flow(msg, this.connMgr)\n flow.getConn()\n this.flowMgr.add(flow)\n\n let shouldScroll = false\n if (this.tableBottomRef?.current && isInViewPort(this.tableBottomRef.current)) {\n shouldScroll = true\n }\n this.setState({ flows: this.flowMgr.showList() }, () => {\n if (shouldScroll) {\n this.tableBottomRef?.current?.scrollIntoView({ behavior: 'auto' })\n }\n })\n }\n else if (msg.type === MessageType.REQUEST_BODY) {\n const flow = this.flowMgr.get(msg.id)\n if (!flow) return\n flow.addRequestBody(msg)\n this.setState({ flows: this.state.flows })\n }\n else if (msg.type === MessageType.RESPONSE) {\n const flow = this.flowMgr.get(msg.id)\n if (!flow) return\n flow.getConn()\n flow.addResponse(msg)\n this.setState({ flows: this.state.flows })\n }\n else if (msg.type === MessageType.RESPONSE_BODY) {\n const flow = this.flowMgr.get(msg.id)\n if (!flow || !flow.response) return\n flow.addResponseBody(msg)\n this.setState({ flows: this.state.flows })\n }\n }\n }\n\n render() {\n const { flows } = this.state\n return (\n <div className=\"main-table-wrap\">\n <div className=\"top-control\">\n <div><Button size=\"sm\" onClick={() => {\n this.flowMgr.clear()\n this.setState({ flows: this.flowMgr.showList(), flow: null })\n }}>Clear</Button></div>\n <div>\n <Form.Control\n size=\"sm\" placeholder=\"Filter\"\n onChange={(e) => {\n const value = e.target.value\n this.flowMgr.changeFilterLazy(value, () => {\n this.setState({ flows: this.flowMgr.showList() })\n })\n }}\n >\n </Form.Control>\n </div>\n\n <BreakPoint onSave={rules => {\n const msg = buildMessageMeta(SendMessageType.CHANGE_BREAK_POINT_RULES, rules)\n if (this.ws) this.ws.send(msg)\n }} />\n\n <span>status: {this.state.wsStatus}</span>\n </div>\n\n <div className=\"table-wrap-div\">\n <Table striped bordered size=\"sm\" style={{ tableLayout: 'fixed' }}>\n <thead>\n <tr>\n <th style={{ width: '50px' }}>No</th>\n <th style={{ width: '80px' }}>Method</th>\n <th style={{ width: '200px' }}>Host</th>\n <th style={{ width: 'auto' }}>Path</th>\n <th style={{ width: '150px' }}>Type</th>\n <th style={{ width: '80px' }}>Status</th>\n <th style={{ width: '90px' }}>Size</th>\n <th style={{ width: '90px' }}>Time</th>\n </tr>\n </thead>\n <tbody>\n {\n flows.map(f => {\n const fp = f.preview()\n\n return (\n <FlowPreview\n key={fp.id}\n flow={fp}\n isSelected={(this.state.flow && this.state.flow.id === fp.id) ? true : false}\n onShowDetail={() => {\n this.setState({ flow: f })\n }}\n />\n )\n })\n }\n </tbody>\n </Table>\n <div ref={this.tableBottomRef} id=\"hidden-bottom\" style={{ height: '0px', visibility: 'hidden', marginBottom: '1px' }}></div>\n </div>\n\n <ViewFlow\n flow={this.state.flow}\n onClose={() => { this.setState({ flow: null }) }}\n onReRenderFlows={() => { this.setState({ flows: this.state.flows }) }}\n onMessage={msg => { if (this.ws) this.ws.send(msg) }}\n />\n </div>\n )\n }\n}\n\nexport default App\n","import { ReportHandler } from 'web-vitals'\n\nconst reportWebVitals = (onPerfEntry?: ReportHandler) => {\n if (onPerfEntry && onPerfEntry instanceof Function) {\n import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {\n getCLS(onPerfEntry)\n getFID(onPerfEntry)\n getFCP(onPerfEntry)\n getLCP(onPerfEntry)\n getTTFB(onPerfEntry)\n })\n }\n}\n\nexport default reportWebVitals\n","import React from 'react'\nimport ReactDOM from 'react-dom'\nimport 'bootstrap/dist/css/bootstrap.min.css'\nimport App from './App'\nimport reportWebVitals from './reportWebVitals'\n\nReactDOM.render(\n <React.StrictMode>\n <App />\n </React.StrictMode>,\n document.getElementById('root')\n)\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals()\n"],"sourceRoot":""} |