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
73 KiB
Plaintext
1 line
73 KiB
Plaintext
{"version":3,"sources":["message.ts","components/BreakPoint.tsx","utils.ts","components/FlowPreview.tsx","components/EditFlow.tsx","components/ViewFlow.tsx","flow.ts","App.tsx","reportWebVitals.ts","index.tsx"],"names":["MessageType","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","FlowPreview","nextProps","isSelected","objA","objB","keysA","Object","keys","keysB","key","undefined","shallowEqual","flow","fp","classNames","waitIntercept","className","onShowDetail","no","host","path","contentType","statusCode","costTime","Flow","msg","id","request","response","_size","headerContentLengthExist","startTime","Date","now","endTime","status","REQUEST","_isTextRequest","_isTextResponse","_requestBody","_hexviewRequestBody","_responseBody","_previewResponseBody","_previewRequestBody","_hexviewResponseBody","curNo","content","URL","pathname","search","REQUEST_BODY","body","RESPONSE","split","includes","RESPONSE_BODY","isTextRequest","TextDecoder","decode","isTextResponse","startsWith","type","data","responseBody","requestBody","hexviewRequestBody","SendMessageType","allMessageBytes","buildMessageEdit","messageType","DROP_REQUEST","DROP_RESPONSE","view","set","TextEncoder","encode","CHANGE_REQUEST","CHANGE_RESPONSE","Error","ArrayBuffer","bodyLen","headerBytes","JSON","stringify","view2","DataView","setUint32","EditFlow","alertMsg","firstLine","headerLines","map","valstr","bodyLines","stringifyRequest","stringifyResponse","when","firstIndex","indexOf","slice","secondIndex","vals","proto","parseRequest","showAlert","onChangeRequest","parseResponse","onChangeResponse","msgType","onMessage","rows","Alert","ViewFlow","flowTab","copied","requestBodyViewTab","responseBodyLineBreak","style","color","pv","previewResponseBody","src","keyStyle","stringStyle","valueStyle","booleanStyle","previewRequestBody","hexviewResponseBody","searchItems","searchParams","forEach","onClose","onReRenderFlows","padding","disabled","curl","fetchToCurl","headers","reduce","obj","copy","setTimeout","marginBottom","requestBodyPreview","FormCheck","inline","checked","label","whiteSpace","preview","hexview","FlowManager","items","_map","filterText","filterTimer","num","max","Map","text","trim","endsWith","reg","RegExp","filter","item","err","oldest","shift","delete","get","callback","clearTimeout","wsReconnIntervals","App","flowMgr","ws","wsUnmountClose","autoScore","wsReconnCount","flows","showList","wsStatus","initScrollMonitor","initWs","close","document","WebSocket","binaryType","onopen","onerror","evt","console","error","onclose","waitSeconds","info","onmessage","meta","Int8Array","resp","contentStr","parse","parseMessage","add","pageBottom","scrollIntoView","behavior","addRequestBody","addResponse","addResponseBody","watcher","scrollMonitor","create","enterViewport","exitViewport","clear","placeholder","changeFilterLazy","CHANGE_BREAK_POINT_RULES","rulesBytes","buildMessageMeta","send","Table","striped","bordered","tableLayout","width","f","reportWebVitals","onPerfEntry","Function","then","getCLS","getFID","getFCP","getLCP","getTTFB","getElementById","ReactDOM","render","StrictMode"],"mappings":"2JAEYA,E,sKC+HGC,E,kDAvGb,WAAYC,GAAgB,IAAD,8BACzB,cAAMA,IAEDC,MAAQ,CACXC,MAAM,EAENC,KAAM,CACJC,OAAQ,MACRC,IAAK,GACLC,OAAQ,GAGVC,WAAW,GAGb,EAAKC,YAAc,EAAKA,YAAYC,KAAjB,gBACnB,EAAKC,WAAa,EAAKA,WAAWD,KAAhB,gBAClB,EAAKE,WAAa,EAAKA,WAAWF,KAAhB,gBAjBO,E,+CAoB3B,WACEG,KAAKC,SAAS,CAAEX,MAAM,M,wBAGxB,WACEU,KAAKC,SAAS,CAAEX,MAAM,M,wBAGxB,WAAc,IACJC,EAASS,KAAKX,MAAdE,KACFW,EAAiB,GACnBX,EAAKE,KACPS,EAAMC,KAAK,CACTX,OAAwB,QAAhBD,EAAKC,OAAmB,GAAKD,EAAKC,OAC1CC,IAAKF,EAAKE,IACVC,OAAQH,EAAKG,SAIjBM,KAAKZ,MAAMgB,OAAOF,GAClBF,KAAKJ,cAELI,KAAKC,SAAS,CAAEN,YAAWO,EAAMG,W,oBAGnC,WAAU,IAAD,SACqBL,KAAKX,MAAzBE,EADD,EACCA,KACFe,EAFC,EACOX,UACc,UAAY,UAExC,OACE,gCACE,cAACY,EAAA,EAAD,CAAQD,QAASA,EAASE,KAAK,KAAKC,QAAST,KAAKF,WAAlD,wBAEA,eAACY,EAAA,EAAD,CAAOpB,KAAMU,KAAKX,MAAMC,KAAMqB,OAAQX,KAAKJ,YAA3C,UACE,cAACc,EAAA,EAAME,OAAP,CAAcC,aAAW,EAAzB,SACE,cAACH,EAAA,EAAMI,MAAP,+BAGF,eAACJ,EAAA,EAAMK,KAAP,WACE,eAACC,EAAA,EAAKC,MAAN,CAAYC,GAAIC,IAAhB,UACE,cAACH,EAAA,EAAKI,MAAN,CAAYC,QAAM,EAACC,GAAI,EAAvB,oBACA,cAACC,EAAA,EAAD,CAAKD,GAAI,GAAT,SACE,eAACN,EAAA,EAAKQ,QAAN,CAAcN,GAAG,SAASO,MAAOlC,EAAKC,OAAQkC,SAAU,SAAAC,GAAO,EAAK1B,SAAS,CAAEV,KAAK,2BAAMA,GAAP,IAAaC,OAAQmC,EAAEC,OAAOH,WAAjH,UACE,yCACA,yCACA,0CACA,yCACA,oDAKN,eAACT,EAAA,EAAKC,MAAN,CAAYC,GAAIC,IAAhB,UACE,cAACH,EAAA,EAAKI,MAAN,CAAYC,QAAM,EAACC,GAAI,EAAvB,iBACA,cAACC,EAAA,EAAD,CAAKD,GAAI,GAAT,SAAa,cAACN,EAAA,EAAKQ,QAAN,CAAcC,MAAOlC,EAAKE,IAAKiC,SAAU,SAAAC,GAAO,EAAK1B,SAAS,CAAEV,KAAK,2BAAMA,GAAP,IAAaE,IAAKkC,EAAEC,OAAOH,kBAG9G,eAACT,EAAA,EAAKC,MAAN,CAAYC,GAAIC,IAAhB,UACE,cAACH,EAAA,EAAKI,MAAN,CAAYC,QAAM,EAACC,GAAI,EAAvB,oBACA,cAACC,EAAA,EAAD,CAAKD,GAAI,GAAT,SACE,eAACN,EAAA,EAAKQ,QAAN,CAAcN,GAAG,SAASO,MAAOlC,EAAKG,OAAQgC,SAAU,SAAAC,GAAO,EAAK1B,SAAS,CAAEV,KAAK,2BAAMA,GAAP,IAAaG,OAAQmC,SAASF,EAAEC,OAAOH,YAA1H,UACE,wBAAQA,MAAM,IAAd,qBACA,wBAAQA,MAAM,IAAd,sBACA,wBAAQA,MAAM,IAAd,6BAMR,eAACf,EAAA,EAAMoB,OAAP,WACE,cAACvB,EAAA,EAAD,CAAQD,QAAQ,YAAYG,QAAST,KAAKJ,YAA1C,mBAGA,cAACW,EAAA,EAAD,CAAQD,QAAQ,UAAUG,QAAST,KAAKD,WAAxC,+B,GA9FagC,IAAMC,WCvBlBC,EAAa,SAACC,GACzB,QAAKA,MACAA,EAAQC,WACRD,EAAQC,OAAO,iBAEb,2DAA2DC,KAAKF,EAAQC,OAAO,gBAAgBE,KAAK,QAGhGC,EAAU,SAACC,GACtB,OAAKA,EACDC,MAAMD,IACNA,GAAO,EADY,IAGnBA,EAAM,KAAY,GAAN,OAAUA,EAAV,MACZA,EAAM,QAAmB,GAAN,QAAWA,EAAM,MAAME,QAAQ,GAA/B,OACjB,GAAN,QAAWF,EAAG,SAAkBE,QAAQ,GAAxC,OANiB,KAuBNC,EAAsB,SAACC,GAIlC,IAHA,IAAIC,EAAS,GACPC,EAAQ,IAAIC,WAAWH,GACvBJ,EAAMM,EAAME,WACTC,EAAI,EAAGA,EAAIT,EAAKS,IACvBJ,GAAUK,OAAOC,aAAaL,EAAMG,IAEtC,OAAOG,KAAKP,IAGDQ,EAAa,SAACT,GACzB,IAAIU,EAAM,GACJR,EAAQ,IAAIC,WAAWH,GACvBJ,EAAMM,EAAME,WAEdO,EAAU,GAEdD,GAAO,cACP,IAAK,IAAIL,EAAI,EAAGA,EAAIT,EAAKS,IACvBK,GAAOR,EAAMG,GAAGO,SAAS,IAAIC,SAAS,EAAG,KAAO,IAE5CX,EAAMG,IAAM,IAAMH,EAAMG,IAAM,IAChCM,GAAWL,OAAOC,aAAaL,EAAMG,IAErCM,GAAW,KAGRN,EAAI,GAAK,KAAO,GACnBK,GAAO,MAAQC,EACfA,EAAU,GACVD,GAAG,aAAUL,EAAI,GAAGO,SAAS,IAAIC,SAAS,EAAG,KAA1C,SACOR,EAAI,GAAK,IAAM,IACzBK,GAAO,MAKX,GAAIC,EAAQjD,OAAS,EAAG,CACtB,IAAK,IAAI2C,EAAIM,EAAQjD,OAAQ2C,EAAI,GAAIA,IACnCK,GAAO,OACFL,EAAI,GAAK,IAAM,IAAGK,GAAO,MAEhCA,GAAO,IAAMC,EAGf,OAAOD,GCnCMI,E,2KAjCb,SAAsBC,GACpB,OAAIA,EAAUC,aAAe3D,KAAKZ,MAAMuE,aDQhB,SAACC,EAAWC,GACtC,GAAID,IAASC,EAAM,OAAO,EAE1B,IAAMC,EAAQC,OAAOC,KAAKJ,GACpBK,EAAQF,OAAOC,KAAKH,GAC1B,GAAIC,EAAMzD,SAAW4D,EAAM5D,OAAQ,OAAO,EAE1C,IAAK,IAAI2C,EAAI,EAAGA,EAAIc,EAAMzD,OAAQ2C,IAAK,CACrC,IAAMkB,EAAMJ,EAAMd,GAClB,QAAkBmB,IAAdN,EAAKK,IAAsBN,EAAKM,KAASL,EAAKK,GAAM,OAAO,EAEjE,OAAO,ECnBiDE,CAAaV,EAAUW,KAAMrE,KAAKZ,MAAMiF,Q,oBAMhG,WAAU,IAAD,OACDC,EAAKtE,KAAKZ,MAAMiF,KAEhBE,EAAa,GAInB,OAHIvE,KAAKZ,MAAMuE,YAAYY,EAAWpE,KAAK,eACvCmE,EAAGE,eAAeD,EAAWpE,KAAK,qBAGpC,qBAAIsE,UAAWF,EAAWlE,OAASkE,EAAWlC,KAAK,UAAO8B,EACxD1D,QAAS,WACP,EAAKrB,MAAMsF,gBAFf,UAKE,6BAAKJ,EAAGK,KACR,6BAAKL,EAAG9E,SACR,6BAAK8E,EAAGM,OACR,6BAAKN,EAAGO,OACR,6BAAKP,EAAGQ,cACR,6BAAKR,EAAGS,aACR,6BAAKT,EAAG9D,OACR,6BAAK8D,EAAGU,kB,GA5BUjD,IAAMC,W,mGHRpB9C,O,qBAAAA,I,+BAAAA,I,uBAAAA,I,kCAAAA,M,KAgDL,IAAM+F,EAAb,WAgCE,WAAYC,GAAgB,yBA/BrBP,QA+BoB,OA9BpBQ,QA8BoB,OA7BpBX,mBA6BoB,OA5BpBY,aA4BoB,OA3BpBC,SAA6B,KA2BT,KAzBpB5F,SAyBoB,OAxBnBoF,UAwBmB,OAvBnBS,MAAQ,EAuBW,KAtBnB9E,KAAO,IAsBY,KArBnB+E,0BAA2B,EAqBR,KApBnBT,YAAc,GAoBK,KAlBnBU,UAAYC,KAAKC,MAkBE,KAjBnBC,QAAU,EAiBS,KAhBnBX,SAAW,YAgBQ,KAZnBY,OAAsB1G,EAAY2G,QAYf,KAVnBC,oBAUmB,OATnBC,qBASmB,OARnBC,kBAQmB,OAPnBC,oBAAqC,KAOlB,KANnBC,mBAMmB,OAJnBC,qBAA4C,KAIzB,KAHnBC,oBAA2C,KAGxB,KAFnBC,qBAAsC,KAG5CrG,KAAK2E,KAAOM,EAAKqB,MACjBtG,KAAKmF,GAAKD,EAAIC,GACdnF,KAAKwE,cAAgBU,EAAIV,cACzBxE,KAAKoF,QAAUF,EAAIqB,QAEnBvG,KAAKP,IAAM,IAAI+G,IAAIxG,KAAKoF,QAAQ3F,KAChCO,KAAK6E,KAAO7E,KAAKP,IAAIgH,SAAWzG,KAAKP,IAAIiH,OAEzC1G,KAAK8F,eAAiB,KACtB9F,KAAK+F,gBAAkB,KACvB/F,KAAKgG,aAAe,KACpBhG,KAAKkG,cAAgB,KA5CzB,kDA+CE,SAAsBhB,GAIpB,OAHAlF,KAAK4F,OAAS1G,EAAYyH,aAC1B3G,KAAKwE,cAAgBU,EAAIV,cACzBxE,KAAKoF,QAAQwB,KAAO1B,EAAIqB,QACjBvG,OAnDX,yBAsDE,SAAmBkF,GAiBjB,OAhBAlF,KAAK4F,OAAS1G,EAAY2H,SAC1B7G,KAAKwE,cAAgBU,EAAIV,cACzBxE,KAAKqF,SAAWH,EAAIqB,QAEhBvG,KAAKqF,UAAYrF,KAAKqF,SAASlD,SACW,MAAxCnC,KAAKqF,SAASlD,OAAO,kBACvBnC,KAAK8E,YAAc9E,KAAKqF,SAASlD,OAAO,gBAAgB,GAAG2E,MAAM,KAAK,GAClE9G,KAAK8E,YAAYiC,SAAS,gBAAe/G,KAAK8E,YAAc,eAEpB,MAA1C9E,KAAKqF,SAASlD,OAAO,oBACvBnC,KAAKuF,0BAA2B,EAChCvF,KAAKsF,MAAQzD,SAAS7B,KAAKqF,SAASlD,OAAO,kBAAkB,IAC7DnC,KAAKQ,KAAO8B,EAAQtC,KAAKsF,SAItBtF,OAvEX,6BA0EE,SAAuBkF,GAWrB,OAVAlF,KAAK4F,OAAS1G,EAAY8H,cAC1BhH,KAAKwE,cAAgBU,EAAIV,cACrBxE,KAAKqF,WAAUrF,KAAKqF,SAASuB,KAAO1B,EAAIqB,SAC5CvG,KAAK2F,QAAUF,KAAKC,MACpB1F,KAAKgF,SAAW/B,OAAOjD,KAAK2F,QAAU3F,KAAKwF,WAAa,OAEnDxF,KAAKuF,0BAA4BvF,KAAKqF,UAAYrF,KAAKqF,SAASuB,OACnE5G,KAAKsF,MAAQtF,KAAKqF,SAASuB,KAAK7D,WAChC/C,KAAKQ,KAAO8B,EAAQtC,KAAKsF,QAEpBtF,OArFX,qBAwFE,WACE,MAAO,CACL2E,GAAI3E,KAAK2E,GACTQ,GAAInF,KAAKmF,GACTX,cAAexE,KAAKwE,cACpBI,KAAM5E,KAAKP,IAAImF,KACfC,KAAM7E,KAAK6E,KACXrF,OAAQQ,KAAKoF,QAAQ5F,OACrBuF,WAAY/E,KAAKqF,SAAWpC,OAAOjD,KAAKqF,SAASN,YAAc,YAC/DvE,KAAMR,KAAKQ,KACXwE,SAAUhF,KAAKgF,SACfF,YAAa9E,KAAK8E,eAnGxB,2BAuGE,WACE,OAA4B,OAAxB9E,KAAK8F,iBACT9F,KAAK8F,eAAiB7D,EAAWjC,KAAKoF,UADGpF,KAAK8F,iBAxGlD,yBA6GE,WACE,OAA0B,OAAtB9F,KAAKgG,aAA8BhG,KAAKgG,aACvChG,KAAKiH,gBAINjH,KAAK4F,OAAS1G,EAAYyH,aAAqB,IACnD3G,KAAKgG,cAAe,IAAIkB,aAAcC,OAAOnH,KAAKoF,QAAQwB,MACnD5G,KAAKgG,eALVhG,KAAKgG,aAAe,GACbhG,KAAKgG,gBAjHlB,gCAwHE,WAA4C,IAAD,IACzC,OAAiC,OAA7BhG,KAAKiG,oBAAqCjG,KAAKiG,oBAC/CjG,KAAK4F,OAAS1G,EAAYyH,aAAqB,MAC/C,UAAE3G,KAAKoF,eAAP,iBAAE,EAAcwB,YAAhB,aAAE,EAAoB7D,aAE1B/C,KAAKiG,oBAAsB7C,EAAWpD,KAAKoF,QAAQwB,MAC5C5G,KAAKiG,qBAHkC,OA3HlD,4BAiIE,WACE,OAAIjG,KAAK4F,OAAS1G,EAAY2H,SAAiB,MAClB,OAAzB7G,KAAK+F,kBACT/F,KAAK+F,gBAAkB9D,EAAWjC,KAAKqF,WADGrF,KAAK+F,mBAnInD,0BAwIE,WAA+B,IAAD,EAC5B,OAA2B,OAAvB/F,KAAKkG,cAA+BlG,KAAKkG,cACzClG,KAAK4F,OAAS1G,EAAY2H,SAAiB,GAC1C7G,KAAKoH,iBAINpH,KAAK4F,OAAS1G,EAAY8H,cAAsB,IACpDhH,KAAKkG,eAAgB,IAAIgB,aAAcC,OAAlB,UAAyBnH,KAAKqF,gBAA9B,aAAyB,EAAeuB,MACtD5G,KAAKkG,gBALVlG,KAAKkG,cAAgB,GACdlG,KAAKkG,iBA7IlB,iCAoJE,WAAmD,IAAD,IAM5CpB,EALJ,OAAI9E,KAAKmG,qBAA6BnG,KAAKmG,qBAEvCnG,KAAK4F,OAAS1G,EAAY8H,cAAsB,MAChD,UAAEhH,KAAKqF,gBAAP,iBAAE,EAAeuB,YAAjB,aAAE,EAAqB7D,aAGvB/C,KAAKqF,SAASlD,OAAO,kBAAiB2C,EAAc9E,KAAKqF,SAASlD,OAAO,gBAAgB,IACxF2C,GAEDA,EAAYuC,WAAW,UACzBrH,KAAKmG,qBAAuB,CAC1BmB,KAAM,QACNC,KAAM7E,EAAoB1C,KAAKqF,SAASuB,OAGnC9B,EAAYiC,SAAS,sBAC5B/G,KAAKmG,qBAAuB,CAC1BmB,KAAM,OACNC,KAAMvH,KAAKwH,iBAIRxH,KAAKmG,sBAfa,MAJsB,OAxJnD,gCA8KE,WAAkD,IAAD,EAC/C,OAAInG,KAAKoG,oBAA4BpG,KAAKoG,oBAEtCpG,KAAK4F,OAAS1G,EAAYyH,aAAqB,MAC/C,UAAE3G,KAAKoF,QAAQwB,YAAf,aAAE,EAAmB7D,aAEpB/C,KAAKiH,gBAKC,OAAO7E,KAAKpC,KAAKoF,QAAQjD,OAAO,gBAAgBE,KAAK,OAC9DrC,KAAKoG,oBAAsB,CACzBkB,KAAM,OACNC,KAAMvH,KAAKyH,gBAPbzH,KAAKoG,oBAAsB,CACzBkB,KAAM,SACNC,KAAMvH,KAAK0H,sBASR1H,KAAKoG,qBAdiC,OAlLjD,iCAmME,WAA6C,IAAD,IAC1C,OAAkC,OAA9BpG,KAAKqG,qBAAsCrG,KAAKqG,qBAEhDrG,KAAK4F,OAAS1G,EAAY8H,cAAsB,MAChD,UAAEhH,KAAKqF,gBAAP,iBAAE,EAAeuB,YAAjB,aAAE,EAAqB7D,aAE3B/C,KAAKqG,qBAAuBjD,EAAWpD,KAAKqF,SAASuB,MAC9C5G,KAAKqG,sBAHmC,SAvMnD,KAAapB,EAkBGqB,MAAQ,EA4LxB,IA6CYqB,EA7CNC,EAAkB,CACtB1I,EAAY2G,QACZ3G,EAAYyH,aACZzH,EAAY2H,SACZ3H,EAAY8H,gB,SAyCFW,O,oCAAAA,I,sCAAAA,I,gCAAAA,I,kCAAAA,I,yDAAAA,M,KAWL,IAAME,EAAmB,SAACC,EAA8BzD,GAC7D,GAAIyD,IAAgBH,EAAgBI,cAAgBD,IAAgBH,EAAgBK,cAAe,CACjG,IAAMC,EAAO,IAAInF,WAAW,IAI5B,OAHAmF,EAAK,GAAK,EACVA,EAAK,GAAKH,EACVG,EAAKC,KAAI,IAAIC,aAAcC,OAAO/D,EAAKc,IAAK,GACrC8C,EAGT,IAAI9F,EACAyE,EAEJ,GAAIkB,IAAgBH,EAAgBU,eAAgB,CAAC,IAAD,EAC3BhE,EAAKe,QAAzBwB,EAD+C,EAC/CA,KAASzE,EADsC,4BAE7C,IAAI2F,IAAgBH,EAAgBW,gBAGzC,MAAM,IAAIC,MAAM,wBAH2C,IAAD,EACnClE,EAAKgB,SAAzBuB,EADuD,EACvDA,KAASzE,EAD8C,wBAMxDyE,aAAgB4B,cAAa5B,EAAO,IAAI9D,WAAW8D,IACvD,IAAM6B,EAAW7B,GAAQA,EAAK7D,WAAc6D,EAAK7D,WAAa,EAE1D,qBAAsBZ,EAAOA,eAAeA,EAAOA,OAAO,oBAC1D,sBAAuBA,EAAOA,eAAeA,EAAOA,OAAO,qBAC/DA,EAAOA,OAAO,kBAAoB,CAACc,OAAOwF,IAE1C,IAAMC,GAAc,IAAIP,aAAcC,OAAOO,KAAKC,UAAUzG,IACtDI,EAAM,GAAamG,EAAY3F,WAAa,EAAI0F,EAChDlB,EAAO,IAAIiB,YAAYjG,GACvB0F,EAAO,IAAInF,WAAWyE,GAC5BU,EAAK,GAAK,EACVA,EAAK,GAAKH,EACVG,EAAKC,KAAI,IAAIC,aAAcC,OAAO/D,EAAKc,IAAK,GAC5C8C,EAAKC,IAAIQ,EAAa,IAClBD,GAASR,EAAKC,IAAItB,EAAoB,GAAa8B,EAAY3F,WAAa,GAEhF,IAAM8F,EAAQ,IAAIC,SAASvB,GAI3B,OAHAsB,EAAME,UAAU,GAAQL,EAAY3F,YACpC8F,EAAME,UAAU,GAAaL,EAAY3F,WAAY0F,GAE9CR,GI5HMe,E,kDAtHb,WAAY5J,GAAgB,IAAD,8BACzB,cAAMA,IAEDC,MAAQ,CACXC,MAAM,EACN2J,SAAU,GACV1C,QAAS,IAGX,EAAK3G,YAAc,EAAKA,YAAYC,KAAjB,gBACnB,EAAKC,WAAa,EAAKA,WAAWD,KAAhB,gBAClB,EAAKE,WAAa,EAAKA,WAAWF,KAAhB,gBAXO,E,6CAc3B,SAAUqF,GACRlF,KAAKC,SAAS,CAAEgJ,SAAU/D,M,yBAG5B,WACElF,KAAKC,SAAS,CAAEX,MAAM,M,wBAGxB,WAAc,IACJ+E,EAASrE,KAAKZ,MAAdiF,KAGJkC,EAAU,GAEZA,EADW,aAHAlC,EAAKgB,SAAW,WAAa,WA7HrB,SAACD,GACxB,IAAM8D,EAAS,UAAM9D,EAAQ5F,OAAd,YAAwB4F,EAAQ3F,KACzC0J,EAAcpF,OAAOC,KAAKoB,EAAQjD,QAAQiH,KAAI,SAAAlF,GAClD,IAAMmF,EAASjE,EAAQjD,OAAO+B,GAAK7B,KAAK,QACxC,MAAM,GAAN,OAAU6B,EAAV,aAAkBmF,MACjBhH,KAAK,MAEJiH,EAAY,GAGhB,OAFIlE,EAAQwB,MAAQ3E,EAAWmD,KAAUkE,GAAY,IAAIpC,aAAcC,OAAO/B,EAAQwB,OAEhF,GAAN,OAAUsC,EAAV,eAA0BC,EAA1B,eAA4CG,GAuH9BC,CAAiBlF,EAAKe,SArFZ,SAACC,GACzB,IAAM6D,EAAS,UAAM7D,EAASN,YACxBoE,EAAcpF,OAAOC,KAAKqB,EAASlD,QAAQiH,KAAI,SAAAlF,GACnD,IAAMmF,EAAShE,EAASlD,OAAO+B,GAAK7B,KAAK,QACzC,MAAM,GAAN,OAAU6B,EAAV,aAAkBmF,MACjBhH,KAAK,MAEJiH,EAAY,GAGhB,OAFIjE,EAASuB,MAAQ3E,EAAWoD,KAAWiE,GAAY,IAAIpC,aAAcC,OAAO9B,EAASuB,OAEnF,GAAN,OAAUsC,EAAV,eAA0BC,EAA1B,eAA4CG,GA6E9BE,CAAkBnF,EAAKgB,UAGnCrF,KAAKC,SAAS,CAAEX,MAAM,EAAM2J,SAAU,GAAI1C,c,wBAG5C,WAAc,IAENkD,EADWzJ,KAAKZ,MAAdiF,KACUgB,SAAW,WAAa,UAElCkB,EAAYvG,KAAKX,MAAjBkH,QAER,GAAa,YAATkD,EAAoB,CACtB,IAAMrE,EAnIS,SAACmB,GACpB,IAAMmD,EAAanD,EAAQoD,QAAQ,QACnC,KAAID,GAAc,GAAlB,CAEA,IAJ8D,EAI5CnD,EAAQqD,MAAM,EAAGF,GACH5C,MAAM,KALwB,mBAKvDtH,EALuD,KAK/CC,EAL+C,KAM9D,GAAKD,GAAWC,EAAhB,CAEA,IAAMoK,EAActD,EAAQoD,QAAQ,OAAQD,EAAa,GACzD,KAAIG,GAAe,GAAnB,CACA,IAV8D,EAUxDV,EAAc5C,EAAQqD,MAAMF,EAAa,EAAGG,GAC5C1H,EAAiB,GAXuC,cAY3CgH,EAAYrC,MAAM,OAZyB,IAY9D,2BAA4C,CAAC,IAAD,UACjBA,MAAM,MADW,mBACnC5C,EADmC,KAC9B4F,EAD8B,KAE1C,IAAK5F,IAAQ4F,EAAM,OACnB3H,EAAO+B,GAAO4F,EAAKhD,MAAM,SAfmC,8BAkB9D,IACIF,EADE0C,EAAY/C,EAAQqD,MAAMC,EAAc,GAI9C,OAFIP,IAAW1C,GAAO,IAAIuB,aAAcC,OAAOkB,IAExC,CACL9J,SACAC,MACAsK,MAAO,GACP5H,SACAyE,WAwGkBoD,CAAazD,GAC7B,IAAKnB,EAEH,YADApF,KAAKiK,UAAU,eAIjBjK,KAAKZ,MAAM8K,gBAAgB9E,GAC3BpF,KAAKJ,kBACA,CACL,IAAMyF,EAhGU,SAACkB,GACrB,IAAMmD,EAAanD,EAAQoD,QAAQ,QACnC,KAAID,GAAc,GAAlB,CAEA,IAAMR,EAAY3C,EAAQqD,MAAM,EAAGF,GAC7B3E,EAAalD,SAASqH,GAC5B,IAAI1G,MAAMuC,GAAV,CAEA,IAAM8E,EAActD,EAAQoD,QAAQ,OAAQD,EAAa,GACzD,KAAIG,GAAe,GAAnB,CACA,IAVgE,EAU1DV,EAAc5C,EAAQqD,MAAMF,EAAa,EAAGG,GAC5C1H,EAAiB,GAXyC,cAY7CgH,EAAYrC,MAAM,OAZ2B,IAYhE,2BAA4C,CAAC,IAAD,UACjBA,MAAM,MADW,mBACnC5C,EADmC,KAC9B4F,EAD8B,KAE1C,IAAK5F,IAAQ4F,EAAM,OACnB3H,EAAO+B,GAAO4F,EAAKhD,MAAM,SAfqC,8BAkBhE,IACIF,EADE0C,EAAY/C,EAAQqD,MAAMC,EAAc,GAI9C,OAFIP,IAAW1C,GAAO,IAAIuB,aAAcC,OAAOkB,IAExC,CACLvE,aACA5C,SACAyE,WAuEmBuD,CAAc5D,GAC/B,IAAKlB,EAEH,YADArF,KAAKiK,UAAU,eAIjBjK,KAAKZ,MAAMgL,iBAAiB/E,GAC5BrF,KAAKJ,iB,oBAIT,WAAU,IAAD,OACCyE,EAASrE,KAAKZ,MAAdiF,KACR,IAAKA,EAAKG,cAAe,OAAO,KAFzB,IAICyE,EAAajJ,KAAKX,MAAlB4J,SAEFQ,EAAOpF,EAAKgB,SAAW,WAAa,UAE1C,OACE,sBAAKZ,UAAU,iBAAf,UAEE,cAAClE,EAAA,EAAD,CAAQC,KAAK,KAAKC,QAAST,KAAKF,WAAhC,kBAEA,cAACS,EAAA,EAAD,CAAQC,KAAK,KAAKC,QAAS,WACzB,IAAM4J,EAAmB,aAATZ,EAAsB9B,EAAgBW,gBAAkBX,EAAgBU,eAClFnD,EAAM2C,EAAiBwC,EAAShG,GACtC,EAAKjF,MAAMkL,UAAUpF,IAHvB,sBAMA,cAAC3E,EAAA,EAAD,CAAQC,KAAK,KAAKC,QAAS,WACzB,IAAM4J,EAAmB,aAATZ,EAAsB9B,EAAgBK,cAAgBL,EAAgBI,aAChF7C,EAAM2C,EAAiBwC,EAAShG,GACtC,EAAKjF,MAAMkL,UAAUpF,IAHvB,kBAOA,eAACxE,EAAA,EAAD,CAAOF,KAAK,KAAKlB,KAAMU,KAAKX,MAAMC,KAAMqB,OAAQX,KAAKJ,YAArD,UACE,cAACc,EAAA,EAAME,OAAP,CAAcC,aAAW,EAAzB,SACE,eAACH,EAAA,EAAMI,MAAP,mBAA4B,YAAT2I,EAAqB,UAAY,gBAGtD,eAAC/I,EAAA,EAAMK,KAAP,WACE,cAACC,EAAA,EAAKC,MAAN,UACE,cAACD,EAAA,EAAKQ,QAAN,CAAcN,GAAG,WAAWqJ,KAAM,GAAI9I,MAAOzB,KAAKX,MAAMkH,QAAS7E,SAAU,SAAAC,GAAO,EAAK1B,SAAS,CAAEsG,QAAS5E,EAAEC,OAAOH,aAGnHwH,EAAkB,cAACuB,EAAA,EAAD,CAAOlK,QAAQ,SAAf,SAAyB2I,IAAhC,QAIhB,eAACvI,EAAA,EAAMoB,OAAP,WACE,cAACvB,EAAA,EAAD,CAAQD,QAAQ,YAAYG,QAAST,KAAKJ,YAA1C,mBAGA,cAACW,EAAA,EAAD,CAAQD,QAAQ,UAAUG,QAAST,KAAKD,WAAxC,+B,GA5GWgC,IAAMC,WCoLdyI,E,kDAxQb,WAAYrL,GAAgB,IAAD,8BACzB,cAAMA,IAEDC,MAAQ,CACXqL,QAAS,UACTC,QAAQ,EACRC,mBAAoB,MACpBC,uBAAuB,GAPA,E,2CAW3B,WAAW,IACDxG,EAASrE,KAAKZ,MAAdiF,KACR,IAAKA,EAAM,OAAO,KAClB,IAAMgB,EAAWhB,EAAKgB,SACtB,IAAKA,EAAU,OAAO,KAEtB,IAAMA,EAASuB,OAAQvB,EAASuB,KAAK7D,WACnC,OAAO,qBAAK+H,MAAO,CAAEC,MAAO,QAArB,yBAGT,IAAMC,EAAK3G,EAAK4G,sBAChB,OAAKD,EAEW,UAAZA,EAAG1D,KACE,qBAAK4D,IAAG,gCAA2BF,EAAGzD,QAE1B,SAAZyD,EAAG1D,KACH,8BAAK,cAAC,IAAD,CAAYC,KAAMyD,EAAGzD,KAAM4D,SAAU,0BAA2BC,YAAa,yBAA0BC,WAAY,wBAAyBC,aAAc,8BAGjK,qBAAKR,MAAO,CAAEC,MAAO,QAArB,iCATS,qBAAKD,MAAO,CAAEC,MAAO,QAArB,mC,gCAYlB,WAAsB,IACZ1G,EAASrE,KAAKZ,MAAdiF,KACR,IAAKA,EAAM,OAAO,KAElB,IAAM2G,EAAK3G,EAAKkH,qBAChB,OAAKP,EAEW,SAAZA,EAAG1D,KACE,8BAAK,cAAC,IAAD,CAAYC,KAAMyD,EAAGzD,KAAM4D,SAAU,0BAA2BC,YAAa,yBAA0BC,WAAY,wBAAyBC,aAAc,8BAEnJ,WAAZN,EAAG1D,KACH,8BAAK,8BAAM0D,EAAGzD,SAGhB,qBAAKuD,MAAO,CAAEC,MAAO,QAArB,iCATS,qBAAKD,MAAO,CAAEC,MAAO,QAArB,mC,qBAYlB,WAAW,IACD1G,EAASrE,KAAKZ,MAAdiF,KACR,IAAKA,EAAM,OAAO,KAClB,IAAMgB,EAAWhB,EAAKgB,SACtB,OAAKA,EAECA,EAASuB,MAAQvB,EAASuB,KAAK7D,WAI9B,8BAAMsB,EAAKmH,wBAHT,qBAAKV,MAAO,CAAEC,MAAO,QAArB,yBAHa,O,oBASxB,WAAU,IAAD,OACP,IAAK/K,KAAKZ,MAAMiF,KAAM,OAAO,KAE7B,IAAMA,EAAOrE,KAAKZ,MAAMiF,KAClBqG,EAAU1K,KAAKX,MAAMqL,QAErBtF,EAAUf,EAAKe,QACfC,EAAuBhB,EAAKgB,UAAY,GAGxCoG,EAAqD,GAO3D,OANIpH,EAAK5E,KAAO4E,EAAK5E,IAAIiH,QACvBrC,EAAK5E,IAAIiM,aAAaC,SAAQ,SAAClK,EAAOyC,GACpCuH,EAAYtL,KAAK,CAAE+D,MAAKzC,aAK1B,sBAAKgD,UAAU,cAAf,UACE,sBAAKA,UAAU,cAAf,UACE,sBAAMhE,QAAS,WAAQ,EAAKrB,MAAMwM,WAAlC,eACA,sBAAMnH,UAAuB,YAAZiG,EAAwB,gBAAavG,EAAW1D,QAAS,WAAQ,EAAKR,SAAS,CAAEyK,QAAS,aAA3G,qBACA,sBAAMjG,UAAuB,YAAZiG,EAAwB,gBAAavG,EAAW1D,QAAS,WAAQ,EAAKR,SAAS,CAAEyK,QAAS,aAA3G,qBACA,sBAAMjG,UAAuB,aAAZiG,EAAyB,gBAAavG,EAAW1D,QAAS,WAAQ,EAAKR,SAAS,CAAEyK,QAAS,cAA5G,sBACA,sBAAMjG,UAAuB,YAAZiG,EAAwB,gBAAavG,EAAW1D,QAAS,WAAQ,EAAKR,SAAS,CAAEyK,QAAS,aAA3G,qBAEA,cAAC,EAAD,CACErG,KAAMA,EACN6F,gBAAiB,SAAA9E,GACff,EAAKe,QAAQ5F,OAAS4F,EAAQ5F,OAC9B6E,EAAKe,QAAQ3F,IAAM2F,EAAQ3F,IAC3B4E,EAAKe,QAAQjD,OAASiD,EAAQjD,OAC1BF,EAAWoC,EAAKe,WAAUf,EAAKe,QAAQwB,KAAOxB,EAAQwB,MAC1D,EAAKxH,MAAMyM,mBAEbzB,iBAAkB,SAAA/E,GACXhB,EAAKgB,WAAUhB,EAAKgB,SAAW,IAEpChB,EAAKgB,SAASN,WAAaM,EAASN,WACpCV,EAAKgB,SAASlD,OAASkD,EAASlD,OAC5BF,EAAWoC,EAAKgB,YAAWhB,EAAKgB,SAASuB,KAAOvB,EAASuB,MAC7D,EAAKxH,MAAMyM,mBAEbvB,UAAW,SAAApF,GACT,EAAK9F,MAAMkL,UAAUpF,GACrBb,EAAKG,eAAgB,EACrB,EAAKpF,MAAMyM,wBAMjB,sBAAKf,MAAO,CAAEgB,QAAS,QAAvB,UAEkB,YAAZpB,EAAyB,KACzB,gCACE,4BAAG,cAACnK,EAAA,EAAD,CAAQC,KAAK,KAAKF,QAASN,KAAKX,MAAMsL,OAAS,UAAY,UAAWoB,SAAU/L,KAAKX,MAAMsL,OAAQlK,QAAS,WAC7G,IAAMuL,EAAOC,IAAY,CACvBxM,IAAK4E,EAAKe,QAAQ3F,IAClBD,OAAQ6E,EAAKe,QAAQ5F,OACrB0M,QAASnI,OAAOC,KAAKK,EAAKe,QAAQjD,QAAQgK,QAAO,SAACC,EAAUlI,GAE1D,OADAkI,EAAIlI,GAAOG,EAAKe,QAAQjD,OAAO+B,GAAK,GAC7BkI,IACN,IACHxF,KAAMvC,EAAKoD,gBAEb4E,IAAKL,GAEL,EAAK/L,SAAS,CAAE0K,QAAQ,IAAQ,WAC9B2B,YAAW,WACT,EAAKrM,SAAS,CAAE0K,QAAQ,MACvB,SAfJ,SAkBC3K,KAAKX,MAAMsL,OAAS,SAAW,mBAEnC,sBAAKlG,UAAU,eAAf,UACE,wCACA,sBAAKA,UAAU,uBAAf,UACE,8CAAiBW,EAAQ3F,OACzB,iDAAoB2F,EAAQ5F,UAC5B,wDAAoB6F,EAASN,YAAc,sBAK3CM,EAASlD,OACT,sBAAKsC,UAAU,eAAf,UACE,iDACA,qBAAKA,UAAU,uBAAf,SAEIV,OAAOC,KAAKqB,EAASlD,QAAQiH,KAAI,SAAAlF,GAC/B,OACE,8BAAcA,EAAd,KAAqBmB,EAASlD,OAAO+B,GAAK7B,KAAK,OAAvC6B,WAPC,KAevB,sBAAKO,UAAU,eAAf,UACE,gDACA,qBAAKA,UAAU,uBAAf,SAEMW,EAAQjD,OACR4B,OAAOC,KAAKoB,EAAQjD,QAAQiH,KAAI,SAAAlF,GAC9B,OACE,8BAAcA,EAAd,KAAqBkB,EAAQjD,OAAO+B,GAAK7B,KAAK,OAAtC6B,MAHM,UAWtBuH,EAAYpL,OACZ,sBAAKoE,UAAU,eAAf,UACE,wDACA,qBAAKA,UAAU,uBAAf,SAEIgH,EAAYrC,KAAI,YAAqB,IAAlBlF,EAAiB,EAAjBA,IAAKzC,EAAY,EAAZA,MACtB,OACE,8BAAcyC,EAAd,KAAqBzC,IAAbyC,WAPI,KAgBtBkB,EAAQwB,MAAQxB,EAAQwB,KAAK7D,WAC7B,sBAAK0B,UAAU,eAAf,UACE,6CACA,qBAAKA,UAAU,uBAAf,SACE,gCACE,sBAAKA,UAAU,sBAAsBqG,MAAO,CAAEyB,aAAc,QAA5D,UACE,sBAAM9H,UAA6C,QAAlCzE,KAAKX,MAAMuL,mBAA+B,gBAAazG,EAAW1D,QAAS,WAAQ,EAAKR,SAAS,CAAE2K,mBAAoB,SAAxI,iBACA,sBAAMnG,UAA6C,YAAlCzE,KAAKX,MAAMuL,mBAAmC,gBAAazG,EAAW1D,QAAS,WAAQ,EAAKR,SAAS,CAAE2K,mBAAoB,aAA5I,wBAIoC,QAAlC5K,KAAKX,MAAMuL,mBAAgC,KAC3C,8BAEMvG,EAAK4C,gBAA6E5C,EAAKoD,cAA/D,sBAAMqD,MAAO,CAAEC,MAAO,QAAtB,gCAMI,YAAlC/K,KAAKX,MAAMuL,mBAAoC,KAC/C,8BAAM5K,KAAKwM,+BArBsB,QAgCrC,aAAZ9B,EAA0B,KACxBrF,EAASuB,MAAQvB,EAASuB,KAAK7D,WAC7BsB,EAAK+C,iBACL,gCACE,qBAAK0D,MAAO,CAAEyB,aAAc,QAA5B,SACE,cAACE,EAAA,EAAD,CACEC,QAAM,EACNpF,KAAK,WACLqF,QAAS3M,KAAKX,MAAMwL,sBACpBnJ,SAAU,SAAAC,GACR,EAAK1B,SAAS,CAAE4K,sBAAuBlJ,EAAEC,OAAO+K,WAElDC,MAAM,+BAEV,qBAAK9B,MAAO,CAAE+B,WAAY7M,KAAKX,MAAMwL,sBAAwB,WAAa,OAA1E,SACGxG,EAAKmD,oBAbe,qBAAKsD,MAAO,CAAEC,MAAO,QAArB,+BADkB,qBAAKD,MAAO,CAAEC,MAAO,QAArB,yBAoBnC,YAAZL,EAAyB,KACzB,8BAAM1K,KAAK8M,YAIC,YAAZpC,EAAyB,KACzB,8BAAM1K,KAAK+M,sB,GAhQFhL,IAAMC,WCvBhBgL,EAAb,WAQE,aAAe,yBAPPC,WAOM,OANNC,UAMM,OALNC,gBAKM,OAJNC,iBAIM,OAHNC,SAGM,OAFNC,SAEM,EACZtN,KAAKiN,MAAQ,GACbjN,KAAKkN,KAAO,IAAIK,IAChBvN,KAAKmN,WAAa,GAClBnN,KAAKoN,YAAc,KACnBpN,KAAKqN,IAAM,EAEXrN,KAAKsN,IAAM,IAff,4CAkBE,WACE,IAAIE,EAAOxN,KAAKmN,WAEhB,GADIK,IAAMA,EAAOA,EAAKC,SACjBD,EAAM,OAAOxN,KAAKiN,MAGvB,GAAIO,EAAKnG,WAAW,MAAQmG,EAAKE,SAAS,KAAM,CAE9C,KADAF,EAAOA,EAAK5D,MAAM,EAAG4D,EAAKnN,OAAS,GAAGoN,QAC3B,OAAOzN,KAAKiN,MACvB,IACE,IAAMU,EAAM,IAAIC,OAAOJ,GACvB,OAAOxN,KAAKiN,MAAMY,QAAO,SAAAC,GACvB,OAAOH,EAAIvL,KAAK0L,EAAK1I,QAAQ3F,QAE/B,MAAOsO,GACP,OAAO/N,KAAKiN,OAIhB,OAAOjN,KAAKiN,MAAMY,QAAO,SAAAC,GACvB,OAAOA,EAAK1I,QAAQ3F,IAAIsH,SAASyG,QAtCvC,iBA0CE,SAAIM,GAKF,GAJAA,EAAKnJ,KAAO3E,KAAKqN,IACjBrN,KAAKiN,MAAM9M,KAAK2N,GAChB9N,KAAKkN,KAAKhF,IAAI4F,EAAK3I,GAAI2I,GAEnB9N,KAAKiN,MAAM5M,OAASL,KAAKsN,IAAK,CAChC,IAAMU,EAAShO,KAAKiN,MAAMgB,QACtBD,GAAQhO,KAAKkN,KAAKgB,OAAOF,EAAO7I,OAjD1C,iBAqDE,SAAIA,GACF,OAAOnF,KAAKkN,KAAKiB,IAAIhJ,KAtDzB,0BAyDE,SAAaqI,GACXxN,KAAKmN,WAAaK,IA1DtB,8BA6DE,SAAiBA,EAAcY,GAAuB,IAAD,OAC/CpO,KAAKoN,cACPiB,aAAarO,KAAKoN,aAClBpN,KAAKoN,YAAc,MAGrBpN,KAAKoN,YAAcd,YAAW,WAC5B,EAAKa,WAAaK,EAClBY,MACC,OAtEP,mBAyEE,WACEpO,KAAKiN,MAAQ,GACbjN,KAAKkN,KAAO,IAAIK,QA3EpB,KCmBMe,EAAoB,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,IA4MhDC,E,kDA7Lb,WAAYnP,GAAgB,IAAD,8BACzB,cAAMA,IATAoP,aAQmB,IAPnBC,QAOmB,IANnBC,oBAMmB,IAJnBC,WAAY,EAIO,EAFnBC,eAAiB,EAKvB,EAAKJ,QAAU,IAAIxB,EAEnB,EAAK3N,MAAQ,CACXwP,MAAO,EAAKL,QAAQM,WACpBzK,KAAM,KACNqG,QAAS,UACTqE,SAAU,SAGZ,EAAKN,GAAK,KACV,EAAKC,gBAAiB,EAEtB,EAAKM,oBAfoB,E,qDAkB3B,WACEhP,KAAKiP,W,kCAGP,WACMjP,KAAKyO,KACPzO,KAAK0O,gBAAiB,EACtB1O,KAAKyO,GAAGS,QACRlP,KAAKyO,GAAK,Q,oBAId,WAAU,IAKJ7J,EALG,OACH5E,KAAKyO,KAETzO,KAAKC,SAAS,CAAE8O,SAAU,eAMxBnK,EAAO,IAAI4B,IAAI2I,SAAS3I,KAAK5B,KAE/B5E,KAAKyO,GAAK,IAAIW,UAAJ,eAAsBxK,EAAtB,UACV5E,KAAKyO,GAAGY,WAAa,cAErBrP,KAAKyO,GAAGa,OAAS,WACf,EAAKV,eAAiB,EACtB,EAAK3O,SAAS,CAAE8O,SAAU,UAG5B/O,KAAKyO,GAAGc,QAAU,SAAAC,GAAQ,IAAD,EACvBC,QAAQC,MAAM,SAAUF,GACxB,YAAKf,UAAL,SAASS,SAGXlP,KAAKyO,GAAGkB,QAAU,WAEhB,GADA,EAAK1P,SAAS,CAAE8O,SAAU,WACtB,EAAKL,eAAT,CAEA,EAAKE,gBACL,EAAKH,GAAK,KACV,IAAMmB,EAActB,EAAkB,EAAKM,gBAAkBN,EAAkBA,EAAkBjO,OAAS,GAC1GoP,QAAQI,KAAR,+BAAqCD,EAArC,aACAtD,YAAW,WACT,EAAK2C,WACU,IAAdW,KAGL5P,KAAKyO,GAAGqB,UAAY,SAAAN,GAClB,IAAMtK,EPmKgB,SAACqC,GAC3B,GAAIA,EAAKxE,WAAa,GAAI,OAAO,KACjC,IAAMgN,EAAO,IAAIC,UAAUzI,EAAKqC,MAAM,EAAG,KAEzC,GAAgB,IADAmG,EAAK,GACF,OAAO,KAC1B,IAAMzI,EAAOyI,EAAK,GAClB,IAAKnI,EAAgBb,SAASO,GAAO,OAAO,KAC5C,IAGM2I,EAAiB,CACrB3I,OACAnC,IALS,IAAI+B,aAAcC,OAAOI,EAAKqC,MAAM,EAAG,KAMhDpF,cALiC,IAAbuL,EAAK,KAO3B,GAAwB,KAApBxI,EAAKxE,WAAmB,OAAOkN,EACnC,GAAI3I,IAASpI,EAAYyH,cAAgBW,IAASpI,EAAY8H,cAE5D,OADAiJ,EAAK1J,QAAUgB,EAAKqC,MAAM,IACnBqG,EAGT,IACI1J,EADE2J,GAAa,IAAIhJ,aAAcC,OAAOI,EAAKqC,MAAM,KAEvD,IACErD,EAAUoC,KAAKwH,MAAMD,GACrB,MAAOnC,GACP,OAAO,KAIT,OADAkC,EAAK1J,QAAUA,EACR0J,EOjMSG,CAAaZ,EAAIjI,MAC7B,GAAKrC,GAML,GAAIA,EAAIoC,OAASpI,EAAY2G,QAAS,CACpC,IAAMxB,EAAO,IAAIY,EAAKC,GACtB,EAAKsJ,QAAQ6B,IAAIhM,GACjB,EAAKpE,SAAS,CAAE4O,MAAO,EAAKL,QAAQM,aAAc,WAC5C,EAAKH,WACP,EAAKvP,MAAMkR,WAAWC,eAAe,CAAEC,SAAU,iBAIlD,GAAItL,EAAIoC,OAASpI,EAAYyH,aAAc,CAC9C,IAAMtC,EAAO,EAAKmK,QAAQL,IAAIjJ,EAAIC,IAClC,IAAKd,EAAM,OACXA,EAAKoM,eAAevL,GACpB,EAAKjF,SAAS,CAAE4O,MAAO,EAAKxP,MAAMwP,aAE/B,GAAI3J,EAAIoC,OAASpI,EAAY2H,SAAU,CAC1C,IAAMxC,EAAO,EAAKmK,QAAQL,IAAIjJ,EAAIC,IAClC,IAAKd,EAAM,OACXA,EAAKqM,YAAYxL,GACjB,EAAKjF,SAAS,CAAE4O,MAAO,EAAKxP,MAAMwP,aAE/B,GAAI3J,EAAIoC,OAASpI,EAAY8H,cAAe,CAC/C,IAAM3C,EAAO,EAAKmK,QAAQL,IAAIjJ,EAAIC,IAClC,IAAKd,IAASA,EAAKgB,SAAU,OAC7BhB,EAAKsM,gBAAgBzL,GACrB,EAAKjF,SAAS,CAAE4O,MAAO,EAAKxP,MAAMwP,cA9BlCY,QAAQC,MAAM,eAAgBF,EAAIjI,U,+BAmCxC,WAAqB,IAAD,OACZqJ,EAAUC,IAAcC,OAAO9Q,KAAKZ,MAAMkR,YAChDM,EAAQG,eAAc,WACpB,EAAKpC,WAAY,KAEnBiC,EAAQI,cAAa,WACnB,EAAKrC,WAAY,O,oBAIrB,WAAU,IAAD,OACCE,EAAU7O,KAAKX,MAAfwP,MACR,OACE,sBAAKpK,UAAU,kBAAf,UACE,sBAAKA,UAAU,cAAf,UACE,8BAAK,cAAClE,EAAA,EAAD,CAAQC,KAAK,KAAKC,QAAS,WAC9B,EAAK+N,QAAQyC,QACb,EAAKhR,SAAS,CAAE4O,MAAO,EAAKL,QAAQM,WAAYzK,KAAM,QAFnD,qBAIL,8BACE,cAACrD,EAAA,EAAKQ,QAAN,CACEhB,KAAK,KAAK0Q,YAAY,SACtBxP,SAAU,SAACC,GACT,IAAMF,EAAQE,EAAEC,OAAOH,MACvB,EAAK+M,QAAQ2C,iBAAiB1P,GAAO,WACnC,EAAKxB,SAAS,CAAE4O,MAAO,EAAKL,QAAQM,qBAO5C,cAAC,EAAD,CAAY1O,OAAQ,SAAAF,GAClB,IAAMgF,EP0Lc,SAAC4C,EAA8B5H,GAC7D,GAAI4H,IAAgBH,EAAgByJ,yBAClC,MAAM,IAAI7I,MAAM,wBAGlB,IAAM8I,GAAa,IAAIlJ,aAAcC,OAAOO,KAAKC,UAAU1I,IACrD+H,EAAO,IAAInF,WAAW,EAAIuO,EAAWtO,YAK3C,OAJAkF,EAAK,GAAK,EACVA,EAAK,GAAKH,EACVG,EAAKC,IAAImJ,EAAY,GAEdpJ,EOrMeqJ,CAAiB3J,EAAgByJ,yBAA0BlR,GACnE,EAAKuO,IAAI,EAAKA,GAAG8C,KAAKrM,MAG5B,4CAAelF,KAAKX,MAAM0P,eAG5B,eAACyC,EAAA,EAAD,CAAOC,SAAO,EAACC,UAAQ,EAAClR,KAAK,KAAKsK,MAAO,CAAE6G,YAAa,SAAxD,UACE,gCACE,+BACE,oBAAI7G,MAAO,CAAE8G,MAAO,QAApB,gBACA,oBAAI9G,MAAO,CAAE8G,MAAO,QAApB,oBACA,oBAAI9G,MAAO,CAAE8G,MAAO,SAApB,kBACA,oBAAI9G,MAAO,CAAE8G,MAAO,QAApB,kBACA,oBAAI9G,MAAO,CAAE8G,MAAO,SAApB,kBACA,oBAAI9G,MAAO,CAAE8G,MAAO,QAApB,oBACA,oBAAI9G,MAAO,CAAE8G,MAAO,QAApB,kBACA,oBAAI9G,MAAO,CAAE8G,MAAO,QAApB,uBAGJ,gCAEI/C,EAAMzF,KAAI,SAAAyI,GACR,IAAMvN,EAAKuN,EAAE/E,UAEb,OACE,cAAC,EAAD,CAEEzI,KAAMC,EACNX,cAAa,EAAKtE,MAAMgF,MAAQ,EAAKhF,MAAMgF,KAAKc,KAAOb,EAAGa,IAC1DT,aAAc,WACZ,EAAKzE,SAAS,CAAEoE,KAAMwN,MAJnBvN,EAAGa,YAapB,cAAC,EAAD,CACEd,KAAMrE,KAAKX,MAAMgF,KACjBuH,QAAS,WAAQ,EAAK3L,SAAS,CAAEoE,KAAM,QACvCwH,gBAAiB,WAAQ,EAAK5L,SAAS,CAAE4O,MAAO,EAAKxP,MAAMwP,SAC3DvE,UAAW,SAAApF,GAAa,EAAKuJ,IAAI,EAAKA,GAAG8C,KAAKrM,a,GA/LtCnD,IAAMC,WCbT8P,EAZS,SAACC,GACnBA,GAAeA,aAAuBC,UACxC,6BAAqBC,MAAK,YAAkD,IAA/CC,EAA8C,EAA9CA,OAAQC,EAAsC,EAAtCA,OAAQC,EAA8B,EAA9BA,OAAQC,EAAsB,EAAtBA,OAAQC,EAAc,EAAdA,QAC3DJ,EAAOH,GACPI,EAAOJ,GACPK,EAAOL,GACPM,EAAON,GACPO,EAAQP,OCHRzB,EAAanB,SAASoD,eAAe,iBAE3CC,IAASC,OACP,cAAC,IAAMC,WAAP,UACE,cAAC,EAAD,CAAKpC,WAAYA,MAEnBnB,SAASoD,eAAe,SAM1BT,M","file":"static/js/main.479f2438.chunk.js","sourcesContent":["import { arrayBufferToBase64, bufHexView, getSize, isTextBody } from './utils'\r\n\r\nexport enum MessageType {\r\n REQUEST = 1,\r\n REQUEST_BODY = 2,\r\n RESPONSE = 3,\r\n RESPONSE_BODY = 4,\r\n}\r\n\r\nexport type Header = Record<string, string[]>\r\n\r\nexport interface IRequest {\r\n method: string\r\n url: string\r\n proto: string\r\n header: Header\r\n body?: ArrayBuffer\r\n}\r\n\r\nexport interface IResponse {\r\n statusCode: number\r\n header: Header\r\n body?: ArrayBuffer\r\n}\r\n\r\nexport interface IMessage {\r\n type: MessageType\r\n id: string\r\n waitIntercept: boolean\r\n content?: ArrayBuffer | IRequest | IResponse\r\n}\r\n\r\nexport interface IFlowPreview {\r\n no: number\r\n id: string\r\n waitIntercept: boolean\r\n host: string\r\n path: string\r\n method: string\r\n statusCode: string\r\n size: string\r\n costTime: string\r\n contentType: string\r\n}\r\n\r\ninterface IPreviewBody {\r\n type: 'image' | 'json' | 'binary'\r\n data: string | null\r\n}\r\n\r\nexport class Flow {\r\n public no: number\r\n public id: string\r\n public waitIntercept: boolean\r\n public request: IRequest\r\n public response: IResponse | null = null\r\n\r\n public url: URL\r\n private path: string\r\n private _size = 0\r\n private size = '0'\r\n private headerContentLengthExist = false\r\n private contentType = ''\r\n\r\n private startTime = Date.now()\r\n private endTime = 0\r\n private costTime = '(pending)'\r\n\r\n public static curNo = 0\r\n\r\n private status: MessageType = MessageType.REQUEST\r\n\r\n private _isTextRequest: boolean | null\r\n private _isTextResponse: boolean | null\r\n private _requestBody: string | null\r\n private _hexviewRequestBody: string | null = null\r\n private _responseBody: string | null\r\n\r\n private _previewResponseBody: IPreviewBody | null = null\r\n private _previewRequestBody: IPreviewBody | null = null\r\n private _hexviewResponseBody: string | null = null\r\n\r\n constructor(msg: IMessage) {\r\n this.no = ++Flow.curNo\r\n this.id = msg.id\r\n this.waitIntercept = msg.waitIntercept\r\n this.request = msg.content as IRequest\r\n\r\n this.url = new URL(this.request.url)\r\n this.path = this.url.pathname + this.url.search\r\n\r\n this._isTextRequest = null\r\n this._isTextResponse = null\r\n this._requestBody = null\r\n this._responseBody = null\r\n }\r\n\r\n public addRequestBody(msg: IMessage): Flow {\r\n this.status = MessageType.REQUEST_BODY\r\n this.waitIntercept = msg.waitIntercept\r\n this.request.body = msg.content as ArrayBuffer\r\n return this\r\n }\r\n\r\n public addResponse(msg: IMessage): Flow {\r\n this.status = MessageType.RESPONSE\r\n this.waitIntercept = msg.waitIntercept\r\n this.response = msg.content as IResponse\r\n\r\n if (this.response && this.response.header) {\r\n if (this.response.header['Content-Type'] != null) {\r\n this.contentType = this.response.header['Content-Type'][0].split(';')[0]\r\n if (this.contentType.includes('javascript')) this.contentType = 'javascript'\r\n }\r\n if (this.response.header['Content-Length'] != null) {\r\n this.headerContentLengthExist = true\r\n this._size = parseInt(this.response.header['Content-Length'][0])\r\n this.size = getSize(this._size)\r\n }\r\n }\r\n\r\n return this\r\n }\r\n\r\n public addResponseBody(msg: IMessage): Flow {\r\n this.status = MessageType.RESPONSE_BODY\r\n this.waitIntercept = msg.waitIntercept\r\n if (this.response) this.response.body = msg.content as ArrayBuffer\r\n this.endTime = Date.now()\r\n this.costTime = String(this.endTime - this.startTime) + ' ms'\r\n\r\n if (!this.headerContentLengthExist && this.response && this.response.body) {\r\n this._size = this.response.body.byteLength\r\n this.size = getSize(this._size)\r\n }\r\n return this\r\n }\r\n\r\n public preview(): IFlowPreview {\r\n return {\r\n no: this.no,\r\n id: this.id,\r\n waitIntercept: this.waitIntercept,\r\n host: this.url.host,\r\n path: this.path,\r\n method: this.request.method,\r\n statusCode: this.response ? String(this.response.statusCode) : '(pending)',\r\n size: this.size,\r\n costTime: this.costTime,\r\n contentType: this.contentType,\r\n }\r\n }\r\n\r\n public isTextRequest(): boolean {\r\n if (this._isTextRequest !== null) return this._isTextRequest\r\n this._isTextRequest = isTextBody(this.request)\r\n return this._isTextRequest\r\n }\r\n\r\n public requestBody(): string {\r\n if (this._requestBody !== null) return this._requestBody\r\n if (!this.isTextRequest()) {\r\n this._requestBody = ''\r\n return this._requestBody\r\n }\r\n if (this.status < MessageType.REQUEST_BODY) return ''\r\n this._requestBody = new TextDecoder().decode(this.request.body)\r\n return this._requestBody\r\n }\r\n\r\n public hexviewRequestBody(): string | null {\r\n if (this._hexviewRequestBody !== null) return this._hexviewRequestBody\r\n if (this.status < MessageType.REQUEST_BODY) return null\r\n if (!(this.request?.body?.byteLength)) return null\r\n\r\n this._hexviewRequestBody = bufHexView(this.request.body)\r\n return this._hexviewRequestBody\r\n }\r\n\r\n public isTextResponse(): boolean | null {\r\n if (this.status < MessageType.RESPONSE) return null\r\n if (this._isTextResponse !== null) return this._isTextResponse\r\n this._isTextResponse = isTextBody(this.response as IResponse)\r\n return this._isTextResponse\r\n }\r\n\r\n public responseBody(): string {\r\n if (this._responseBody !== null) return this._responseBody\r\n if (this.status < MessageType.RESPONSE) return ''\r\n if (!this.isTextResponse()) {\r\n this._responseBody = ''\r\n return this._responseBody\r\n }\r\n if (this.status < MessageType.RESPONSE_BODY) return ''\r\n this._responseBody = new TextDecoder().decode(this.response?.body)\r\n return this._responseBody\r\n }\r\n\r\n public previewResponseBody(): IPreviewBody | null {\r\n if (this._previewResponseBody) return this._previewResponseBody\r\n\r\n if (this.status < MessageType.RESPONSE_BODY) return null\r\n if (!(this.response?.body?.byteLength)) return null\r\n\r\n let contentType: string | undefined\r\n if (this.response.header['Content-Type']) contentType = this.response.header['Content-Type'][0]\r\n if (!contentType) return null\r\n\r\n if (contentType.startsWith('image/')) {\r\n this._previewResponseBody = {\r\n type: 'image',\r\n data: arrayBufferToBase64(this.response.body),\r\n }\r\n }\r\n else if (contentType.includes('application/json')) {\r\n this._previewResponseBody = {\r\n type: 'json',\r\n data: this.responseBody(),\r\n }\r\n }\r\n\r\n return this._previewResponseBody\r\n }\r\n\r\n public previewRequestBody(): IPreviewBody | null {\r\n if (this._previewRequestBody) return this._previewRequestBody\r\n\r\n if (this.status < MessageType.REQUEST_BODY) return null\r\n if (!(this.request.body?.byteLength)) return null\r\n\r\n if (!this.isTextRequest()) {\r\n this._previewRequestBody = {\r\n type: 'binary',\r\n data: this.hexviewRequestBody(),\r\n }\r\n } else if (/json/.test(this.request.header['Content-Type'].join(''))) {\r\n this._previewRequestBody = {\r\n type: 'json',\r\n data: this.requestBody(),\r\n }\r\n }\r\n\r\n return this._previewRequestBody\r\n }\r\n\r\n public hexviewResponseBody(): string | null {\r\n if (this._hexviewResponseBody !== null) return this._hexviewResponseBody\r\n\r\n if (this.status < MessageType.RESPONSE_BODY) return null\r\n if (!(this.response?.body?.byteLength)) return null\r\n\r\n this._hexviewResponseBody = bufHexView(this.response.body)\r\n return this._hexviewResponseBody\r\n }\r\n}\r\n\r\nconst allMessageBytes = [\r\n MessageType.REQUEST,\r\n MessageType.REQUEST_BODY,\r\n MessageType.RESPONSE,\r\n MessageType.RESPONSE_BODY,\r\n]\r\n\r\n\r\n// type: 1/2/3/4\r\n// messageFlow\r\n// version 1 byte + type 1 byte + id 36 byte + waitIntercept 1 byte + content left bytes\r\nexport const parseMessage = (data: ArrayBuffer): IMessage | null => {\r\n if (data.byteLength < 39) return null\r\n const meta = new Int8Array(data.slice(0, 39))\r\n const version = meta[0]\r\n if (version !== 1) return null\r\n const type = meta[1] as MessageType\r\n if (!allMessageBytes.includes(type)) return null\r\n const id = new TextDecoder().decode(data.slice(2, 38))\r\n const waitIntercept = meta[38] === 1\r\n\r\n const resp: IMessage = {\r\n type,\r\n id,\r\n waitIntercept,\r\n }\r\n if (data.byteLength === 39) return resp\r\n if (type === MessageType.REQUEST_BODY || type === MessageType.RESPONSE_BODY) {\r\n resp.content = data.slice(39)\r\n return resp\r\n }\r\n\r\n const contentStr = new TextDecoder().decode(data.slice(39))\r\n let content: any\r\n try {\r\n content = JSON.parse(contentStr)\r\n } catch (err) {\r\n return null\r\n }\r\n\r\n resp.content = content\r\n return resp\r\n}\r\n\r\n\r\nexport enum SendMessageType {\r\n CHANGE_REQUEST = 11,\r\n CHANGE_RESPONSE = 12,\r\n DROP_REQUEST = 13,\r\n DROP_RESPONSE = 14,\r\n CHANGE_BREAK_POINT_RULES = 21,\r\n}\r\n\r\n// type: 11/12/13/14\r\n// messageEdit\r\n// version 1 byte + type 1 byte + id 36 byte + header len 4 byte + header content bytes + body len 4 byte + [body content bytes]\r\nexport const buildMessageEdit = (messageType: SendMessageType, flow: Flow) => {\r\n if (messageType === SendMessageType.DROP_REQUEST || messageType === SendMessageType.DROP_RESPONSE) {\r\n const view = new Uint8Array(38)\r\n view[0] = 1\r\n view[1] = messageType\r\n view.set(new TextEncoder().encode(flow.id), 2)\r\n return view\r\n }\r\n\r\n let header: Omit<IRequest, 'body'> | Omit<IResponse, 'body'>\r\n let body: ArrayBuffer | Uint8Array | undefined\r\n\r\n if (messageType === SendMessageType.CHANGE_REQUEST) {\r\n ({ body, ...header } = flow.request)\r\n } else if (messageType === SendMessageType.CHANGE_RESPONSE) {\r\n ({ body, ...header } = flow.response as IResponse)\r\n } else {\r\n throw new Error('invalid message type')\r\n }\r\n\r\n if (body instanceof ArrayBuffer) body = new Uint8Array(body)\r\n const bodyLen = (body && body.byteLength) ? body.byteLength : 0\r\n\r\n if ('Content-Encoding' in header.header) delete header.header['Content-Encoding']\r\n if ('Transfer-Encoding' in header.header) delete header.header['Transfer-Encoding']\r\n header.header['Content-Length'] = [String(bodyLen)]\r\n\r\n const headerBytes = new TextEncoder().encode(JSON.stringify(header))\r\n const len = 2 + 36 + 4 + headerBytes.byteLength + 4 + bodyLen\r\n const data = new ArrayBuffer(len)\r\n const view = new Uint8Array(data)\r\n view[0] = 1\r\n view[1] = messageType\r\n view.set(new TextEncoder().encode(flow.id), 2)\r\n view.set(headerBytes, 2 + 36 + 4)\r\n if (bodyLen) view.set(body as Uint8Array, 2 + 36 + 4 + headerBytes.byteLength + 4)\r\n\r\n const view2 = new DataView(data)\r\n view2.setUint32(2 + 36, headerBytes.byteLength)\r\n view2.setUint32(2 + 36 + 4 + headerBytes.byteLength, bodyLen)\r\n\r\n return view\r\n}\r\n\r\n\r\n// type: 21\r\n// messageMeta\r\n// version 1 byte + type 1 byte + content left bytes\r\nexport const buildMessageMeta = (messageType: SendMessageType, rules: any) => {\r\n if (messageType !== SendMessageType.CHANGE_BREAK_POINT_RULES) {\r\n throw new Error('invalid message type')\r\n }\r\n\r\n const rulesBytes = new TextEncoder().encode(JSON.stringify(rules))\r\n const view = new Uint8Array(2 + rulesBytes.byteLength)\r\n view[0] = 1\r\n view[1] = messageType\r\n view.set(rulesBytes, 2)\r\n\r\n return view\r\n}\r\n","import React from 'react'\r\nimport Button from 'react-bootstrap/Button'\r\nimport Modal from 'react-bootstrap/Modal'\r\nimport Form from 'react-bootstrap/Form'\r\nimport Row from 'react-bootstrap/Row'\r\nimport Col from 'react-bootstrap/Col'\r\n\r\ntype Method = 'ALL' | 'GET' | 'POST' | 'PUT' | 'DELETE' | ''\r\ntype Action = 1 | 2 | 3\r\ninterface IRule {\r\n method: Method\r\n url: string\r\n action: Action\r\n}\r\n\r\ninterface IState {\r\n show: boolean\r\n rule: IRule\r\n haveRules: boolean\r\n}\r\n\r\ninterface IProps {\r\n onSave: (rules: IRule[]) => void\r\n}\r\n\r\nclass BreakPoint extends React.Component<IProps, IState> {\r\n constructor(props: IProps) {\r\n super(props)\r\n\r\n this.state = {\r\n show: false,\r\n\r\n rule: {\r\n method: 'ALL',\r\n url: '',\r\n action: 1,\r\n },\r\n\r\n haveRules: false,\r\n }\r\n\r\n this.handleClose = this.handleClose.bind(this)\r\n this.handleShow = this.handleShow.bind(this)\r\n this.handleSave = this.handleSave.bind(this)\r\n }\r\n\r\n handleClose() {\r\n this.setState({ show: false })\r\n }\r\n\r\n handleShow() {\r\n this.setState({ show: true })\r\n }\r\n\r\n handleSave() {\r\n const { rule } = this.state\r\n const rules: IRule[] = []\r\n if (rule.url) {\r\n rules.push({\r\n method: rule.method === 'ALL' ? '' : rule.method,\r\n url: rule.url,\r\n action: rule.action,\r\n })\r\n }\r\n\r\n this.props.onSave(rules)\r\n this.handleClose()\r\n\r\n this.setState({ haveRules: rules.length ? true : false })\r\n }\r\n\r\n render() {\r\n const { rule, haveRules } = this.state\r\n const variant = haveRules ? 'success' : 'primary'\r\n\r\n return (\r\n <div>\r\n <Button variant={variant} size=\"sm\" onClick={this.handleShow}>BreakPoint</Button>\r\n\r\n <Modal show={this.state.show} onHide={this.handleClose}>\r\n <Modal.Header closeButton>\r\n <Modal.Title>Set BreakPoint</Modal.Title>\r\n </Modal.Header>\r\n\r\n <Modal.Body>\r\n <Form.Group as={Row}>\r\n <Form.Label column sm={2}>Method</Form.Label>\r\n <Col sm={10}>\r\n <Form.Control as=\"select\" value={rule.method} onChange={e => { this.setState({ rule: { ...rule, method: e.target.value as Method } }) }}>\r\n <option>ALL</option>\r\n <option>GET</option>\r\n <option>POST</option>\r\n <option>PUT</option>\r\n <option>DELETE</option>\r\n </Form.Control>\r\n </Col>\r\n </Form.Group>\r\n\r\n <Form.Group as={Row}>\r\n <Form.Label column sm={2}>URL</Form.Label>\r\n <Col sm={10}><Form.Control value={rule.url} onChange={e => { this.setState({ rule: { ...rule, url: e.target.value } }) }} /></Col>\r\n </Form.Group>\r\n\r\n <Form.Group as={Row}>\r\n <Form.Label column sm={2}>Action</Form.Label>\r\n <Col sm={10}>\r\n <Form.Control as=\"select\" value={rule.action} onChange={e => { this.setState({ rule: { ...rule, action: parseInt(e.target.value) as Action } }) }}>\r\n <option value=\"1\">Request</option>\r\n <option value=\"2\">Response</option>\r\n <option value=\"3\">Both</option>\r\n </Form.Control>\r\n </Col>\r\n </Form.Group>\r\n </Modal.Body>\r\n\r\n <Modal.Footer>\r\n <Button variant=\"secondary\" onClick={this.handleClose}>\r\n Close\r\n </Button>\r\n <Button variant=\"primary\" onClick={this.handleSave}>\r\n Save\r\n </Button>\r\n </Modal.Footer>\r\n </Modal>\r\n </div>\r\n )\r\n }\r\n}\r\n\r\nexport default BreakPoint\r\n","import { IRequest, IResponse } from './message'\r\n\r\nexport const isTextBody = (payload: IRequest | IResponse) => {\r\n if (!payload) return false\r\n if (!payload.header) return false\r\n if (!payload.header['Content-Type']) return false\r\n\r\n return /text|javascript|json|x-www-form-urlencoded|xml|form-data/.test(payload.header['Content-Type'].join(''))\r\n}\r\n\r\nexport const getSize = (len: number) => {\r\n if (!len) return '0'\r\n if (isNaN(len)) return '0'\r\n if (len <= 0) return '0'\r\n\r\n if (len < 1024) return `${len} B`\r\n if (len < 1024 * 1024) return `${(len / 1024).toFixed(2)} KB`\r\n return `${(len / (1024 * 1024)).toFixed(2)} MB`\r\n}\r\n\r\nexport const shallowEqual = (objA: any, objB: any) => {\r\n if (objA === objB) return true\r\n\r\n const keysA = Object.keys(objA)\r\n const keysB = Object.keys(objB)\r\n if (keysA.length !== keysB.length) return false\r\n\r\n for (let i = 0; i < keysA.length; i++) {\r\n const key = keysA[i]\r\n if (objB[key] === undefined || objA[key] !== objB[key]) return false\r\n }\r\n return true\r\n}\r\n\r\nexport const arrayBufferToBase64 = (buf: ArrayBuffer) => {\r\n let binary = ''\r\n const bytes = new Uint8Array(buf)\r\n const len = bytes.byteLength\r\n for (let i = 0; i < len; i++) {\r\n binary += String.fromCharCode(bytes[i])\r\n }\r\n return btoa(binary)\r\n}\r\n\r\nexport const bufHexView = (buf: ArrayBuffer) => {\r\n let str = ''\r\n const bytes = new Uint8Array(buf)\r\n const len = bytes.byteLength\r\n\r\n let viewStr = ''\r\n\r\n str += '00000000: '\r\n for (let i = 0; i < len; i++) {\r\n str += bytes[i].toString(16).padStart(2, '0') + ' '\r\n\r\n if (bytes[i] >= 32 && bytes[i] <= 126) {\r\n viewStr += String.fromCharCode(bytes[i])\r\n } else {\r\n viewStr += '.'\r\n }\r\n\r\n if ((i + 1) % 16 === 0) {\r\n str += ' ' + viewStr\r\n viewStr = ''\r\n str += `\\n${(i + 1).toString(16).padStart(8, '0')}: `\r\n } else if ((i + 1) % 8 === 0) {\r\n str += ' '\r\n }\r\n }\r\n\r\n // 补充最后一行的空白\r\n if (viewStr.length > 0) {\r\n for (let i = viewStr.length; i < 16; i++) {\r\n str += ' ' + ' '\r\n if ((i + 1) % 8 === 0) str += ' '\r\n }\r\n str += ' ' + viewStr\r\n }\r\n\r\n return str\r\n}\r\n","import React from 'react'\r\nimport { IFlowPreview } from '../message'\r\nimport { shallowEqual } from '../utils'\r\n\r\ninterface IProps {\r\n flow: IFlowPreview\r\n isSelected: boolean\r\n onShowDetail: () => void\r\n}\r\n\r\nclass FlowPreview extends React.Component<IProps> {\r\n shouldComponentUpdate(nextProps: IProps) {\r\n if (nextProps.isSelected === this.props.isSelected && shallowEqual(nextProps.flow, this.props.flow)) {\r\n return false\r\n }\r\n return true\r\n }\r\n\r\n render() {\r\n const fp = this.props.flow\r\n\r\n const classNames = []\r\n if (this.props.isSelected) classNames.push('tr-selected')\r\n if (fp.waitIntercept) classNames.push('tr-wait-intercept')\r\n\r\n return (\r\n <tr className={classNames.length ? classNames.join(' ') : undefined}\r\n onClick={() => {\r\n this.props.onShowDetail()\r\n }}\r\n >\r\n <td>{fp.no}</td>\r\n <td>{fp.method}</td>\r\n <td>{fp.host}</td>\r\n <td>{fp.path}</td>\r\n <td>{fp.contentType}</td>\r\n <td>{fp.statusCode}</td>\r\n <td>{fp.size}</td>\r\n <td>{fp.costTime}</td>\r\n </tr>\r\n )\r\n }\r\n}\r\n\r\nexport default FlowPreview\r\n","import React from 'react'\r\nimport Button from 'react-bootstrap/Button'\r\nimport Modal from 'react-bootstrap/Modal'\r\nimport Form from 'react-bootstrap/Form'\r\nimport Alert from 'react-bootstrap/Alert'\r\n\r\nimport { SendMessageType, buildMessageEdit, IRequest, IResponse, Header, Flow } from '../message'\r\nimport { isTextBody } from '../utils'\r\n\r\n\r\nconst stringifyRequest = (request: IRequest) => {\r\n const firstLine = `${request.method} ${request.url}`\r\n const headerLines = Object.keys(request.header).map(key => {\r\n const valstr = request.header[key].join(' \\t ') // for parse convenience\r\n return `${key}: ${valstr}`\r\n }).join('\\n')\r\n\r\n let bodyLines = ''\r\n if (request.body && isTextBody(request)) bodyLines = new TextDecoder().decode(request.body)\r\n\r\n return `${firstLine}\\n\\n${headerLines}\\n\\n${bodyLines}`\r\n}\r\n\r\nconst parseRequest = (content: string): IRequest | undefined => {\r\n const firstIndex = content.indexOf('\\n\\n')\r\n if (firstIndex <= 0) return\r\n\r\n const firstLine = content.slice(0, firstIndex)\r\n const [method, url] = firstLine.split(' ')\r\n if (!method || !url) return\r\n\r\n const secondIndex = content.indexOf('\\n\\n', firstIndex + 2)\r\n if (secondIndex <= 0) return\r\n const headerLines = content.slice(firstIndex + 2, secondIndex)\r\n const header: Header = {}\r\n for (const line of headerLines.split('\\n')) {\r\n const [key, vals] = line.split(': ')\r\n if (!key || !vals) return\r\n header[key] = vals.split(' \\t ')\r\n }\r\n\r\n const bodyLines = content.slice(secondIndex + 2)\r\n let body: ArrayBuffer | undefined\r\n if (bodyLines) body = new TextEncoder().encode(bodyLines)\r\n\r\n return {\r\n method,\r\n url,\r\n proto: '',\r\n header,\r\n body,\r\n }\r\n}\r\n\r\nconst stringifyResponse = (response: IResponse) => {\r\n const firstLine = `${response.statusCode}`\r\n const headerLines = Object.keys(response.header).map(key => {\r\n const valstr = response.header[key].join(' \\t ') // for parse convenience\r\n return `${key}: ${valstr}`\r\n }).join('\\n')\r\n\r\n let bodyLines = ''\r\n if (response.body && isTextBody(response)) bodyLines = new TextDecoder().decode(response.body)\r\n\r\n return `${firstLine}\\n\\n${headerLines}\\n\\n${bodyLines}`\r\n}\r\n\r\nconst parseResponse = (content: string): IResponse | undefined => {\r\n const firstIndex = content.indexOf('\\n\\n')\r\n if (firstIndex <= 0) return\r\n\r\n const firstLine = content.slice(0, firstIndex)\r\n const statusCode = parseInt(firstLine)\r\n if (isNaN(statusCode)) return\r\n\r\n const secondIndex = content.indexOf('\\n\\n', firstIndex + 2)\r\n if (secondIndex <= 0) return\r\n const headerLines = content.slice(firstIndex + 2, secondIndex)\r\n const header: Header = {}\r\n for (const line of headerLines.split('\\n')) {\r\n const [key, vals] = line.split(': ')\r\n if (!key || !vals) return\r\n header[key] = vals.split(' \\t ')\r\n }\r\n\r\n const bodyLines = content.slice(secondIndex + 2)\r\n let body: ArrayBuffer | undefined\r\n if (bodyLines) body = new TextEncoder().encode(bodyLines)\r\n\r\n return {\r\n statusCode,\r\n header,\r\n body,\r\n }\r\n}\r\n\r\n\r\ninterface IProps {\r\n flow: Flow\r\n onChangeRequest: (request: IRequest) => void\r\n onChangeResponse: (response: IResponse) => void\r\n onMessage: (msg: ArrayBufferLike) => void\r\n}\r\n\r\ninterface IState {\r\n show: boolean\r\n alertMsg: string\r\n content: string\r\n}\r\n\r\nclass EditFlow extends React.Component<IProps, IState> {\r\n constructor(props: IProps) {\r\n super(props)\r\n\r\n this.state = {\r\n show: false,\r\n alertMsg: '',\r\n content: '',\r\n }\r\n\r\n this.handleClose = this.handleClose.bind(this)\r\n this.handleShow = this.handleShow.bind(this)\r\n this.handleSave = this.handleSave.bind(this)\r\n }\r\n\r\n showAlert(msg: string) {\r\n this.setState({ alertMsg: msg })\r\n }\r\n\r\n handleClose() {\r\n this.setState({ show: false })\r\n }\r\n\r\n handleShow() {\r\n const { flow } = this.props\r\n const when = flow.response ? 'response' : 'request'\r\n\r\n let content = ''\r\n if (when === 'request') {\r\n content = stringifyRequest(flow.request)\r\n } else {\r\n content = stringifyResponse(flow.response as IResponse)\r\n }\r\n\r\n this.setState({ show: true, alertMsg: '', content })\r\n }\r\n\r\n handleSave() {\r\n const { flow } = this.props\r\n const when = flow.response ? 'response' : 'request'\r\n\r\n const { content } = this.state\r\n\r\n if (when === 'request') {\r\n const request = parseRequest(content)\r\n if (!request) {\r\n this.showAlert('parse error')\r\n return\r\n }\r\n\r\n this.props.onChangeRequest(request)\r\n this.handleClose()\r\n } else {\r\n const response = parseResponse(content)\r\n if (!response) {\r\n this.showAlert('parse error')\r\n return\r\n }\r\n\r\n this.props.onChangeResponse(response)\r\n this.handleClose()\r\n }\r\n }\r\n\r\n render() {\r\n const { flow } = this.props\r\n if (!flow.waitIntercept) return null\r\n\r\n const { alertMsg } = this.state\r\n\r\n const when = flow.response ? 'response' : 'request'\r\n\r\n return (\r\n <div className=\"flow-wait-area\">\r\n\r\n <Button size=\"sm\" onClick={this.handleShow}>Edit</Button>\r\n\r\n <Button size=\"sm\" onClick={() => {\r\n const msgType = when === 'response' ? SendMessageType.CHANGE_RESPONSE : SendMessageType.CHANGE_REQUEST\r\n const msg = buildMessageEdit(msgType, flow)\r\n this.props.onMessage(msg)\r\n }}>Continue</Button>\r\n\r\n <Button size=\"sm\" onClick={() => {\r\n const msgType = when === 'response' ? SendMessageType.DROP_RESPONSE : SendMessageType.DROP_REQUEST\r\n const msg = buildMessageEdit(msgType, flow)\r\n this.props.onMessage(msg)\r\n }}>Drop</Button>\r\n\r\n\r\n <Modal size=\"lg\" show={this.state.show} onHide={this.handleClose}>\r\n <Modal.Header closeButton>\r\n <Modal.Title>Edit {when === 'request' ? 'Request' : 'Response'}</Modal.Title>\r\n </Modal.Header>\r\n\r\n <Modal.Body>\r\n <Form.Group>\r\n <Form.Control as=\"textarea\" rows={10} value={this.state.content} onChange={e => { this.setState({ content: e.target.value }) }} />\r\n </Form.Group>\r\n {\r\n !alertMsg ? null : <Alert variant=\"danger\">{alertMsg}</Alert>\r\n }\r\n </Modal.Body>\r\n\r\n <Modal.Footer>\r\n <Button variant=\"secondary\" onClick={this.handleClose}>\r\n Close\r\n </Button>\r\n <Button variant=\"primary\" onClick={this.handleSave}>\r\n Save\r\n </Button>\r\n </Modal.Footer>\r\n </Modal>\r\n\r\n </div>\r\n )\r\n }\r\n}\r\n\r\nexport default EditFlow\r\n","import React from 'react'\r\nimport Button from 'react-bootstrap/Button'\r\nimport FormCheck from 'react-bootstrap/FormCheck'\r\nimport fetchToCurl from 'fetch-to-curl'\r\nimport copy from 'copy-to-clipboard'\r\nimport JSONPretty from 'react-json-pretty'\r\nimport { Flow, IResponse } from '../message'\r\nimport { isTextBody } from '../utils'\r\n\r\nimport EditFlow from './EditFlow'\r\n\r\ninterface Iprops {\r\n flow: Flow | null\r\n onClose: () => void\r\n onReRenderFlows: () => void\r\n onMessage: (msg: ArrayBufferLike) => void\r\n}\r\n\r\ninterface IState {\r\n flowTab: 'Headers' | 'Preview' | 'Response' | 'Hexview'\r\n copied: boolean\r\n requestBodyViewTab: 'Raw' | 'Preview'\r\n responseBodyLineBreak: boolean\r\n}\r\n\r\nclass ViewFlow extends React.Component<Iprops, IState> {\r\n constructor(props: Iprops) {\r\n super(props)\r\n\r\n this.state = {\r\n flowTab: 'Headers',\r\n copied: false,\r\n requestBodyViewTab: 'Raw',\r\n responseBodyLineBreak: false,\r\n }\r\n }\r\n\r\n preview() {\r\n const { flow } = this.props\r\n if (!flow) return null\r\n const response = flow.response\r\n if (!response) return null\r\n\r\n if (!(response.body && response.body.byteLength)) {\r\n return <div style={{ color: 'gray' }}>No response</div>\r\n }\r\n\r\n const pv = flow.previewResponseBody()\r\n if (!pv) return <div style={{ color: 'gray' }}>Not support preview</div>\r\n\r\n if (pv.type === 'image') {\r\n return <img src={`data:image/png;base64,${pv.data}`} />\r\n }\r\n else if (pv.type === 'json') {\r\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>\r\n }\r\n\r\n return <div style={{ color: 'gray' }}>Not support preview</div>\r\n }\r\n\r\n requestBodyPreview() {\r\n const { flow } = this.props\r\n if (!flow) return null\r\n\r\n const pv = flow.previewRequestBody()\r\n if (!pv) return <div style={{ color: 'gray' }}>Not support preview</div>\r\n\r\n if (pv.type === 'json') {\r\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>\r\n }\r\n else if (pv.type === 'binary') {\r\n return <div><pre>{pv.data}</pre></div>\r\n }\r\n\r\n return <div style={{ color: 'gray' }}>Not support preview</div>\r\n }\r\n\r\n hexview() {\r\n const { flow } = this.props\r\n if (!flow) return null\r\n const response = flow.response\r\n if (!response) return null\r\n\r\n if (!(response.body && response.body.byteLength)) {\r\n return <div style={{ color: 'gray' }}>No response</div>\r\n }\r\n\r\n return <pre>{flow.hexviewResponseBody()}</pre>\r\n }\r\n\r\n render() {\r\n if (!this.props.flow) return null\r\n\r\n const flow = this.props.flow\r\n const flowTab = this.state.flowTab\r\n\r\n const request = flow.request\r\n const response: IResponse = (flow.response || {}) as any\r\n\r\n // Query String Parameters\r\n const searchItems: Array<{ key: string; value: string }> = []\r\n if (flow.url && flow.url.search) {\r\n flow.url.searchParams.forEach((value, key) => {\r\n searchItems.push({ key, value })\r\n })\r\n }\r\n\r\n return (\r\n <div className=\"flow-detail\">\r\n <div className=\"header-tabs\">\r\n <span onClick={() => { this.props.onClose() }}>x</span>\r\n <span className={flowTab === 'Headers' ? 'selected' : undefined} onClick={() => { this.setState({ flowTab: 'Headers' }) }}>Headers</span>\r\n <span className={flowTab === 'Preview' ? 'selected' : undefined} onClick={() => { this.setState({ flowTab: 'Preview' }) }}>Preview</span>\r\n <span className={flowTab === 'Response' ? 'selected' : undefined} onClick={() => { this.setState({ flowTab: 'Response' }) }}>Response</span>\r\n <span className={flowTab === 'Hexview' ? 'selected' : undefined} onClick={() => { this.setState({ flowTab: 'Hexview' }) }}>Hexview</span>\r\n\r\n <EditFlow\r\n flow={flow}\r\n onChangeRequest={request => {\r\n flow.request.method = request.method\r\n flow.request.url = request.url\r\n flow.request.header = request.header\r\n if (isTextBody(flow.request)) flow.request.body = request.body\r\n this.props.onReRenderFlows()\r\n }}\r\n onChangeResponse={response => {\r\n if (!flow.response) flow.response = {} as IResponse\r\n\r\n flow.response.statusCode = response.statusCode\r\n flow.response.header = response.header\r\n if (isTextBody(flow.response)) flow.response.body = response.body\r\n this.props.onReRenderFlows()\r\n }}\r\n onMessage={msg => {\r\n this.props.onMessage(msg)\r\n flow.waitIntercept = false\r\n this.props.onReRenderFlows()\r\n }}\r\n />\r\n\r\n </div>\r\n\r\n <div style={{ padding: '20px' }}>\r\n {\r\n !(flowTab === 'Headers') ? null :\r\n <div>\r\n <p><Button size=\"sm\" variant={this.state.copied ? 'success' : 'primary'} disabled={this.state.copied} onClick={() => {\r\n const curl = fetchToCurl({\r\n url: flow.request.url,\r\n method: flow.request.method,\r\n headers: Object.keys(flow.request.header).reduce((obj: any, key: string) => {\r\n obj[key] = flow.request.header[key][0]\r\n return obj\r\n }, {}),\r\n body: flow.requestBody(),\r\n })\r\n copy(curl)\r\n\r\n this.setState({ copied: true }, () => {\r\n setTimeout(() => {\r\n this.setState({ copied: false })\r\n }, 1000)\r\n })\r\n\r\n }}>{this.state.copied ? 'Copied' : 'Copy as cURL'}</Button></p>\r\n\r\n <div className=\"header-block\">\r\n <p>General</p>\r\n <div className=\"header-block-content\">\r\n <p>Request URL: {request.url}</p>\r\n <p>Request Method: {request.method}</p>\r\n <p>Status Code: {`${response.statusCode || '(pending)'}`}</p>\r\n </div>\r\n </div>\r\n\r\n {\r\n !(response.header) ? null :\r\n <div className=\"header-block\">\r\n <p>Response Headers</p>\r\n <div className=\"header-block-content\">\r\n {\r\n Object.keys(response.header).map(key => {\r\n return (\r\n <p key={key}>{key}: {response.header[key].join(' ')}</p>\r\n )\r\n })\r\n }\r\n </div>\r\n </div>\r\n }\r\n\r\n <div className=\"header-block\">\r\n <p>Request Headers</p>\r\n <div className=\"header-block-content\">\r\n {\r\n !(request.header) ? null :\r\n Object.keys(request.header).map(key => {\r\n return (\r\n <p key={key}>{key}: {request.header[key].join(' ')}</p>\r\n )\r\n })\r\n }\r\n </div>\r\n </div>\r\n\r\n {\r\n !(searchItems.length) ? null :\r\n <div className=\"header-block\">\r\n <p>Query String Parameters</p>\r\n <div className=\"header-block-content\">\r\n {\r\n searchItems.map(({ key, value }) => {\r\n return (\r\n <p key={key}>{key}: {value}</p>\r\n )\r\n })\r\n }\r\n </div>\r\n </div>\r\n }\r\n\r\n {\r\n !(request.body && request.body.byteLength) ? null :\r\n <div className=\"header-block\">\r\n <p>Request Body</p>\r\n <div className=\"header-block-content\">\r\n <div>\r\n <div className=\"request-body-detail\" style={{ marginBottom: '15px' }}>\r\n <span className={this.state.requestBodyViewTab === 'Raw' ? 'selected' : undefined} onClick={() => { this.setState({ requestBodyViewTab: 'Raw' }) }}>Raw</span>\r\n <span className={this.state.requestBodyViewTab === 'Preview' ? 'selected' : undefined} onClick={() => { this.setState({ requestBodyViewTab: 'Preview' }) }}>Preview</span>\r\n </div>\r\n\r\n {\r\n !(this.state.requestBodyViewTab === 'Raw') ? null :\r\n <div>\r\n {\r\n !(flow.isTextRequest()) ? <span style={{ color: 'gray' }}>Not text Request</span> : flow.requestBody()\r\n }\r\n </div>\r\n }\r\n\r\n {\r\n !(this.state.requestBodyViewTab === 'Preview') ? null :\r\n <div>{this.requestBodyPreview()}</div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n </div>\r\n }\r\n\r\n {\r\n !(flowTab === 'Response') ? null :\r\n !(response.body && response.body.byteLength) ? <div style={{ color: 'gray' }}>No response</div> :\r\n !(flow.isTextResponse()) ? <div style={{ color: 'gray' }}>Not text response</div> :\r\n <div>\r\n <div style={{ marginBottom: '20px' }}>\r\n <FormCheck\r\n inline\r\n type=\"checkbox\"\r\n checked={this.state.responseBodyLineBreak}\r\n onChange={e => {\r\n this.setState({ responseBodyLineBreak: e.target.checked })\r\n }}\r\n label=\"自动换行\"></FormCheck>\r\n </div>\r\n <div style={{ whiteSpace: this.state.responseBodyLineBreak ? 'pre-wrap' : 'pre' }}>\r\n {flow.responseBody()}\r\n </div>\r\n </div>\r\n }\r\n\r\n {\r\n !(flowTab === 'Preview') ? null :\r\n <div>{this.preview()}</div>\r\n }\r\n\r\n {\r\n !(flowTab === 'Hexview') ? null :\r\n <div>{this.hexview()}</div>\r\n }\r\n </div>\r\n\r\n </div>\r\n )\r\n }\r\n}\r\n\r\nexport default ViewFlow\r\n","import { Flow } from './message'\r\n\r\nexport class FlowManager {\r\n private items: Flow[]\r\n private _map: Map<string, Flow>\r\n private filterText: string\r\n private filterTimer: number | null\r\n private num: number\r\n private max: number\r\n\r\n constructor() {\r\n this.items = []\r\n this._map = new Map()\r\n this.filterText = ''\r\n this.filterTimer = null\r\n this.num = 0\r\n\r\n this.max = 1000\r\n }\r\n\r\n showList() {\r\n let text = this.filterText\r\n if (text) text = text.trim()\r\n if (!text) return this.items\r\n\r\n // regexp\r\n if (text.startsWith('/') && text.endsWith('/')) {\r\n text = text.slice(1, text.length - 1).trim()\r\n if (!text) return this.items\r\n try {\r\n const reg = new RegExp(text)\r\n return this.items.filter(item => {\r\n return reg.test(item.request.url)\r\n })\r\n } catch (err) {\r\n return this.items\r\n }\r\n }\r\n\r\n return this.items.filter(item => {\r\n return item.request.url.includes(text)\r\n })\r\n }\r\n\r\n add(item: Flow) {\r\n item.no = ++this.num\r\n this.items.push(item)\r\n this._map.set(item.id, item)\r\n\r\n if (this.items.length > this.max) {\r\n const oldest = this.items.shift()\r\n if (oldest) this._map.delete(oldest.id)\r\n }\r\n }\r\n\r\n get(id: string) {\r\n return this._map.get(id)\r\n }\r\n\r\n changeFilter(text: string) {\r\n this.filterText = text\r\n }\r\n\r\n changeFilterLazy(text: string, callback: () => void) {\r\n if (this.filterTimer) {\r\n clearTimeout(this.filterTimer)\r\n this.filterTimer = null\r\n }\r\n\r\n this.filterTimer = setTimeout(() => {\r\n this.filterText = text\r\n callback()\r\n }, 300) as any\r\n }\r\n\r\n clear() {\r\n this.items = []\r\n this._map = new Map()\r\n }\r\n}\r\n","import React from 'react'\r\nimport Table from 'react-bootstrap/Table'\r\nimport Form from 'react-bootstrap/Form'\r\nimport Button from 'react-bootstrap/Button'\r\nimport scrollMonitor from 'scrollmonitor'\r\nimport './App.css'\r\n\r\nimport BreakPoint from './components/BreakPoint'\r\nimport FlowPreview from './components/FlowPreview'\r\nimport ViewFlow from './components/ViewFlow'\r\n\r\nimport { FlowManager } from './flow'\r\nimport { parseMessage, SendMessageType, buildMessageMeta, Flow, MessageType } from './message'\r\n\r\ninterface IState {\r\n flows: Flow[]\r\n flow: Flow | null\r\n flowTab: 'Headers' | 'Preview' | 'Response'\r\n wsStatus: 'open' | 'close' | 'connecting'\r\n}\r\n\r\nconst wsReconnIntervals = [1, 1, 2, 2, 4, 4, 8, 8, 16, 16, 32, 32]\r\n\r\ninterface IProps {\r\n pageBottom: HTMLElement\r\n}\r\n\r\nclass App extends React.Component<IProps, IState> {\r\n private flowMgr: FlowManager\r\n private ws: WebSocket | null\r\n private wsUnmountClose: boolean\r\n\r\n private autoScore = false\r\n\r\n private wsReconnCount = -1\r\n\r\n constructor(props: IProps) {\r\n super(props)\r\n\r\n this.flowMgr = new FlowManager()\r\n\r\n this.state = {\r\n flows: this.flowMgr.showList(),\r\n flow: null,\r\n flowTab: 'Headers', // Headers, Preview, Response\r\n wsStatus: 'close',\r\n }\r\n\r\n this.ws = null\r\n this.wsUnmountClose = false\r\n\r\n this.initScrollMonitor()\r\n }\r\n\r\n componentDidMount() {\r\n this.initWs()\r\n }\r\n\r\n componentWillUnmount() {\r\n if (this.ws) {\r\n this.wsUnmountClose = true\r\n this.ws.close()\r\n this.ws = null\r\n }\r\n }\r\n\r\n initWs() {\r\n if (this.ws) return\r\n\r\n this.setState({ wsStatus: 'connecting' })\r\n\r\n let host\r\n if (process.env.NODE_ENV === 'development') {\r\n host = 'localhost:9081'\r\n } else {\r\n host = new URL(document.URL).host\r\n }\r\n this.ws = new WebSocket(`ws://${host}/echo`)\r\n this.ws.binaryType = 'arraybuffer'\r\n\r\n this.ws.onopen = () => {\r\n this.wsReconnCount = -1\r\n this.setState({ wsStatus: 'open' })\r\n }\r\n\r\n this.ws.onerror = evt => {\r\n console.error('ERROR:', evt)\r\n this.ws?.close()\r\n }\r\n\r\n this.ws.onclose = () => {\r\n this.setState({ wsStatus: 'close' })\r\n if (this.wsUnmountClose) return\r\n\r\n this.wsReconnCount++\r\n this.ws = null\r\n const waitSeconds = wsReconnIntervals[this.wsReconnCount] || wsReconnIntervals[wsReconnIntervals.length - 1]\r\n console.info(`will reconnect after ${waitSeconds} seconds`)\r\n setTimeout(() => {\r\n this.initWs()\r\n }, waitSeconds * 1000)\r\n }\r\n\r\n this.ws.onmessage = evt => {\r\n const msg = parseMessage(evt.data)\r\n if (!msg) {\r\n console.error('parse error:', evt.data)\r\n return\r\n }\r\n // console.log('msg:', msg)\r\n\r\n if (msg.type === MessageType.REQUEST) {\r\n const flow = new Flow(msg)\r\n this.flowMgr.add(flow)\r\n this.setState({ flows: this.flowMgr.showList() }, () => {\r\n if (this.autoScore) {\r\n this.props.pageBottom.scrollIntoView({ behavior: 'auto' })\r\n }\r\n })\r\n }\r\n else if (msg.type === MessageType.REQUEST_BODY) {\r\n const flow = this.flowMgr.get(msg.id)\r\n if (!flow) return\r\n flow.addRequestBody(msg)\r\n this.setState({ flows: this.state.flows })\r\n }\r\n else if (msg.type === MessageType.RESPONSE) {\r\n const flow = this.flowMgr.get(msg.id)\r\n if (!flow) return\r\n flow.addResponse(msg)\r\n this.setState({ flows: this.state.flows })\r\n }\r\n else if (msg.type === MessageType.RESPONSE_BODY) {\r\n const flow = this.flowMgr.get(msg.id)\r\n if (!flow || !flow.response) return\r\n flow.addResponseBody(msg)\r\n this.setState({ flows: this.state.flows })\r\n }\r\n }\r\n }\r\n\r\n initScrollMonitor() {\r\n const watcher = scrollMonitor.create(this.props.pageBottom)\r\n watcher.enterViewport(() => {\r\n this.autoScore = true\r\n })\r\n watcher.exitViewport(() => {\r\n this.autoScore = false\r\n })\r\n }\r\n\r\n render() {\r\n const { flows } = this.state\r\n return (\r\n <div className=\"main-table-wrap\">\r\n <div className=\"top-control\">\r\n <div><Button size=\"sm\" onClick={() => {\r\n this.flowMgr.clear()\r\n this.setState({ flows: this.flowMgr.showList(), flow: null })\r\n }}>Clear</Button></div>\r\n <div>\r\n <Form.Control\r\n size=\"sm\" placeholder=\"Filter\"\r\n onChange={(e) => {\r\n const value = e.target.value\r\n this.flowMgr.changeFilterLazy(value, () => {\r\n this.setState({ flows: this.flowMgr.showList() })\r\n })\r\n }}\r\n >\r\n </Form.Control>\r\n </div>\r\n\r\n <BreakPoint onSave={rules => {\r\n const msg = buildMessageMeta(SendMessageType.CHANGE_BREAK_POINT_RULES, rules)\r\n if (this.ws) this.ws.send(msg)\r\n }} />\r\n\r\n <span>status: {this.state.wsStatus}</span>\r\n </div>\r\n\r\n <Table striped bordered size=\"sm\" style={{ tableLayout: 'fixed' }}>\r\n <thead>\r\n <tr>\r\n <th style={{ width: '50px' }}>No</th>\r\n <th style={{ width: '80px' }}>Method</th>\r\n <th style={{ width: '200px' }}>Host</th>\r\n <th style={{ width: 'auto' }}>Path</th>\r\n <th style={{ width: '150px' }}>Type</th>\r\n <th style={{ width: '80px' }}>Status</th>\r\n <th style={{ width: '90px' }}>Size</th>\r\n <th style={{ width: '90px' }}>Time</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n {\r\n flows.map(f => {\r\n const fp = f.preview()\r\n\r\n return (\r\n <FlowPreview\r\n key={fp.id}\r\n flow={fp}\r\n isSelected={(this.state.flow && this.state.flow.id === fp.id) ? true : false}\r\n onShowDetail={() => {\r\n this.setState({ flow: f })\r\n }}\r\n />\r\n )\r\n })\r\n }\r\n </tbody>\r\n </Table>\r\n\r\n <ViewFlow\r\n flow={this.state.flow}\r\n onClose={() => { this.setState({ flow: null }) }}\r\n onReRenderFlows={() => { this.setState({ flows: this.state.flows }) }}\r\n onMessage={msg => { if (this.ws) this.ws.send(msg) }}\r\n />\r\n </div>\r\n )\r\n }\r\n}\r\n\r\nexport default App\r\n","import { ReportHandler } from 'web-vitals'\r\n\r\nconst reportWebVitals = (onPerfEntry?: ReportHandler) => {\r\n if (onPerfEntry && onPerfEntry instanceof Function) {\r\n import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {\r\n getCLS(onPerfEntry)\r\n getFID(onPerfEntry)\r\n getFCP(onPerfEntry)\r\n getLCP(onPerfEntry)\r\n getTTFB(onPerfEntry)\r\n })\r\n }\r\n}\r\n\r\nexport default reportWebVitals\r\n","import React from 'react'\r\nimport ReactDOM from 'react-dom'\r\nimport 'bootstrap/dist/css/bootstrap.min.css'\r\nimport App from './App'\r\nimport reportWebVitals from './reportWebVitals'\r\n\r\nconst pageBottom = document.getElementById('hidden-bottom')\r\n\r\nReactDOM.render(\r\n <React.StrictMode>\r\n <App pageBottom={pageBottom as HTMLElement} />\r\n </React.StrictMode>,\r\n document.getElementById('root')\r\n)\r\n\r\n// If you want to start measuring performance in your app, pass a function\r\n// to log results (for example: reportWebVitals(console.log))\r\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\r\nreportWebVitals()\r\n"],"sourceRoot":""} |