local-traffic 0.0.99 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- "use strict";var e,t=this&&this.__awaiter||function(e,t,n,o){return new(n||(n=Promise))((function(r,s){function i(e){try{l(o.next(e))}catch(e){s(e)}}function a(e){try{l(o.throw(e))}catch(e){s(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,a)}l((o=o.apply(e,t||[])).next())}))},n=this&&this.__rest||function(e,t){var n={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&t.indexOf(o)<0&&(n[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(o=Object.getOwnPropertySymbols(e);r<o.length;r++)t.indexOf(o[r])<0&&Object.prototype.propertyIsEnumerable.call(e,o[r])&&(n[o[r]]=e[o[r]])}return n};Object.defineProperty(exports,"__esModule",{value:!0}),exports.update=exports.serve=exports.determineMapping=exports.send=exports.cleanEntropy=exports.replaceTextUsingMapping=exports.replaceBody=exports.acknowledgeWebsocket=exports.readWebsocketBuffer=exports.createWebsocketBufferFrom=exports.websocketServe=exports.recorderHandler=exports.quickStatus=exports.errorListener=exports.load=exports.start=void 0;const o=require("http2"),r=require("http"),s=require("https"),i=require("url"),a=require("fs"),l=require("zlib"),d=require("path"),c=require("crypto"),u=require("process"),p=require("os");var m,g,h,f;!function(e){e[e.ERROR=124]="ERROR",e[e.INFO=93]="INFO",e[e.WARNING=172]="WARNING"}(m||(m={})),function(e){e.INBOUND="↘️ ",e.PORT="☎️ ",e.OUTBOUND="↗️ ",e.RULES="🔗",e.MOCKS="🌐",e.STRICT_MOCKS="🕸️",e.AUTO_RECORD="📼",e.REWRITE="✒️ ",e.LOGS="📝",e.RESTART="🔄",e.WEBSOCKET="☄️ ",e.COLORED="✨",e.SHIELD="🛡️ ",e.NO="⛔",e.ERROR_1="❌",e.ERROR_2="⛈️ ",e.ERROR_3="☢️ ",e.ERROR_4="⁉️ ",e.ERROR_5="⚡",e.ERROR_6="☠️ "}(g||(g={})),function(e){e.INBOUND="INBOUND",e.OUTBOUND="OUTBOUND"}(h||(h={})),function(e){e.PROXY="proxy",e.MOCK="mock"}(f||(f={}));const v=(0,d.resolve)((0,p.homedir)(),".local-traffic.json"),y=(0,d.resolve)((0,u.cwd)(),u.argv.slice(-1)[0].endsWith(".json")?u.argv.slice(-1)[0]:v),b=()=>{var e,t;return null!==(t=null===(e=u.hrtime.bigint)||void 0===e?void 0:e.call(u.hrtime))&&void 0!==t?t:(()=>{const e=(0,u.hrtime)();return 1e3*e[0]+e[1]/1e6})()},O=e=>{const t=new Date;return`${e?"":""}${`${t.getHours()}`.padStart(2,"0")}${e?":":":"}${`${t.getMinutes()}`.padStart(2,"0")}${e?":":":"}${`${t.getSeconds()}`.padStart(2,"0")}${e?"":""}`},k=function(e,n){return t(this,void 0,void 0,(function*(){var t,o,r,s,i,a,l;const d=n.map((e=>e.map((e=>e.text.replace(/⎸/g,"|").replace(/⎹/g,"|").replace(/\u001b\[[^m]*m/g,"").replace(new RegExp(g.INBOUND,"g"),"inbound:").replace(new RegExp(g.PORT,"g"),"port:").replace(new RegExp(g.OUTBOUND,"g"),"outbound:").replace(new RegExp(g.RULES,"g"),"rules:").replace(new RegExp(g.NO,"g"),"").replace(new RegExp(g.REWRITE,"g"),"+rewrite").replace(new RegExp(g.WEBSOCKET,"g"),"websocket").replace(new RegExp(g.SHIELD,"g"),"web-security").replace(new RegExp(g.MOCKS,"g"),"mocks").replace(new RegExp(g.STRICT_MOCKS,"g"),"mocks (strict)").replace(new RegExp(g.AUTO_RECORD,"g"),"auto record").replace(new RegExp(g.LOGS,"g"),"logs").replace(new RegExp(g.RESTART,"g"),"restart").replace(new RegExp(g.COLORED,"g"),"colored").replace(/\|+/g,"|"))).join(" | ")));if(null===(t=null==e?void 0:e.config)||void 0===t?void 0:t.simpleLogs)for(let t of d)console.log(`${O(null===(o=null==e?void 0:e.config)||void 0===o?void 0:o.simpleLogs)} | ${t}`);else for(let t of n){const n=t.map((e=>`[48;5;${e.color}m${e.text}`));console.log(`${O(null===(r=null==e?void 0:e.config)||void 0===r?void 0:r.simpleLogs)}${t.map((e=>{var t;return`[48;5;${e.color}m${"".padEnd((null!==(t=e.length)&&void 0!==t?t:64)+1)}`})).join("▐")}`),yield new Promise((e=>u.stdout.moveCursor(-1e3,-1,(()=>e(void 0)))));let o=9;for(let e=0;e<n.length;e++)yield new Promise((e=>u.stdout.moveCursor(-1e3,0,(()=>u.stdout.moveCursor(o,0,(()=>e(void 0))))))),u.stdout.write(n[e]),o+=(null!==(s=t[e].length)&&void 0!==s?s:64)+2;console.log("");for(let n of d)null===(i=null==e?void 0:e.notifyLogsListeners)||void 0===i||i.call(e,{event:n,level:(c=null!==(l=null===(a=null==t?void 0:t[0])||void 0===a?void 0:a.color)&&void 0!==l?l:m.INFO,c===m.ERROR?"error":c===m.WARNING?"warning":"info")})}var c}))},w=(e,t)=>{var n;const o=Array(4).fill(0).map((()=>t?Math.floor(256*Math.random()):0)),r=e.split("").map(((e,t)=>e.charCodeAt(0)^o[3&t])),s=e.length,i=t?128:0,a=e.length<126?Buffer.from(Uint8Array.from([129,i+s]).buffer):e.length<65535?Buffer.concat([Buffer.from(Uint8Array.from([129,126|i]).buffer),Buffer.from(Uint8Array.from([s>>8]).buffer),Buffer.from(Uint8Array.from([255&s]).buffer)]):Buffer.concat([Buffer.from(Uint8Array.from([129,127|i]).buffer),Buffer.concat((null!==(n=Number(s).toString(16).padStart(16,"0").match(/.{2}/g))&&void 0!==n?n:["0"]).map((e=>parseInt(e,16))).map((e=>Buffer.from(Uint8Array.from([e]).buffer))))]),l=Buffer.from(Int8Array.from(o).buffer),d=Buffer.from(Int8Array.from(r).buffer);return Buffer.concat(t?[a,l,d]:[a,d])};exports.createWebsocketBufferFrom=w;const R=(e,t)=>{var n;if(!(t||1&e.readUInt8(0)))return{payloadLength:0,mask:[0,0,0,0],body:""};const o=t?0:e.readUInt8(1),r=o>>7,s=127&o,i=t?t.payloadLength:127!==s?s:e.readUInt8(2)<<8+e.readUInt8(3),a=t?t.mask:r?Array(4).fill(0).map(((t,n)=>e.readUInt8(n+4))):[0,0,0,0],l=t?0:r?8:4,d=Array(e.length-l).fill(0).map(((t,n)=>String.fromCharCode(e.readUInt8(n+l)^a[3&n]))).join("");return{payloadLength:i,mask:a,body:(null!==(n=null==t?void 0:t.body)&&void 0!==n?n:"").concat(d)}};exports.readWebsocketBuffer=R;const E=(e,t)=>{const n=(0,c.createHash)("sha1");n.update(t+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11");const o=n.digest("base64");e.allowHalfOpen=!0,e.write(`HTTP/1.1 101 Switching Protocols\r\ndate: ${(new Date).toUTCString()}\r\nconnection: upgrade\r\nupgrade: websocket\r\nserver: local\r\nsec-websocket-accept: ${o}\r\n\r\n`)};exports.acknowledgeWebsocket=E;const $=function(e){return S(e,this.configListeners)},x=function(e){const{response:t}=e,o=n(e,["response"]);return Promise.all([S(e,this.logsListeners.filter((e=>e.wantsResponseMessage))),S(o,this.logsListeners.filter((e=>!e.wantsResponseMessage)))])},S=(e,t)=>{if(!t.length)return;const n=JSON.stringify(e),o=new Set(t.map((e=>e.wantsMask))),r=o.has(!1)&&w(n,!1),s=o.has(!0)&&w(n,!0),i=e=>{e.stream.errored&&e.stream.destroy()};t.forEach((e=>{e.stream.closed||e.stream.errored||(e.wantsMask?e.stream.write(s,"ascii",(()=>i(e))):e.stream.write(r,"ascii",(()=>i(e))))}))},C=function(){var e,t;return[{color:52,text:`${g.PORT} ${(null!==(e=this.config.port)&&void 0!==e?e:"").toString()}`,length:11},{color:53,text:`${g.OUTBOUND} ${this.config.dontUseHttp2Downstream?"H1.1":"H/2 "}${this.config.replaceRequestBodyUrls?g.REWRITE:" "}`,length:11},{color:54,text:`${g.INBOUND} ${this.config.ssl?"H/2 ":"H1.1"}${this.config.replaceResponseBodyUrls?g.REWRITE:" "}`,length:11},{color:55,text:""+(this.mode===f.PROXY&&this.mockConfig.autoRecord?`${g.AUTO_RECORD}${this.mockConfig.mocks.size.toString().padStart(3)}`:this.mode===f.PROXY?`${g.RULES}${Object.keys(null!==(t=this.config.mapping)&&void 0!==t?t:{}).length.toString().padStart(3)}`:`${this.mockConfig.strict?g.STRICT_MOCKS:g.MOCKS}${this.mockConfig.mocks.size.toString().padStart(3)}`),length:7},{color:56,text:`${this.config.websocket?g.WEBSOCKET:g.NO}`,length:4},{color:57,text:`${this.config.simpleLogs?g.NO:g.COLORED}`,length:4},{color:93,text:`${this.config.disableWebSecurity?g.NO:g.SHIELD}`,length:4}]},I=function(){return t(this,void 0,void 0,(function*(){this.log([this.buildQuickStatus()]),this.notifyConfigListeners(this.config)}))};exports.quickStatus=I;const B=(e,t,n,o,r)=>`${W(128163,"error",e.message)}\n<p>An error happened while trying to proxy a remote exchange</p>\n<div class="alert alert-warning" role="alert">\n&#x24D8;&nbsp;This is not an error from the downstream service.\n</div>\n<div class="alert alert-danger" role="alert">\n<pre><code>${e.stack||`<i>${e.name} : ${e.message}</i>`}${e.errno?`<br/>(code : ${e.errno})`:""}</code></pre>\n</div>\nMore information about the request :\n<table class="table">\n<tbody>\n<tr>\n<td>server mode</td>\n<td>${t}</td>\n</tr>\n<tr>\n<td>phase</td>\n<td>${n}</td>\n</tr>\n<tr>\n<td>requested URL</td>\n<td>${o}</td>\n</tr>\n<tr>\n<td>downstream URL</td>\n<td>${r||"&lt;no-target-url&gt;"}</td>\n</tr>\n</tbody>\n</table>\n</div></body></html>`,q=(e,t,n)=>`<table id="table-access" class="table table-striped" style="display: block; width: 100%; overflow-y: auto">\n<thead>\n<tr>\n<th scope="col"${!0===n.captureResponseBody?' style="min-width: 120px"':""}>...</th>\n<th scope="col">Date</th>\n<th scope="col">Level</th>\n<th scope="col">Protocol</th>\n<th scope="col">Method</th>\n<th scope="col">Status</th>\n<th scope="col">Duration</th>\n<th scope="col">Upstream Path</th>\n<th scope="col">Downstream Path</th>\n</tr>\n</thead>\n<tbody id="access">\n</tbody>\n</table>\n<table id="table-proxy" class="table table-striped" style="display: none; width: 100%; overflow-y: auto">\n<thead>\n<tr>\n<th scope="col">Date</th>\n<th scope="col">Level</th>\n<th scope="col">Message</th>\n</tr>\n</thead>\n<tbody id="proxy">\n</tbody>\n</table>\n<script type="text/javascript">\nfunction start() {\ndocument.getElementById('table-access').style.height =\n(document.documentElement.clientHeight - 150) + 'px';\nconst socket = new WebSocket("ws${t.ssl?"s":""}://${e}/local-traffic-logs${n.captureResponseBody?"?wantsResponseMessage=true":""}");\nsocket.onmessage = function(event) {\nlet data = event.data\nlet uniqueHash;\ntry {\nconst { uniqueHash: uniqueHash1, ...data1 } = JSON.parse(event.data);\ndata = data1;\nuniqueHash = uniqueHash1;\n} catch(e) { }\nif (document.getElementById('mock-mode')?.checked) return;\nif (${!0===n.captureResponseBody} && \ndata?.downstreamPath?.startsWith('recorder://') &&\n!data?.upstreamPath?.endsWith('?forceLogInRecorderPage=true'))\nreturn;\nconst time = new Date().toISOString().split('T')[1].replace('Z', '');\nconst actions = getActionsHtmlText(uniqueHash, data.response);\nif(data.statusCode && uniqueHash) {\nconst color = getColorFromStatusCode(data.statusCode);\nconst statusCodeColumn = document.querySelector("#event-" + data.randomId + " .statusCode");\nif (statusCodeColumn)\nstatusCodeColumn.innerHTML = '<span class="badge bg-' + color + '">' + data.statusCode + '</span>';\n\nconst durationColumn = document.querySelector("#event-" + data.randomId + " .duration");\nif (durationColumn) {\nconst duration = data.duration > 10000 ? Math.floor(data.duration / 1000) + 's' :\ndata.duration + 'ms';\ndurationColumn.innerHTML = duration;\n}\n\nconst protocolColumn = document.querySelector("#event-" + data.randomId + " .protocol");\nif (protocolColumn) {\nprotocolColumn.innerHTML = data.protocol;\n}\n\nconst replayColumn = document.querySelector("#event-" + data.randomId + " .replay");\nif (replayColumn) {\nreplayColumn.innerHTML = actions;\n}\n} else if (uniqueHash) {\naddNewRequest(data.randomId, actions, time, data.level, data.protocol, data.method, \n'<span class="badge bg-secondary">...</span>', '&#x23F1;',\ndata.upstreamPath, data.downstreamPath);\n} else if(data.event) {\ndocument.getElementById("proxy")\n.insertAdjacentHTML('afterbegin', '<tr><td scope="col">' + time + '</td>' +\n'<td scope="col">' + (data.level || 'info')+ '</td>' + \n'<td scope="col">' + data.event + '</td></tr>');\n}\ncleanup();\n};\nsocket.onerror = function(error) {\nconsole.log(\`[error] \${JSON.stringify(error)}\`);\nsetTimeout(start, 5000);\n};\n};\nfunction show(id) {\n[...document.querySelectorAll('table')].forEach((table, index) => {\ntable.style.display = index === id ? 'block': 'none'\n});\n[...document.querySelectorAll('.navbar-nav .nav-item .nav-link')].forEach((link, index) => {\nif (index === id) { link.classList.add('active') } else link.classList.remove('active');\n});\n}\nfunction remove(event) {\nevent.target.closest('tr').remove();\nif (window.updateState) window.updateState();\n}\nfunction cleanup() {\nconst currentLimit = parseInt(document.getElementById('limit').value)\nfor (let table of ['access', 'proxy']) {\nwhile (currentLimit && document.getElementById(table).childNodes.length && \ndocument.getElementById(table).childNodes.length > currentLimit) {\n[...document.getElementById(table).childNodes].slice(-1)[0].remove();\n}\n}\n}\nfunction replay(event) {\nconst uniqueHash = event.target.dataset.uniquehash;\nconst { method, url, headers, body } = JSON.parse(atob(uniqueHash));\nfetch(url, {\nmethod,\nheaders,\nbody: !body || !body.length ? undefined : atob(body)\n});\n}\nfunction getActionsHtmlText(uniqueHash, response) {\nconst edit = ${!0===n.captureResponseBody} && uniqueHash\n? '<button data-response="' + (response ?? "") +\n'" data-uniquehash="' + uniqueHash + \n'" data-bs-toggle="modal" data-bs-target="#edit-request" type="button" ' +\n'class="btn btn-primary">&#x1F4DD;</button>'\n: ''\nconst remove = ${!0===n.captureResponseBody} && uniqueHash\n? '<button onclick="javascript:remove(event)" type="button" ' +\n'class="btn btn-primary">&#x274C;</button>'\n: ''\nconst replay = ${!1===n.captureResponseBody} && uniqueHash ? '<button data-response="' + \nbtoa(JSON.stringify(response ?? {})) +\n'" data-uniquehash="' + uniqueHash + '" onclick="javascript:replay(event)" ' +\n'type="button" class="btn btn-primary">&#x1F501;</button>' : '';\nreturn edit + replay + remove\n}\nfunction addNewRequest(\nrandomId, actions, time, level, protocol, method, \nstatusCode, duration, upstreamPath, downstreamPath\n) {\ndocument.getElementById("access")\n.insertAdjacentHTML('afterbegin', '<tr id="event-' + randomId + '">' +\n'<td scope="col" class="replay">' + actions + '</td>' +\n'<td scope="col">' + time + '</td>' +\n'<td scope="col">' + (level || 'info')+ '</td>' + \n'<td scope="col" class="protocol">' + protocol + '</td>' + \n'<td scope="col" class="method">' + method + '</td>' + \n'<td scope="col" class="statusCode">' + statusCode + '</td>' +\n'<td scope="col" class="duration text-end">' + duration + '</td>' +\n'<td scope="col" class="upstream-path">' + upstreamPath + '</td>' + \n'<td scope="col">' + downstreamPath + '</td>' + \n'</tr>');\n}\nfunction getColorFromStatusCode(statusCode) {\nreturn Math.floor(statusCode / 100) === 1 ? "info" :\nMath.floor(statusCode / 100) === 2 ? "success" :\nMath.floor(statusCode / 100) === 3 ? "dark" :\nMath.floor(statusCode / 100) === 4 ? "warning" :\nMath.floor(statusCode / 100) === 5 ? "danger" :\n"secondary";\n}\nwindow.addEventListener("DOMContentLoaded", start);\n<\/script>`,N=(e,t,n)=>{let o={};try{o=JSON.parse(t.toString("ascii"))}catch(e){}if("object"!=typeof o||Object.keys(o).filter((e=>!["strict","mode","mocks","autoRecord"].includes(e))).length||!Array.isArray(o.mocks)&&void 0!==o.mocks)return void e.log([[{text:`${g.MOCKS} invalid mocks update received`,color:m.WARNING}]]);const{mocks:r,mode:s,strict:i,autoRecord:a}=o,l=r?new Map(r.map((({response:t,uniqueHash:n})=>[z(e.config,n),t]))):null,d=s!==e.mode&&s===f.PROXY,c=(!d||!0===a)&&(null!=a?a:e.mockConfig.autoRecord),u=void 0!==c&&c!=e.mockConfig.autoRecord,p=s!==e.mode&&s===f.MOCK||null!==l&&e.mockConfig.mocks.size!==l.size,h=null!=i?i:e.mockConfig.strict,v=null!=s?s:e.mode,y=!!h!=!!e.mockConfig.strict,b=n;ee(e,b?{mode:v,mockConfig:{autoRecord:!1,strict:h,mocks:new Map}}:{mode:v,mockConfig:{strict:h,autoRecord:c,mocks:null!=l?l:e.mockConfig.mocks}}),setTimeout((()=>{var t;return e.log([d?[{text:`${g.RULES} ${Object.keys(null!==(t=e.config.mapping)&&void 0!==t?t:{}).length.toString().padStart(5)} loaded mapping rules`,color:m.INFO}]:null,p?[{text:`${h?g.STRICT_MOCKS:g.MOCKS} ${(null!=l?l:e.mockConfig.mocks).size.toString().padStart(5)} loaded mocks`,color:m.INFO}]:null,y?[{text:`${h?g.STRICT_MOCKS:g.MOCKS} mocks strict mode : ${null!=h?h:e.mockConfig.strict}`,color:m.INFO}]:null,u?[{text:`${v===f.PROXY?g.AUTO_RECORD:h?g.STRICT_MOCKS:g.MOCKS} mocks auto-record : ${c}`,color:m.INFO}]:null,d||p||u||y||b?e.buildQuickStatus():null].filter((e=>e)))}),1)};exports.recorderHandler=N;const T=(e,n,o,i,a,l,d,c,u)=>t(void 0,void 0,void 0,(function*(){const t={hostname:e.hostname,path:i,port:e.port?e.port:"https:"===e.protocol?443:80,protocol:e.protocol,rejectUnauthorized:!1,method:a.method,headers:Object.assign(Object.assign({},Object.assign({},...Object.entries(l).filter((([e])=>!e.startsWith(":")&&"transfer-encoding"!==e.toLowerCase())).map((([e,t])=>({[e]:t}))))),{host:e.hostname})};let p=null;const m=p||[...L].includes(e.protocol)?null:yield new Promise((i=>{const l="https:"===e.protocol?(0,s.request)(t,i):(0,r.request)(t,i);l.on("error",(e=>{p=Buffer.from(B(e,u,"request",n,o)),i(null)})),c&&(l.write(d),l.end()),c||(a.on("data",(e=>l.write(e))),a.on("end",(()=>l.end())))}));if(p)throw p;return{alpnProtocol:"HTTP1.1",error:null,data:null,hasRun:!1,events:{},on:function(e,t){return"response"===e?null==t?void 0:t(Object.assign(Object.assign({},m.headers),{":status":m.statusCode,":statusmessage":m.statusMessage})):m.on(e,t)},end:function(){return this},request:function(){return this},write:function(){return this}}})),j={logs:(e,t)=>J(`${W(128250,"logs","")}\n<nav class="navbar navbar-expand-lg navbar-dark bg-primary nav-fill">\n<div class="container-fluid">\n<ul class="navbar-nav">\n<li class="nav-item">\n<a class="nav-link active" aria-current="page" href="javascript:show(0)">Access</a>\n</li>\n<li class="nav-item">\n<a class="nav-link" href="javascript:show(1)">Proxy</a>\n</li>\n</ul>\n<span class="navbar-text">\nLimit : <select id="limit" onchange="javascript:cleanup()"><option value="-1">0 (clear)</option><option value="10">10</option>\n<option value="50">50</option><option value="100">100</option><option value="200">200</option>\n<option selected="selected" value="500">500</option><option value="0">Infinity (discouraged)</option>\n</select> rows\n</span>\n</div>\n</nav>\n${q(e,t.config,{captureResponseBody:!1})}\n</body></html>`),config:(e,t)=>J(`${W(127899,"config","")}\n<link href="${M}jsoneditor/dist/jsoneditor.min.css" rel="stylesheet" type="text/css">\n<script src="${M}jsoneditor/dist/jsoneditor.min.js"><\/script>\n<script src="${M}node-forge/dist/forge.min.js"><\/script>\n<div id="ssl-modal" class="modal" tabindex="-1" role="dialog">\n<div class="modal-dialog" role="document">\n<div class="modal-content">\n<div class="modal-header">\n<h5 class="modal-title">SSL keypair generation in progress</h5>\n</div>\n<div class="modal-body">\n<p>Wait a few seconds or move your mouse to increase the entropy.</p>\n</div>\n</div>\n</div>\n</div>\n<div id="jsoneditor" style="width: 400px; height: 400px;"></div>\n<script>\n// create the editor\nconst container = document.getElementById("jsoneditor")\nconst options = {mode: "code", allowSchemaSuggestions: true, schema: {\ntype: "object",\nproperties: {\n${Object.entries(Object.assign(Object.assign({},A),{ssl:{cert:"",key:""}})).map((([e,t])=>`${e}: {type: ${"unwantedHeaderNamesInMocks"===e?'"array","items": {"type":"string"}':"number"==typeof t?'"integer"':"string"==typeof t?'"string"':"boolean"==typeof t?'"boolean"':'"object"'}}`)).join(",\n ")}\n},\nrequired: [],\nadditionalProperties: false\n}}\n\nfunction save() {\nsocket.send(JSON.stringify(editor.get()));\n}\n\nfunction generateSslCertificate() {\nconst sslModal = new bootstrap.Modal(document.getElementById('ssl-modal'), {});\nsslModal.show()\nsetTimeout(function() {\nconst keypair = forge.pki.rsa.generateKeyPair(2048);\nconst certificate = forge.pki.createCertificate();\nconst now = new Date();\nconst fiveYears = new Date(new Date(now).setFullYear(now.getFullYear() + 5));\nObject.assign(certificate, {\npublicKey: keypair.publicKey,\nserialNumber: "01",\nvalidity: {\nnotBefore: now,\nnotAfter: fiveYears,\n},\n});\ncertificate.sign(keypair.privateKey, forge.md.sha256.create());\nconst key = forge.pki.privateKeyToPem(keypair.privateKey);\nconst cert = forge.pki.certificateToPem(certificate);\nconst existingConfig = editor.get();\neditor.set({ ...existingConfig, ssl: { key, cert },\nport: parseInt(("" + existingConfig.port).replace(/(80|[0-9])80$/, '443'))\n});\nsslModal.hide();\n}, 100);\n}\n\nconst editor = new JSONEditor(container, options);\nlet socket;\nconst initialJson = ${JSON.stringify(t.config)}\neditor.set(initialJson)\neditor.validate();\neditor.aceEditor.commands.addCommand({\nname: 'save',\nbindKey: {win: 'Ctrl-S', mac: 'Command-S'},\nexec: save,\n});\n\nwindow.addEventListener("DOMContentLoaded", function() {\ndocument.getElementById('jsoneditor').style.height =\n(document.documentElement.clientHeight - 150) + 'px';\ndocument.getElementById('jsoneditor').style.width =\nparseInt(window.getComputedStyle(\ndocument.querySelector('.container')).maxWidth) + 'px';\nconst sslButton = document.createElement('button');\nsslButton.addEventListener("click", generateSslCertificate);\nsslButton.type="button";\nsslButton.classList.add("btn");\nsslButton.classList.add("btn-primary");\nsslButton.innerHTML="&#x1F512;";\ndocument.querySelector('.jsoneditor-menu')\n.appendChild(sslButton);\nconst saveButton = document.createElement('button');\nsaveButton.addEventListener("click", save);\nsaveButton.type="button";\nsaveButton.classList.add("btn");\nsaveButton.classList.add("btn-primary");\nsaveButton.innerHTML="&#x1F4BE;";\ndocument.querySelector('.jsoneditor-menu')\n.appendChild(saveButton);\nsocket = new WebSocket("ws${t.config.ssl?"s":""}://${e}/local-traffic-config");\nsocket.onmessage = function(event) {\neditor.set(JSON.parse(event.data))\neditor.validate()\n}\n});\n<\/script>\n</body></html>`),recorder:(e,t,n)=>{var o,r,s,i,a,l,d,c,u,p;return(null===(o=n.url)||void 0===o?void 0:o.endsWith("?forceLogInRecorderPage=true"))?J('{"ping":"pong"}',{contentType:"application/json; charset=utf-8"}):"GET"===n.method&&(null===(s=null===(r=n.headers)||void 0===r?void 0:r.accept)||void 0===s?void 0:s.includes("application/json"))?J(JSON.stringify(Object.assign(Object.assign({},t.mockConfig),{mode:t.mode,mocks:[...t.mockConfig.mocks.entries()].map((([e,t])=>({uniqueHash:e,response:t})))})),{contentType:"application/json; charset=utf-8"}):["PUT","POST","DELETE"].includes(null!==(i=n.method)&&void 0!==i?i:"")?J('{"status": "acknowledged"}',{contentType:"application/json; charset=utf-8",onOutboundWrite:e=>N(t,e,"DELETE"===n.method)}):J(`${W(9210,"recorder","")}\n<link href="${M}jsoneditor/dist/jsoneditor.min.css" rel="stylesheet" type="text/css">\n<script src="${M}jsoneditor/dist/jsoneditor.min.js"><\/script>\n<script src="${M}pako/dist/pako.min.js"><\/script>\n<form>\n<div id="commands"${t.mockConfig.autoRecord?' style="filter:blur(8px)"':""}>\n<span>Mode : </span>\n<div class="btn-group" role="group" aria-label="Server Mode">\n<input type="radio" class="btn-check" name="server-mode" id="record-mode" autocomplete="off"${t.mode===f.PROXY?" checked":""}>\n<label class="btn btn-outline-primary" for="record-mode">&#9210; Record</label>\n<input type="radio" class="btn-check" name="server-mode" id="mock-mode" autocomplete="off"${t.mode===f.MOCK?" checked":""}>\n<label class="btn btn-outline-primary" for="mock-mode">&#x1F310; Mock</label>\n</div>\n<span>Actions : </span>\n<button type="button" class="btn btn-light" id="add-mock">&#x2795; Mock from dummy request</button>\n<button type="button" class="btn btn-light" id="upload-mocks">&#x1F4E5; Upload mocks</button>\n<button type="button" class="btn btn-light" id="download-mocks">&#x1F4E6; Download mocks</button>\n<button type="button" class="btn btn-light" id="delete-mocks">&#x1F5D1; Delete mocks</button>\n</div>\n<div class="row">\n<div class="col-lg" style="max-width: 200px">\n<div class="form-check form-switch" id="strict-mock-mode-form-control">\n<input class="form-check-input" type="checkbox" id="strict-mock-mode"${t.mockConfig.strict?' checked="checked"':""}>\n<label class="form-check-label" for="strict-mock-mode">Strict mock mode</label>\n</div>\n</div>\n<div class="col-lg" style="max-width: 200px">\n<div class="form-check form-switch">\n<input class="form-check-input" type="checkbox" id="auto-record-mode"${t.mockConfig.autoRecord?' checked="checked"':""}>\n<label class="form-check-label" for="auto-record-mode">Auto record mode</label>\n</div>\n</div>\n<div class="col-lg">&nbsp;</div>\n</div>\n<input type="hidden" id="limit" value="0"/>\n<div class="modal fade" id="edit-request" tabindex="-1" \naria-labelledby="edit-request-label" aria-hidden="true">\n<div class="modal-dialog" style="max-width: 900px">\n<div class="modal-content">\n<div class="modal-header">\n<h1 class="modal-title fs-5" id="edit-request-label">Edit request to /</h1>\n<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>\n</div>\n<div class="modal-body">\n<div class="container">\n<div class="row">\n<div class="col-lg">\n<h2>Request :</h2>\n<div id="uniqueHash-editor" style="width: 400px; height: 400px;"></div>\n</div>\n<div class="col-lg">\n<h2>Response : </h2>\n<div id="response-editor" style="width: 400px; height: 400px;"></div>\n</div>\n</div>\n</div>\n</div>\n<div class="modal-footer">\n<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>\n<button type="button" class="btn btn-primary" onclick="javascript:saveRequest()">Save changes</button>\n</div>\n</div>\n</div>\n</div>\n<script>\nconst xmlOrJsonPrologsInBase64 = [\n"eyJ","PD94bWw=","PCFET0NUWVBF","PCFkb2N0eXBl","PGh0bWw","PEhUTUw","H4sIAAAAAAAA", "W3tc"\n];\nfunction getMocksData () {\nreturn JSON.stringify(\n[...document.querySelectorAll('button[data-uniqueHash]')].map(button => ({\nresponse: button.attributes['data-response']?.value,\nuniqueHash: button.attributes['data-uniqueHash']?.value}))\n)\n}\nfunction updateState () {\nfetch("http${t.config.ssl?"s":""}://${e}${null!==(d=null===(l=Object.entries(null!==(a=t.config.mapping)&&void 0!==a?a:{}).find((([e,t])=>{var n;return null===(n=null==t?void 0:t.toString())||void 0===n?void 0:n.startsWith("recorder:")})))||void 0===l?void 0:l[0])&&void 0!==d?d:"/recorder/"}", {\nmethod: 'PUT',\nheaders: { 'Content-Type': 'application/json' },\nbody: '{"strict":' + document.getElementById('strict-mock-mode').checked +\n',"autoRecord":' + document.getElementById('auto-record-mode').checked +\n',"mode":"' + \n(document.getElementById('mock-mode').checked ? "mock" : "proxy") + '"' +\n',"mocks":' + getMocksData() + '}'\n})\n}\nfunction loadMocks(mocksHashes) {\nconst time = new Date().toISOString().split('T')[1].replace('Z', '');\nlet mocks = [];\ntry {\nmocks = mocksHashes.map(mock => ({...mock, \nrequest: JSON.parse(atob(mock.uniqueHash)),\nresponse: JSON.parse(atob(mock.response))\n}));\n} catch(e) { }\nmocks.forEach(mock => {\nconst randomId = window.crypto.randomUUID();\nconst actions = getActionsHtmlText(mock.uniqueHash, mock.response);\naddNewRequest(randomId, actions, time, 'info', 'HTTP/2', mock.request.method, \n'<span class="badge bg-' + \ngetColorFromStatusCode(mock.response.status) + '">' + \nmock.response.status + \n'</span>', \n'0ms', mock.request.url, \n'N/A');\n});\n}\ndocument.getElementById('add-mock').addEventListener('click', () => {\nconst iframe = document.createElement('iframe');\niframe.style.display = 'none';\niframe.onload = function() { iframe.parentNode.removeChild(iframe); };\niframe.src = "http${t.config.ssl?"s":""}://${e}${null!==(p=null===(u=Object.entries(null!==(c=t.config.mapping)&&void 0!==c?c:{}).find((([e,t])=>{var n;return null===(n=null==t?void 0:t.toString())||void 0===n?void 0:n.startsWith("recorder:")})))||void 0===u?void 0:u[0])&&void 0!==p?p:"/recorder/"}?forceLogInRecorderPage=true";\ndocument.body.appendChild(iframe);\n});\ndocument.getElementById('upload-mocks').addEventListener('click', () => {\nconst time = new Date().toISOString().split('T')[1].replace('Z', '');\nconst fileInput = document.createElement('input');\nfileInput.type = "file";\nfileInput.multiple = "multiple";\nfileInput.onchange = function() {\nconst fileReader = new FileReader();\n[...fileInput.files].reduce((promise, file) =>\npromise.then(result => new Promise(resolve => {\nfileReader.readAsText(file);\nfileReader.onload = function(){\nresolve(result.concat(fileReader.result));\n};\n})), Promise.resolve([]))\n.then(files => files.flatMap(file => JSON.parse(file)))\n.catch(e => [])\n.then(mocks => loadMocks(mocks))\n.then(() => updateState());\n}\nfileInput.click();\n});\ndocument.getElementById('download-mocks').addEventListener('click', () => {\nconst link = document.createElement('a');\nlink.href = URL.createObjectURL(new Blob([getMocksData()], {\ntype: "application/json",\n}));\nlink.download = "mocks-" + new Date().toISOString() + ".json";\nlink.click();\nURL.revokeObjectURL(link.href);\n})\ndocument.getElementById('delete-mocks').addEventListener('click', () => {\ndocument.getElementById('limit').value = -1;\ncleanup();\nupdateState();\ndocument.getElementById('limit').value = 0;\n})\ndocument.getElementById('record-mode').addEventListener('change', () => {\ndocument.getElementById('limit').value = 0;\ncleanup();\nupdateState();\n})\ndocument.getElementById('mock-mode').addEventListener('change', () => {\nupdateState();\n})\ndocument.getElementById('auto-record-mode').addEventListener('change', (e) => { \nupdateState();\ndocument.getElementById('table-access').style.filter = \ndocument.getElementById('auto-record-mode').checked ? 'blur(8px)' : 'blur(0px)';\ndocument.getElementById('commands').style.filter = \ndocument.getElementById('auto-record-mode').checked ? 'blur(8px)' : 'blur(0px)';\ndocument.getElementById('alert-about-auto-record-mode').style.display = \ndocument.getElementById('auto-record-mode').checked ? 'block' : 'none';\ndocument.getElementById('strict-mock-mode-form-control').style.filter = \ndocument.getElementById('auto-record-mode').checked ? 'blur(8px)' : 'blur(0px)';\n\n})\ndocument.getElementById('strict-mock-mode').addEventListener('change', (e) => { \nupdateState();\n})\nfunction saveRequest () {\n$('#edit-request').modal("hide");\n\nconst requestBeingEdited = window.requestBeingEdited;\nlet request = uniqueHashEditor.get();\nlet response = responseEditor.get();\nif (typeof request.body === "object") {\nrequest.body = JSON.stringify(request.body);\n}\nif (typeof response.body === "object") {\nresponse.body = JSON.stringify(response.body);\n}\nconst oldRequest = JSON.parse(atob(requestBeingEdited.attributes['data-uniqueHash'].value));\nconst oldResponse = JSON.parse(atob(requestBeingEdited.attributes['data-response'].value));\nconst requestProlog = requestBeingEdited.attributes['data-requestProlog']?.value;\nconst responseProlog = requestBeingEdited.attributes['data-responseProlog']?.value;\nconst requestPrologHasChanged = request.body.substring(0, 10) !== oldRequest.body.substring(0, 10);\nconst responsePrologHasChanged = response.body.substring(0, 10) !== response.body.substring(0, 10);\nif (requestProlog === "H4sIAAAAAAAA" && !requestPrologHasChanged) {\nrequest.body =\nbtoa([...pako.gzip(request.body)].map(e => String.fromCharCode(e)).join(""));\n} else if ((requestProlog === null || !request.body.startsWith(requestProlog ?? "")) && \nrequest.body.substring(0, 10) !== oldRequest.body.substring(0, 10)) {\nrequest.body = btoa(request.body);\n}\nif (responseProlog === "H4sIAAAAAAAA" && !responsePrologHasChanged) {\nresponse.body =\nbtoa([...pako.gzip(response.body)].map(e => String.fromCharCode(e)).join(""));\n} else if ((responseProlog === null || !response.body.startsWith(responseProlog ?? "")) && \nresponse.body.substring(0, 10) !== oldResponse.body.substring(0, 10)) {\nresponse.body = btoa(response.body);\n}\nrequest = btoa(JSON.stringify(request));\nresponse = btoa(JSON.stringify(response));\nrequestBeingEdited.setAttribute('data-uniqueHash', request);\nrequestBeingEdited.setAttribute('data-response', response);\nconst row = requestBeingEdited.closest('tr');\nrow.querySelector("td.method").innerHTML = uniqueHashEditor.get().method;\nrow.querySelector("td.upstream-path").innerHTML = uniqueHashEditor.get().url;\nwindow.requestBeingEdited = undefined;\nupdateState();\n}\ndocument.getElementById('edit-request').addEventListener('show.bs.modal', event => {\nconst request = JSON.parse(atob(event.relatedTarget.attributes['data-uniqueHash'].value));\nconst response = JSON.parse(atob(event.relatedTarget.attributes['data-response'].value));\nconst requestProlog = xmlOrJsonPrologsInBase64.find(prolog => request.body?.startsWith(prolog));\nconst responseProlog = xmlOrJsonPrologsInBase64.find(prolog => response.body?.startsWith(prolog));\nif (requestProlog) {\nevent.relatedTarget.setAttribute('data-requestProlog', requestProlog);\nrequest.body = request.body.startsWith("H4sIAAAAAAAA") \n? pako.ungzip(new Uint8Array(atob(request.body).split("").map(e => e.charCodeAt(0))), {to: "string"})\n: atob(request.body);\nrequest.body = request.body.startsWith("{\\"") || request.body.startsWith("[{\\"")\n? JSON.parse(request.body) : request.body;\n}\nif (responseProlog) {\nevent.relatedTarget.setAttribute('data-responseProlog', responseProlog);\nresponse.body = response.body.startsWith("H4sIAAAAAAAA") \n? pako.ungzip(new Uint8Array(atob(response.body).split("").map(e => e.charCodeAt(0))), {to: "string"})\n: atob(response.body);\nresponse.body = response.body.startsWith("{\\"") || response.body.startsWith("[{\\"")\n? JSON.parse(response.body) : response.body;\n}\nwindow.requestBeingEdited = event.relatedTarget;\nwindow.uniqueHashEditor.set(request);\nwindow.responseEditor.set(response);\ndocument.getElementById('edit-request-label').innerText = "Edit request to " + request.url;\n})\n\nsetTimeout(() => {\nloadMocks(${JSON.stringify([...t.mockConfig.mocks.entries()].map((([e,t])=>({uniqueHash:e,response:t}))))});\nwindow.uniqueHashEditor = new JSONEditor(document.getElementById("uniqueHash-editor"), {\nmode: "code", allowSchemaSuggestions: true, schema: {\ntype: "object",\nproperties: {\nmethod: {type: "string"},\nurl: {type: "string"},\nbody: {oneOf: [{type:"string"},{type:"object"},{type:"array"}]},\nheaders: {type: "object"},\n},\nrequired: [],\nadditionalProperties: false\n}});\nwindow.responseEditor = new JSONEditor(document.getElementById("response-editor"), {\nmode: "code", allowSchemaSuggestions: true, schema: {\ntype: "object",\nproperties: {\nbody: {oneOf: [{type:"string"},{type:"object"},{type:"array"}]},\nheaders: {type: "object"},\nstatus: {type: "integer"}\n},\nrequired: [],\nadditionalProperties: false\n}});\n${t.mockConfig.autoRecord?";document.getElementById('strict-mock-mode-form-control').style.filter='blur(8px)';;document.getElementById('table-access').style.filter='blur(8px)';":""}\ndocument.forms[0].reset();\n}, 10)\n<\/script>\n</form>\n<div class="alert alert-warning" role="alert"\nstyle="display:${t.mockConfig.autoRecord?"block":"none"};left:20%;right:20%;position:absolute;z-index:1;" id="alert-about-auto-record-mode">\n&#x24D8;&nbsp;Auto-record mode and recorder webapp are known to be mutually exclusive.\n<br/><br/>Changing the mocks on both sides is somehow hard to sort out.\n<br/>This is triggering concurrent modifications in the mock config.\n<hr/>\nHere is what you can do :\n<ul>\n<li>If you want to record mocks using a frontend app, turn off the auto-record mode.</li>\n<li>If you want to record mocks with the recorder API only, close this app.</li>\n</ul>\n</div>\n${q(e,t.config,{captureResponseBody:!0})}\n</body>\n</html>`)},file:(e,t,n,o)=>{const r=null==o?void 0:o.target,s=(0,d.resolve)("/",r.hostname,...r.pathname.replace(/[?#].*$/,"").replace(/^\/+/,"").split("/").map(decodeURIComponent));return{alpnProtocol:"file",error:null,data:null,hasRun:!1,run:function(){return this.hasRun?Promise.resolve():new Promise((e=>(0,a.readFile)(s,((t,n)=>{if(this.hasRun=!0,!t||"EISDIR"!==t.code)return this.error=t,this.data=n,void e(void 0);(0,a.readdir)(s,((t,n)=>{this.error=t,this.data=n,t?e(void 0):Promise.all(n.map((e=>new Promise((t=>(0,a.lstat)((0,d.resolve)(r.pathname,e),((n,o)=>t([e,o,n])))))))).then((t=>{const n=t.filter((e=>!e[2]&&e[1].isDirectory())).concat(t.filter((e=>!e[2]&&e[1].isFile())));this.data=`${W(128194,"directory",r.href)}<p>Directory content of <i>${r.href.replace(/\//g,"&#x002F;")}</i></p><ul class="list-group"><li class="list-group-item">&#x1F4C1;<a href="${r.pathname.endsWith("/")?"..":"."}">&lt;parent&gt;</a></li>${n.filter((e=>!e[2])).map((e=>`<li class="list-group-item">&#x${(e[1].isDirectory()?128193:128196).toString(16)};<a href="${r.pathname.endsWith("/")?"":`${r.pathname.split("/").slice(-1)[0]}/`}${e[0]}">${e[0]}</a></li>`)).join("\n")}</li></ul></body></html>`,e(void 0)}))}))}))))},events:{},on:function(e,t){return this.events[e]=t,this.run().then((()=>{"response"===e&&this.events.response(s.endsWith(".svg")?{Server:"local","Content-Type":"image/svg+xml"}:{Server:"local"},0),"data"===e&&this.data&&(this.events.data(this.data),this.events.end()),"error"===e&&this.error&&this.events.error(this.error)})),this},end:function(){return this},request:function(){return this},write:function(){return this}}},data:(e,t,n,o)=>{var r,s,i,a,l,d;const[,c,u,p]=null!==(s=/^data:([^;,]*)?;?([^,]*)?,(.*)$/.exec(null!==(r=null==o?void 0:o.target.href)&&void 0!==r?r:"data:,"))&&void 0!==s?s:["","","",""],m=decodeURIComponent(p),g="base64"===u?Buffer.from(m,"base64url").toString("binary"):m;return J(t.config.replaceResponseBodyUrls?_(Buffer.from(g),{"content-type":c||"text/plain"},{mapping:null!==(i=t.config.mapping)&&void 0!==i?i:{},proxyHostnameAndPort:e,proxyHostname:null!==(a=null==o?void 0:o.proxyHostname)&&void 0!==a?a:"localhost",key:null!==(l=null==o?void 0:o.key)&&void 0!==l?l:"",direction:h.INBOUND,ssl:!!t.config.ssl,port:null!==(d=t.config.port)&&void 0!==d?d:null==A?void 0:A.port}):g,{contentType:c})}},P=Object.keys(j),L=P.map((e=>`${e}:`)),A={mapping:Object.assign({},...P.filter((e=>"data"!==e&&"file"!==e)).map((e=>({[`/${e}/`]:`${e}://`})))),port:8080,replaceRequestBodyUrls:!1,replaceResponseBodyUrls:!1,dontUseHttp2Downstream:!1,dontTranslateLocationHeader:!1,logAccessInTerminal:!1,simpleLogs:!1,websocket:!0,disableWebSecurity:!1,connectTimeout:3e3,socketTimeout:3e3,unwantedHeaderNamesInMocks:[]},H=(...e)=>t(void 0,[...e],void 0,(function*(e=!0){return new Promise((t=>(0,a.readFile)(y,((n,o)=>{n&&!e&&k(null,[[{text:`${g.ERROR_1} config error. Using default value`,color:m.ERROR}]]);let r=null;try{r=Object.assign({},A,JSON.parse((null!=o?o:"{}").toString()))}catch(e){return r=null!=r?r:Object.assign({},A),k({config:void 0},[[{text:`${g.ERROR_2} config syntax incorrect, ignoring`,color:m.ERROR}]]).then((()=>t(r)))}n&&"ENOENT"===n.code&&e&&y===v?(0,a.writeFile)(y,JSON.stringify(A,null,2),(e=>k(null,e?[[{text:`${g.ERROR_4} config file NOT created`,color:m.ERROR}]]:[[{text:`${g.COLORED} config file created`,color:m.INFO}]]).then((()=>t(r))))):t(r)}))))}));exports.load=H;const U=e=>""==e?"":(0,d.normalize)(e).replace(/\\/g,"/"),M="https://cdn.jsdelivr.net/npm/",D=["host","connection","keep-alive","upgrade","transfer-encoding","upgrade-insecure-requests","proxy-connection"],W=(e,t,n)=>`<!doctype html>\n<html lang="en">\n<head>\n<title>&#x${e.toString(16)}; local-traffic ${t} | ${n}</title>\n<link href="${M}bootstrap/dist/css/bootstrap.min.css" rel="stylesheet"/>\n<script src="${M}jquery/dist/jquery.min.js"><\/script>\n<script src="${M}bootstrap/dist/js/bootstrap.bundle.min.js"><\/script>\n</head>\n<body><div class="container"><h1>&#x${e.toString(16)}; local-traffic ${t}</h1>\n<br/>`,F=({response:e})=>({alpnProtocol:"mock",error:null,data:null,hasRun:!1,run:function(){return this.hasRun?Promise.resolve():new Promise((t=>{try{this.data=JSON.parse(Buffer.from(e,"base64").toString("utf-8"))}catch(e){this.data={}}t(void 0)}))},events:{},on:function(e,t){return this.events[e]=t,this.run().then((()=>{var t;"response"===e&&this.events.response(Object.assign(Object.assign({},this.data.headers),{"X-LocalTraffic-Mock":"1"}),this.data.status),"data"===e&&this.data&&(this.events.data(Buffer.from(null!==(t=this.data.body)&&void 0!==t?t:"","base64")),this.events.end()),"error"===e&&this.error&&this.events.error(this.error)})),this},end:function(){return this},request:function(){return this},write:function(){return this}}),J=(e,t)=>({alpnProtocol:"static",error:null,data:null,outboundData:null,run:function(){return"string"==typeof e?new Promise((t=>{this.data=e,t(void 0)})):e.then((e=>{this.data=e.toString("utf8")}))},events:{},on:function(e,n){return this.events[e]=n,this.run().then((()=>{var n;"response"===e&&this.events.response({Server:"local","Content-Type":null!==(n=null==t?void 0:t.contentType)&&void 0!==n?n:"text/html"},0),"data"===e&&this.data&&(this.events.data(this.data),this.events.end()),"error"===e&&this.error&&this.events.error(this.error)})),this},write:function(e){var n;return this.outboundData=e,e instanceof Buffer&&(null===(n=null==t?void 0:t.onOutboundWrite)||void 0===n||n.call(t,e)),this},end:function(){return this},request:function(){return this}}),_=(e,n,o)=>t(void 0,void 0,void 0,(function*(){var r,s;return(null!==(s=null===(r=n["content-encoding"])||void 0===r?void 0:r.toString())&&void 0!==s?s:"").split(",").reduce(((e,n)=>t(void 0,void 0,void 0,(function*(){const t=n.trim().toLowerCase(),o="gzip"===t||"x-gzip"===t?l.gunzip:"deflate"===t?l.inflate:"br"===t?l.brotliDecompress:"identity"===t||""===t?(e,t)=>{t(null,e)}:null;if(null===o)throw new Error(`${t} compression not supported by the proxy`);const r=yield e;return yield new Promise(((e,t)=>o(r,((n,o)=>{n&&t(n),e(o)}))))}))),Promise.resolve(e)).then((e=>{const t=e.length>1e7,r=["text/html","application/javascript","application/json"].some((e=>{var t;return(null!==(t=n["content-type"])&&void 0!==t?t:"").toString().includes(e)}));return!t&&(r||!/[^\x00-\xFF]/.test(e.toString()))?K(e.toString(),{direction:o.direction,proxyHostnameAndPort:o.proxyHostnameAndPort,ssl:o.ssl,mapping:o.mapping}).replace(/\?protocol=wss?%3A&hostname=[^&]+&port=[0-9]+&pathname=/g,`?protocol=ws${o.ssl?"s":""}%3A&hostname=${o.proxyHostname}&port=${o.port}&pathname=${encodeURIComponent(o.key.replace(/\/+$/,""))}`):e})).then((e=>{var t,o;return(null!==(o=null===(t=n["content-encoding"])||void 0===t?void 0:t.toString())&&void 0!==o?o:"").split(",").reverse().reduce(((e,t)=>{const n=t.trim().toLowerCase(),o="gzip"===n||"x-gzip"===n?l.gzip:"deflate"===n?l.deflate:"br"===n?l.brotliCompress:"identity"===n||""===n?(e,t)=>{t(null,e)}:null;if(null===o)throw new Error(`${n} compression not supported by the proxy`);return e.then((e=>new Promise((t=>o(e,((e,n)=>{if(e)throw e;t(n)}))))))}),Promise.resolve(Buffer.from(e)))}))}));exports.replaceBody=_;const K=(e,{direction:t,proxyHostnameAndPort:n,ssl:o,mapping:r})=>Object.entries(r).map((([e,t])=>[e,"string"==typeof t?t:t.replaceBody])).reduce(((e,[r,s])=>L.some((e=>s.startsWith(e)))||""!==r&&!r.match(/^[-a-zA-Z0-9()@:%_\+.~#?&//=]*$/)?e:t===h.INBOUND?e.replace(new RegExp(s.replace(new RegExp(`^(${P.join("|")})://`),"").replace(/[*+?^${}()|[\]\\]/g,"").replace(/^https/,"https?")+"/*","ig"),`http${o?"s":""}://${n}${r.replace(/\/+$/,"")}/`):e.split(`http${o?"s":""}://${n}${r.replace(/\/+$/,"")}`).join(s)),e).split(`${n}/:`).join(`${n}:`);exports.replaceTextUsingMapping=K;const z=(e,t)=>{try{const n="object"==typeof t?t:JSON.parse(Buffer.from(t,"base64").toString("utf-8"));return["access-control-max-age","authorization","cache-control","cookie","date","dnt","expires","if-modified-since","if-unmodified-since","keep-alive","last-modified","pragma","proxy-authenticate","proxy-authorization","referer","retry-after","signed-headers","server-timing","sec-ch-ua","sec-ch-ua-mobile","sec-ch-ua-platform","sec-fetch-dest","sec-fetch-mode","sec-fetch-site","sec-fetch-user","upgrade-insecure-requests","user-agent",...Array.isArray(e.unwantedHeaderNamesInMocks)?e.unwantedHeaderNamesInMocks:[]].forEach((e=>{var t;null===(t=null==n?void 0:n.headers)||void 0===t||delete t[e]})),n.headers=Object.keys(n.headers).sort().reduce(((e,t)=>(e[t]=n.headers[t],e)),{}),Buffer.from(JSON.stringify(n),"utf-8").toString("base64")}catch(e){return t}};exports.cleanEntropy=z;const G=(e,t,n)=>{t.writeHead(e,{"content-type":"text/html","content-length":n.length}),t.end(n)};exports.send=G;const Y=(e,t)=>{var n,o,r,s,a,l,d,c;const u=(null!==(r=null!==(o=null===(n=e.headers[":authority"])||void 0===n?void 0:n.toString())&&void 0!==o?o:e.headers.host)&&void 0!==r?r:"localhost").replace(/:.*/,""),p=e.headers[":authority"]||`${e.headers.host}${(null!==(s=e.headers.host)&&void 0!==s?s:"").match(/:[0-9]+$/)?"":80!==t.port||t.ssl?443===t.port&&t.ssl?"":`:${null!==(a=t.port)&&void 0!==a?a:8080}`:""}`,m=new i.URL(`http${t.ssl?"s":""}://${p}${null!==(l=e.url)&&void 0!==l?l:""}`),g=m.href.substring(m.origin.length),h=Object.assign({},Object.assign({},...Object.entries(null!==(d=t.mapping)&&void 0!==d?d:{}).map((([e,t])=>{var n,o;const r="string"==typeof t?t:null!==(n=null==t?void 0:t.downstreamUrl)&&void 0!==n?n:"";return{[e]:new i.URL((null===(o=null==r?void 0:r.startsWith)||void 0===o?void 0:o.call(r,"data:"))?r:U(r))}}))));let f=null;const[v,y]=null!==(c=Object.entries(h).find((([e])=>{var t;return f=null!==(t=g.match(RegExp(e.replace(/^\//,"^/"))))&&void 0!==t?t:null})))&&void 0!==c?c:["/"],b=f&&y?new i.URL(y.href.replace(/\$\$(\d+)/g,((e,t)=>f[parseInt(t)]))):null;return{proxyHostname:u,proxyHostnameAndPort:p,url:m,path:g,key:v,target:b}};exports.determineMapping=Y;const X=function(e,t,n){var o,a,l,d,c,u,p,h,f,v;if(n.on("error",(()=>{e.log([[{text:`${g.WEBSOCKET} websocket connection reset`,color:m.WARNING}]])})),!e.config.websocket)return n.end("HTTP/1.1 503 Service Unavailable\r\n\r\n"),{};const{key:y,target:b,path:O,url:k}=Y(t,e.config);if(O.startsWith("/local-traffic-logs"))return E(n,null!==(o=t.headers["sec-websocket-key"])&&void 0!==o?o:""),{logsListeners:e.logsListeners.concat({stream:n,wantsMask:!(null!==(l=null===(a=t.headers["user-agent"])||void 0===a?void 0:a.toString())&&void 0!==l?l:"").includes("Chrome"),wantsResponseMessage:[...k.searchParams.entries()].some((([e,t])=>"wantsResponseMessage"===e&&"true"===t))})};if("/local-traffic-config"===O){E(n,null!==(d=t.headers["sec-websocket-key"])&&void 0!==d?d:"");let o=null;return n.on("data",(t=>{const n=R(t,o);if(null===o&&n.body.length<n.payloadLength)o=n;else{if(n.body.length>=n.payloadLength&&0===n.body.length)return{};if(n.body.length>=n.payloadLength){let t;o=null;try{t=JSON.parse(n.body)}catch(t){return e.log([[{text:`${g.ERROR_4} config file NOT read, try again later`,color:m.WARNING}]]),{}}ee(e,{pendingConfigSave:t})}}})),{configListeners:e.configListeners.concat({stream:n,wantsMask:!(null!==(u=null===(c=t.headers["user-agent"])||void 0===c?void 0:c.toString())&&void 0!==u?u:"").includes("Chrome")})}}const w=new i.URL(`${null!==(p=null==b?void 0:b.protocol)&&void 0!==p?p:"https"}//${null!==(h=null==b?void 0:b.host)&&void 0!==h?h:"localhost"}${null===(v=null===(f=t.url)||void 0===f?void 0:f.replace(new RegExp(`^${y}`,"g"),b.pathname))||void 0===v?void 0:v.replace(/^\/*/,"/")}`),$={hostname:w.hostname,path:w.pathname,port:w.port,protocol:w.protocol,rejectUnauthorized:!1,method:t.method,headers:Object.assign(Object.assign({},t.headers),{host:w.hostname,origin:w.origin}),host:w.hostname},x="https:"===w.protocol?(0,s.request)($):(0,r.request)($);return x.end(),x.on("error",(t=>{e.log([[{text:`${g.WEBSOCKET} websocket request has errored ${t.errno?`(${t.errno})`:""}`,color:m.WARNING}]])})),x.on("upgrade",((t,o)=>{const r=`HTTP/${t.httpVersion} ${t.statusCode} ${t.statusMessage}\r\n${Object.entries(t.headers).flatMap((([e,t])=>(Array.isArray(t)?t:[t]).map((t=>[e,t])))).map((([e,t])=>`${e}: ${t}\r\n`)).join("")}\r\n`;n.write(r),n.allowHalfOpen=!0,o.allowHalfOpen=!0,o.on("data",(e=>n.write(e))),n.on("data",(e=>o.write(e))),o.on("error",(t=>{e.log([[{text:`${g.WEBSOCKET} downstream socket has errored ${t.errno?`(${t.errno})`:""}`,color:m.WARNING}]])})),n.on("error",(t=>{e.log([[{text:`${g.WEBSOCKET} upstream socket has errored ${t.errno?`(${t.errno})`:""}`,color:m.WARNING}]])}))})),{}};exports.websocketServe=X;const Z=function(e,n,r){return t(this,void 0,void 0,(function*(){var s,a,l,d,p,v,O,k,w,R,E,$,x,S,C,I,q,N,P,H,M,W,J,X,Z,Q,V,ee;if(!n.headers.host&&!n.headers[":authority"])return void G(400,r,Buffer.from(B(new Error("client must supply a 'host' header"),e.mode,"proxy",new i.URL(`http${e.config.ssl?"s":""}://unknowndomain${n.url}`))));const{proxyHostname:te,proxyHostnameAndPort:ne,url:oe,path:re,key:se,target:ie}=Y(n,e.config),ae=null!=ie?ie:e.mode===f.MOCK?new i.URL(`http${e.config.ssl?"s":""}://${ne}/`):null;if(!ae)return void G(502,r,Buffer.from(B(new Error(`No mapping found in config file ${y}`),e.mode,"proxy",oe)));const le="data:"===ae.protocol?"":"//",de=ae.host.replace(RegExp(/\/+$/),""),ce=ae.href.substring(`${ae.protocol}${le}`.length+ae.host.length),ue="file:"===ae.protocol||"data:"===ae.protocol?ce:`${ce}${U(re.replace(RegExp(U(se)),""))}`.replace(/^\/*/,"data:"===ae.protocol?"":"/"),pe=new i.URL(`${ae.protocol}${le}${de}${ue}`),me=L.some((e=>ae.protocol===e)),ge=(0,c.randomBytes)(20).toString("hex");let he=null;const fe=e.config.replaceRequestBodyUrls||!!e.logsListeners.length;e.config.ssl&&(yield new Promise((e=>setTimeout(e,1))));const ve=parseInt(null!==(s=n.headers["content-length"])&&void 0!==s?s:"0")>0,ye=!!(null==n?void 0:n.readableLength)||ve,be=!!(null==n?void 0:n.stream)&&ve,Oe=!((e.config.ssl&&!1===be||!e.config.ssl&&!1===ye)&&("0"===n.headers["content-length"]||void 0===n.headers["content-length"]));if(fe){const t=null!==(a=null==n?void 0:n.stream)&&void 0!==a?a:n;let o=Buffer.from([]);yield Promise.race([new Promise((t=>setTimeout(t,e.config.connectTimeout))),new Promise((e=>{Oe?(t.on("data",(e=>{o=Buffer.concat([o,e])})),t.on("end",e),t.on("error",e)):e(void 0)}))]),Oe&&!o.length&&(yield e.log([[{text:`${g.ERROR_4} body replacement error ${re.slice(-17)}`,color:m.WARNING}]])),he=e.config.replaceRequestBodyUrls?yield _(o,n.headers,{proxyHostnameAndPort:ne,proxyHostname:te,key:se,mapping:null!==(l=e.config.mapping)&&void 0!==l?l:{},port:null!==(d=e.config.port)&&void 0!==d?d:A.port,ssl:!!e.config.ssl,direction:h.OUTBOUND}):o}const ke=e.logsListeners.some((e=>e.wantsResponseMessage)),we=e.mockConfig.autoRecord&&e.mode===f.PROXY,Re=z(e.config,{method:null!==(p=n.method)&&void 0!==p?p:"GET",url:null!==(v=n.url)&&void 0!==v?v:"",headers:Object.assign({},...Object.entries(n.headers).filter((([e])=>!e.startsWith(":"))).map((([e,t])=>({[e]:t})))),body:(e.mode===f.MOCK||ke||we)&&null!==(O=null==he?void 0:he.toString("base64"))&&void 0!==O?O:""});e.config.logAccessInTerminal&&!pe.pathname.startsWith("/:/")&&(yield e.log([[{color:"GET"===n.method?22:"POST"===n.method?52:"PUT"===n.method?94:"DELETE"===n.method?244:"OPTIONS"===n.method?19:"PATCH"===n.method?162:"HEAD"===n.method?53:"TRACE"===n.method?6:"CONNECT"===n.method?2:0,text:(null!==(k=n.method)&&void 0!==k?k:"GET").toString(),length:null===(w=n.method)||void 0===w?void 0:w.length},{color:8,text:pe.pathname.toString().padStart(62-(null!==(E=null===(R=n.method)||void 0===R?void 0:R.length)&&void 0!==E?E:3)).substring(0,62-(null!==(x=null===($=n.method)||void 0===$?void 0:$.length)&&void 0!==x?x:3)),length:62-(null!==(C=null===(S=n.method)||void 0===S?void 0:S.length)&&void 0!==C?C:3)}]]));const Ee=e.mode===f.MOCK&&!me,$e=Ee?null!==(I=e.mockConfig.mocks.get(Re))&&void 0!==I?I:null===(q=Array.from(e.mockConfig.mocks.entries()).filter((([t])=>{var n;const o=JSON.parse(Buffer.from(Re,"base64").toString("ascii")),r=JSON.parse(Buffer.from(t,"base64").toString("ascii"));return r.method===o.method&&r.url===o.url&&(!r.body||r.body===o.body)&&Object.entries(null!==(n=r.headers)&&void 0!==n?n:{}).every((([t,n])=>{var r,s,i,a;return!n||(null===(i=null===(s=null===(r=e.config)||void 0===r?void 0:r.unwantedHeaderNamesInMocks)||void 0===s?void 0:s.includes)||void 0===i?void 0:i.call(s,t))||(null===(a=o.headers)||void 0===a?void 0:a[t])===n}))})).sort((([e],[t])=>{var n,o;const r=JSON.parse(Buffer.from(t,"base64").toString("ascii")),s=JSON.parse(Buffer.from(e,"base64").toString("ascii")),i=r.body?1:0,a=s.body?1:0;return Object.keys(null!==(n=r.headers)&&void 0!==n?n:{}).length+i-Object.keys(null!==(o=s.headers)&&void 0!==o?o:{}).length-a}))[0])||void 0===q?void 0:q[1]:null;if(Ee&&!$e&&e.mockConfig.strict)return void G(502,r,Buffer.from(B(new Error("No corresponding mock found in the server. \nTry switching back to the proxy mode"),e.mode,"mock",oe)));let xe=null;const Se=b(),Ce=Object.assign(Object.assign({},[...Object.entries(n.headers)].filter((([e])=>!D.includes(e.toLowerCase()))).reduce(((e,[t,n])=>(e[t]=(e[t]||"")+(Array.isArray(n)?n:[n]).map((e=>null==e?void 0:e.replace(oe.hostname,de))).join(", "),e)),{})),{origin:ae.href,referer:pe.toString(),"content-length":null!==(P=null!==(N=null==he?void 0:he.length)&&void 0!==N?N:n.headers["content-length"])&&void 0!==P?P:0,":authority":de,":method":n.method,":path":ue,":scheme":ae.protocol.replace(":","")}),Ie=Ee&&$e?F({response:$e}):me?j[ae.protocol.replace(/:$/,"")](ne,e,n,{target:pe,proxyHostname:te,key:se}):yield((e,n,r)=>t(void 0,void 0,void 0,(function*(){var e,t;let s=null,i="https:"===(null===(e=null==r?void 0:r.target)||void 0===e?void 0:e.protocol)&&!n.config.dontUseHttp2Downstream;const a=i?n.mode!==f.PROXY&&(null===(t=null==n?void 0:n.mockConfig)||void 0===t?void 0:t.strict)?null:yield Promise.race([new Promise((e=>{const t=(0,o.connect)(r.target,{timeout:n.config.connectTimeout,sessionTimeout:n.config.socketTimeout,rejectUnauthorized:!1,protocol:r.target.protocol},((n,o)=>{i=i&&!!o.alpnProtocol,e(i?t:null)}));t.on("error",(e=>{s=i?Buffer.from(B(e,n.mode,"connection",r.url,r.target)):null}))})),new Promise((e=>setTimeout((()=>{i=!1,e(null)}),n.config.connectTimeout)))]):null;if(s)throw s;return i?a:null})))(0,e,{target:pe,url:oe}).then((t=>t||T(ae,oe,pe,ue,n,Ce,he,fe,e.mode))).catch((e=>(xe=e,null))),Be=(null===(M=null===(H=null==Ie?void 0:Ie.alpnProtocol)||void 0===H?void 0:H.startsWith)||void 0===M?void 0:M.call(H,"h2"))?"HTTP/2":null!==(W=null==Ie?void 0:Ie.alpnProtocol)&&void 0!==W?W:"HTTP1.1";e.notifyLogsListeners({level:"info",protocol:Be,method:n.method,upstreamPath:re,downstreamPath:pe.href,randomId:ge,uniqueHash:Re}),xe instanceof Buffer||(xe=null);const qe=!xe&&(null==Ie?void 0:Ie.request(Ce,{endStream:e.config.ssl?!(null==be||be):!ye}));if("object"==typeof qe&&(null===(J=null==qe?void 0:qe.on)||void 0===J||J.call(qe,"error",(t=>{const n=-505===t.errno;xe=Buffer.from(B(t,e.mode,"stream"+(n?" (error -505 usually means that the downstream service does not support this http version)":""),oe,pe))}))),xe)return void G(502,r,xe);xe=null,be&&qe&&!fe?(n.stream.on("data",(e=>{qe.write(e)})),n.stream.on("end",(()=>qe.end()))):ye&&qe&&!fe?(n.on("data",(e=>{qe.write(e)})),n.on("end",(()=>qe.end()))):qe&&fe&&Oe&&!qe.writableEnded&&(qe.write(he),qe.end());const{outboundResponseHeaders:Ne}=yield new Promise((e=>{var t,n;return null!==(n=null===(t=null==qe?void 0:qe.on)||void 0===t?void 0:t.call(qe,"response",(t=>{e({outboundResponseHeaders:t})})))&&void 0!==n?n:e({outboundResponseHeaders:{}})}));let Te=null;try{Ne.location&&(Te=new i.URL(Ne.location.startsWith("/")?`${ae.origin}${Ne.location.replace(/^\/+/,"/")}`:Ne.location.replace(/^file:\/+/,"file:///").replace(/^(http)(s?):\/+/,"$1$2://")))}catch(t){yield e.log([[{text:`${g.ERROR_4} location replacement error ${(null!==(X=Ne.location)&&void 0!==X?X:"").slice(-13)}`,color:m.WARNING}]])}const je=e.config.replaceResponseBodyUrls&&Te?new i.URL(K(Te.href,{direction:h.INBOUND,proxyHostnameAndPort:ne,ssl:!!e.config.ssl,mapping:null!==(Z=e.config.mapping)&&void 0!==Z?Z:{}}).replace(new RegExp(`^(${L.join("|")})/+`),"")):Te,Pe=Te?(null==je?void 0:je.origin)!==Te.origin||e.config.dontTranslateLocationHeader?je:`${oe.origin}${je.href.substring(je.origin.length)}`:Te,Le=null!=xe?xe:yield new Promise((e=>{var t,n;let o=Buffer.alloc(0);qe?(null===(t=null==qe?void 0:qe.on)||void 0===t||t.call(qe,"data",(e=>o=Buffer.concat([o,"string"==typeof e?Buffer.from(e):e]))),null===(n=null==qe?void 0:qe.on)||void 0===n||n.call(qe,"end",(()=>{e(o)}))):e(o)})).then((t=>{var n,o;return e.config.replaceResponseBodyUrls&&t.length?L.some((e=>ae.protocol===e))?t:_(t,Ne,{proxyHostnameAndPort:ne,proxyHostname:te,key:se,direction:h.INBOUND,mapping:null!==(n=e.config.mapping)&&void 0!==n?n:{},port:null!==(o=e.config.port)&&void 0!==o?o:A.port,ssl:!!e.config.ssl}).catch((t=>(G(502,r,Buffer.from(B(t,e.mode,"stream",oe,pe))),Buffer.from("")))):t})),Ae=Object.assign(Object.assign({},Object.entries(Object.assign(Object.assign(Object.assign({},Ne),e.config.replaceResponseBodyUrls?{"content-length":`${Le.byteLength}`}:{}),e.config.disableWebSecurity?{"content-security-policy":"report only","access-control-allow-headers":"*","access-control-allow-method":"*","access-control-allow-origin":"*"}:{})).filter((([e])=>!e.startsWith(":")&&!D.includes(e.toLowerCase()))).reduce(((e,[t,n])=>{const o=de.split("").map(((e,t)=>de.substring(t).startsWith(".")&&de.substring(t))).filter((e=>e)),r=[de].concat(o).reduce(((e,t)=>(Array.isArray(e)?e:[e]).map((e=>"string"==typeof e?e.replace(`Domain=${t}`,`Domain=${oe.hostname}`):e))),n);return e[t]=(e[t]||[]).concat(r),e}),{})),Pe?{location:[Pe]}:{});try{Object.entries(Ae).forEach((([e,t])=>t&&r.setHeader(e,t)))}catch(e){}const He=null!==(Q=Ne[":status"])&&void 0!==Q?Q:200;try{e.config.ssl?r.writeHead(He,Ae):r.writeHead(He,"HTTP/2"===Be?"":null!==(ee=null===(V=Ne[":statusmessage"])||void 0===V?void 0:V.toString())&&void 0!==ee?ee:"",Ae)}catch(e){}Le?r.end(Le):r.end();const Ue=b(),Me=ke||we?Buffer.from(JSON.stringify({body:null==Le?void 0:Le.toString("base64"),headers:Ne,status:He})).toString("base64"):"";e.notifyLogsListeners({randomId:ge,statusCode:He,protocol:Be,duration:Math.floor(Number(Ue-Se)/1e6),uniqueHash:Re,response:Me}),!we||e.config.logAccessInTerminal||me||(e.mockConfig.mocks.set(Re,Me),u.stdout.moveCursor(0,-1,(()=>u.stdout.clearLine(-1,e.quickStatus))))}))};exports.serve=Z;const Q=(e,t)=>{"EACCES"===t.code&&setTimeout((()=>e.log([[{text:`${g.NO} permission denied for this port`,color:m.ERROR}]])),10),"EADDRINUSE"===t.code&&setTimeout((()=>e.log([[{text:`${g.ERROR_6} port is already used. NOT started`,color:m.ERROR}]])),10)};exports.errorListener=Q;const V=e=>ee({config:Object.assign(Object.assign({},A),e)},{server:null});exports.start=V;const ee=(e,n)=>t(void 0,void 0,void 0,(function*(){var s,i,l,d,c,u,p,h,v,b,O,w,R,E,S,B,q,N,T,j,P,L,A,U,M,D;if(0===Object.keys(null!=n?n:{}).length&&e.server)return n;if(null==n?void 0:n.pendingConfigSave)return(0,a.writeFile)(y,JSON.stringify(n.pendingConfigSave,null,2),(t=>{var n,o;t?null===(n=e.log)||void 0===n||n.call(e,[[{text:`${g.ERROR_4} config file NOT saved`,color:m.ERROR}]]):null===(o=e.log)||void 0===o||o.call(e,[[{text:`${g.COLORED} config file saved... will reload`,color:m.INFO}]])})),e;if(null===(null==n?void 0:n.configListeners)&&(yield Promise.all((null!==(s=e.configListeners)&&void 0!==s?s:[]).map((e=>new Promise((t=>e.stream.end(t))))))),null===(null==n?void 0:n.logsListeners)&&(yield Promise.all((null!==(i=e.configListeners)&&void 0!==i?i:[]).map((e=>new Promise((t=>e.stream.end(t))))))),null===(null==n?void 0:n.server)&&e.server){const t=yield Promise.race([new Promise((t=>{var n;return null===(n=e.server)||void 0===n?void 0:n.close(t)})).then((()=>!0)),new Promise((e=>setTimeout(e,5e3))).then((()=>!1))]);t||(yield null===(l=e.log)||void 0===l?void 0:l.call(e,[[{text:`${g.RESTART} error during restart (websockets ?)`,color:m.WARNING}]]))}(null!==(d=e.configListeners)&&void 0!==d?d:[]).concat(null!==(c=e.logsListeners)&&void 0!==c?c:[]).filter((e=>e.stream.errored||e.stream.closed)).forEach((e=>e.stream.destroy()));const W=null!==(u=null==n?void 0:n.config)&&void 0!==u?u:e.config,F=null!==(h=null!==(p=null==n?void 0:n.mode)&&void 0!==p?p:e.mode)&&void 0!==h?h:f.PROXY,J=null!==(w=null!==(b=null===(v=null==n?void 0:n.mockConfig)||void 0===v?void 0:v.autoRecord)&&void 0!==b?b:null===(O=e.mockConfig)||void 0===O?void 0:O.autoRecord)&&void 0!==w&&w,_=null!==(B=null!==(E=null===(R=null==n?void 0:n.mockConfig)||void 0===R?void 0:R.strict)&&void 0!==E?E:null===(S=e.mockConfig)||void 0===S?void 0:S.strict)&&void 0!==B&&B,K=null!==(j=null!==(N=null===(q=null==n?void 0:n.mockConfig)||void 0===q?void 0:q.mocks)&&void 0!==N?N:null===(T=e.mockConfig)||void 0===T?void 0:T.mocks)&&void 0!==j?j:new Map,z=(null===(null==n?void 0:n.configListeners)?[]:null!==(L=null!==(P=null==n?void 0:n.configListeners)&&void 0!==P?P:e.configListeners)&&void 0!==L?L:[]).filter((e=>!e.stream.errored&&!e.stream.closed)),G=(null===(null==n?void 0:n.logsListeners)?[]:null!==(U=null!==(A=null==n?void 0:n.logsListeners)&&void 0!==A?A:e.logsListeners)&&void 0!==U?U:[]).filter((e=>!e.stream.errored&&!e.stream.closed)),Y=e;return Object.assign(Y,{config:W,logsListeners:G,configListeners:z,mode:F,mockConfig:{mocks:K,strict:_,autoRecord:J},configFileWatcher:void 0===Y.configFileWatcher?(0,a.watchFile)(y,(()=>t(void 0,void 0,void 0,(function*(){return ee(Y,yield function(e){return t(this,void 0,void 0,(function*(){var t,n,o,r,s;const i=e.config,a=yield H(!1),l=[];if(!a)return{};if(isNaN(null!==(t=null==a?void 0:a.port)&&void 0!==t?t:NaN)||(null!==(n=null==a?void 0:a.port)&&void 0!==n?n:-1)>65535||(null!==(o=null==a?void 0:a.port)&&void 0!==o?o:-1)<0)return yield e.log([[{text:`${g.PORT} port number invalid. Not refreshing`,color:m.ERROR}]]),{};if((null===(r=null==a?void 0:a.mapping)||void 0===r?void 0:r[""])||l.push([{text:`${g.ERROR_3} default mapping "" not provided.`,color:m.WARNING}]),"object"!=typeof a.mapping)return e.log([[{text:`${g.ERROR_5} mapping should be an object. Aborting`,color:m.ERROR}]]),{};a.replaceRequestBodyUrls!==i.replaceRequestBodyUrls&&l.push([{text:`${g.REWRITE} request body url ${a.replaceRequestBodyUrls?"":"NO "}rewriting`,color:m.INFO}]),a.replaceResponseBodyUrls!==i.replaceResponseBodyUrls&&l.push([{text:`${g.REWRITE} response body url ${a.replaceResponseBodyUrls?"":"NO "}rewriting`,color:m.INFO}]),a.dontTranslateLocationHeader!==i.dontTranslateLocationHeader&&l.push([{text:`${g.REWRITE} response location header ${a.dontTranslateLocationHeader?"NO ":""}translation`,color:m.INFO}]),a.dontUseHttp2Downstream!==i.dontUseHttp2Downstream&&l.push([{text:`${g.OUTBOUND} http/2 ${a.dontUseHttp2Downstream?"de":""}activated downstream`,color:m.INFO}]),a.disableWebSecurity!==i.disableWebSecurity&&l.push([{text:`${g.SHIELD} web security ${a.disableWebSecurity?"de":""}activated`,color:m.INFO}]),a.websocket!==i.websocket&&l.push([{text:`${g.WEBSOCKET} websocket ${a.websocket?"":"de"}activated`,color:m.INFO}]),a.logAccessInTerminal!==i.logAccessInTerminal&&l.push([{text:`${g.LOGS} access terminal logging ${a.logAccessInTerminal?"on":"off"}`,color:m.INFO}]),a.simpleLogs!==i.simpleLogs&&l.push([{text:`${g.COLORED} simple logs ${a.simpleLogs?"on":"off"}`,color:m.INFO}]),Object.keys(a.mapping).join("\n")!==Object.keys(null!==(s=i.mapping)&&void 0!==s?s:{}).join("\n")&&l.push([{text:`${g.RULES} ${Object.keys(a.mapping).length.toString().padStart(5)} loaded mapping rules`,color:m.INFO}]),a.port!==i.port&&l.push([{text:`${g.PORT} port changed from ${i.port} to ${a.port}`,color:m.INFO}]),a.ssl&&!i.ssl&&l.push([{text:`${g.INBOUND} ssl configuration added`,color:m.INFO}]),!a.ssl&&i.ssl&&l.push([{text:`${g.INBOUND} ssl configuration removed`,color:m.INFO}]);const d=a.port!==i.port||JSON.stringify(a.ssl)!==JSON.stringify(i.ssl);return d&&l.push([{text:`${g.RESTART} restarting server`,color:m.INFO}]),setTimeout((()=>null==e?void 0:e.log(l.concat([C.apply(Object.assign(Object.assign({},e),{config:a}))]))),1),{config:a,server:d?null:void 0}}))}(Y))})))):Y.configFileWatcher,log:k.bind(Y,Y),notifyConfigListeners:$.bind(Y),notifyLogsListeners:x.bind(Y),buildQuickStatus:C.bind(Y),quickStatus:I.bind(Y),server:null!==(null==n?void 0:n.server)||(null!==(D=null===(M=null==n?void 0:n.config)||void 0===M?void 0:M.port)&&void 0!==D?D:0)<0?(null==n?void 0:n.server)?Y.server:null:((null==W?void 0:W.ssl)?o.createSecureServer.bind(null,Object.assign(Object.assign({},W.ssl),{allowHTTP1:!0})):r.createServer)(((e,t)=>Z(Y,e,t))).addListener("error",(e=>Q(Y,e))).on("upgrade",((e,t)=>ee(Y,X(Y,e,t)))).listen(null==W?void 0:W.port)}),Y}));exports.update=ee;const te=null!==(e=u.argv.map((e=>e.trim())).filter((e=>e&&!["ts-node","node","npx","npm","exec"].some((t=>e.includes(t)&&!e.match(/npm-cache/)&&!e.match(/_npx/)))))[0])&&void 0!==e?e:"",ne=te.toLowerCase().replace(/[-_]/g,"").includes("localtraffic")&&!te.match(/(.|-)?(test|spec)\.m?[jt]sx?$/),oe=u.argv.some((e=>"--crash-test"===e));if(oe){const e=Math.floor(40151+9e3*Math.random()),t=(t,n)=>(0,r.request)({hostname:"localhost",port:e,path:"/config/",method:"GET",headers:{Accept:"text/html"},timeout:500},(e=>n({response:e,state:t}))).on("error",(e=>n({error:e,state:t}))).end();ee({config:Object.assign(Object.assign({},A),{port:e}),configFileWatcher:null},{server:null}).then((e=>new Promise((n=>setTimeout(t.bind(null,e,n),1e3))))).then((({state:e,response:t})=>200!==t.statusCode?Promise.reject("Crash test has failed"):ee(e,{config:{port:-1},server:null}))).then((e=>new Promise((n=>setTimeout(t.bind(null,e,n),1e3))))).then((({error:e})=>"ECONNREFUSED"!==(null==e?void 0:e.code)?Promise.reject("Server should have stopped"):k({config:{simpleLogs:!0}},[[{text:`${g.COLORED} Crash test successful`,color:m.INFO}]]))).then((()=>(0,u.exit)(0))).catch((()=>(0,u.exit)(1)))}!oe&&ne&&H().then(V).then((e=>e.quickStatus()));
2
+ "use strict";var e,t=this&&this.__awaiter||function(e,t,n,o){return new(n||(n=Promise))((function(r,s){function i(e){try{l(o.next(e))}catch(e){s(e)}}function a(e){try{l(o.throw(e))}catch(e){s(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,a)}l((o=o.apply(e,t||[])).next())}))},n=this&&this.__rest||function(e,t){var n={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&t.indexOf(o)<0&&(n[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(o=Object.getOwnPropertySymbols(e);r<o.length;r++)t.indexOf(o[r])<0&&Object.prototype.propertyIsEnumerable.call(e,o[r])&&(n[o[r]]=e[o[r]])}return n};Object.defineProperty(exports,"__esModule",{value:!0}),exports.update=exports.serve=exports.determineMapping=exports.send=exports.cleanEntropy=exports.replaceTextUsingMapping=exports.replaceBody=exports.acknowledgeWebsocket=exports.readWebsocketBuffer=exports.createWebsocketBufferFrom=exports.websocketServe=exports.recorderHandler=exports.quickStatus=exports.errorListener=exports.load=exports.start=void 0;const o=require("http2"),r=require("http"),s=require("https"),i=require("url"),a=require("fs"),l=require("zlib"),d=require("path"),c=require("crypto"),u=require("process"),p=require("os");var m,g,h,f;!function(e){e[e.ERROR=124]="ERROR",e[e.INFO=93]="INFO",e[e.WARNING=172]="WARNING"}(m||(m={})),function(e){e.INBOUND="↘️ ",e.PORT="☎️ ",e.OUTBOUND="↗️ ",e.RULES="🔗",e.MOCKS="🌐",e.STRICT_MOCKS="🕸️",e.AUTO_RECORD="📼",e.REWRITE="✒️ ",e.LOGS="📝",e.RESTART="🔄",e.WEBSOCKET="☄️ ",e.COLORED="✨",e.SHIELD="🛡️ ",e.NO="⛔",e.ERROR_1="❌",e.ERROR_2="⛈️ ",e.ERROR_3="☢️ ",e.ERROR_4="⁉️ ",e.ERROR_5="⚡",e.ERROR_6="☠️ "}(g||(g={})),function(e){e.INBOUND="INBOUND",e.OUTBOUND="OUTBOUND"}(h||(h={})),function(e){e.PROXY="proxy",e.MOCK="mock"}(f||(f={}));const v=(0,d.resolve)((0,p.homedir)(),".local-traffic.json"),y=(0,d.resolve)((0,u.cwd)(),u.argv.slice(-1)[0].endsWith(".json")?u.argv.slice(-1)[0]:v),b=()=>{var e,t;return null!==(t=null===(e=u.hrtime.bigint)||void 0===e?void 0:e.call(u.hrtime))&&void 0!==t?t:(()=>{const e=(0,u.hrtime)();return 1e3*e[0]+e[1]/1e6})()},O=e=>{const t=new Date;return`${e?"":""}${`${t.getHours()}`.padStart(2,"0")}${e?":":":"}${`${t.getMinutes()}`.padStart(2,"0")}${e?":":":"}${`${t.getSeconds()}`.padStart(2,"0")}${e?"":""}`},k=function(e,n){return t(this,void 0,void 0,(function*(){var t,o,r,s,i,a,l;const d=n.map((e=>e.map((e=>e.text.replace(/⎸/g,"|").replace(/⎹/g,"|").replace(/\u001b\[[^m]*m/g,"").replace(new RegExp(g.INBOUND,"g"),"inbound:").replace(new RegExp(g.PORT,"g"),"port:").replace(new RegExp(g.OUTBOUND,"g"),"outbound:").replace(new RegExp(g.RULES,"g"),"rules:").replace(new RegExp(g.NO,"g"),"").replace(new RegExp(g.REWRITE,"g"),"+rewrite").replace(new RegExp(g.WEBSOCKET,"g"),"websocket").replace(new RegExp(g.SHIELD,"g"),"web-security").replace(new RegExp(g.MOCKS,"g"),"mocks").replace(new RegExp(g.STRICT_MOCKS,"g"),"mocks (strict)").replace(new RegExp(g.AUTO_RECORD,"g"),"auto record").replace(new RegExp(g.LOGS,"g"),"logs").replace(new RegExp(g.RESTART,"g"),"restart").replace(new RegExp(g.COLORED,"g"),"colored").replace(/\|+/g,"|"))).join(" | ")));if(null===(t=null==e?void 0:e.config)||void 0===t?void 0:t.simpleLogs)for(let t of d)console.log(`${O(null===(o=null==e?void 0:e.config)||void 0===o?void 0:o.simpleLogs)} | ${t}`);else for(let t of n){const n=t.map((e=>`[48;5;${e.color}m${e.text}`));console.log(`${O(null===(r=null==e?void 0:e.config)||void 0===r?void 0:r.simpleLogs)}${t.map((e=>{var t;return`[48;5;${e.color}m${"".padEnd((null!==(t=e.length)&&void 0!==t?t:64)+1)}`})).join("▐")}`),yield new Promise((e=>u.stdout.moveCursor(-1e3,-1,(()=>e(void 0)))));let o=9;for(let e=0;e<n.length;e++)yield new Promise((e=>u.stdout.moveCursor(-1e3,0,(()=>u.stdout.moveCursor(o,0,(()=>e(void 0))))))),u.stdout.write(n[e]),o+=(null!==(s=t[e].length)&&void 0!==s?s:64)+2;console.log("");for(let n of d)null===(i=null==e?void 0:e.notifyLogsListeners)||void 0===i||i.call(e,{event:n,level:(c=null!==(l=null===(a=null==t?void 0:t[0])||void 0===a?void 0:a.color)&&void 0!==l?l:m.INFO,c===m.ERROR?"error":c===m.WARNING?"warning":"info")})}var c}))},w=(e,t)=>{var n;const o=Array(4).fill(0).map((()=>t?Math.floor(256*Math.random()):0)),r=e.split("").map(((e,t)=>e.charCodeAt(0)^o[3&t])),s=e.length,i=t?128:0,a=e.length<126?Buffer.from(Uint8Array.from([129,i+s]).buffer):e.length<65535?Buffer.concat([Buffer.from(Uint8Array.from([129,126|i]).buffer),Buffer.from(Uint8Array.from([s>>8]).buffer),Buffer.from(Uint8Array.from([255&s]).buffer)]):Buffer.concat([Buffer.from(Uint8Array.from([129,127|i]).buffer),Buffer.concat((null!==(n=Number(s).toString(16).padStart(16,"0").match(/.{2}/g))&&void 0!==n?n:["0"]).map((e=>parseInt(e,16))).map((e=>Buffer.from(Uint8Array.from([e]).buffer))))]),l=Buffer.from(Int8Array.from(o).buffer),d=Buffer.from(Int8Array.from(r).buffer);return Buffer.concat(t?[a,l,d]:[a,d])};exports.createWebsocketBufferFrom=w;const R=(e,t)=>{var n;if(!(t||1&e.readUInt8(0)))return{payloadLength:0,mask:[0,0,0,0],body:""};const o=t?0:e.readUInt8(1),r=o>>7,s=127&o,i=t?t.payloadLength:127!==s?s:e.readUInt8(2)<<8+e.readUInt8(3),a=t?t.mask:r?Array(4).fill(0).map(((t,n)=>e.readUInt8(n+4))):[0,0,0,0],l=t?0:r?8:4,d=Array(e.length-l).fill(0).map(((t,n)=>String.fromCharCode(e.readUInt8(n+l)^a[3&n]))).join("");return{payloadLength:i,mask:a,body:(null!==(n=null==t?void 0:t.body)&&void 0!==n?n:"").concat(d)}};exports.readWebsocketBuffer=R;const x=(e,t)=>{const n=(0,c.createHash)("sha1");n.update(t+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11");const o=n.digest("base64");e.allowHalfOpen=!0,e.write(`HTTP/1.1 101 Switching Protocols\r\ndate: ${(new Date).toUTCString()}\r\nconnection: upgrade\r\nupgrade: websocket\r\nserver: local\r\nsec-websocket-accept: ${o}\r\n\r\n`)};exports.acknowledgeWebsocket=x;const E=function(e){return S(e,this.configListeners)},$=function(e){const{response:t}=e,o=n(e,["response"]);return Promise.all([S(e,this.logsListeners.filter((e=>e.wantsResponseMessage))),S(o,this.logsListeners.filter((e=>!e.wantsResponseMessage)))])},S=(e,t)=>{if(!t.length)return;const n=JSON.stringify(e),o=new Set(t.map((e=>e.wantsMask))),r=o.has(!1)&&w(n,!1),s=o.has(!0)&&w(n,!0),i=e=>{e.stream.errored&&e.stream.destroy()};t.forEach((e=>{e.stream.closed||e.stream.errored||(e.wantsMask?e.stream.write(s,"ascii",(()=>i(e))):e.stream.write(r,"ascii",(()=>i(e))))}))},C=function(){var e,t;return[{color:52,text:`${g.PORT} ${(null!==(e=this.config.port)&&void 0!==e?e:"").toString()}`,length:11},{color:53,text:`${g.OUTBOUND} ${this.config.dontUseHttp2Downstream?"H1.1":"H/2 "}${this.config.replaceRequestBodyUrls?g.REWRITE:" "}`,length:11},{color:54,text:`${g.INBOUND} ${this.config.ssl?"H/2 ":"H1.1"}${this.config.replaceResponseBodyUrls?g.REWRITE:" "}`,length:11},{color:55,text:""+(this.mode===f.PROXY&&this.mockConfig.autoRecord?`${g.AUTO_RECORD}${this.mockConfig.mocks.size.toString().padStart(3)}`:this.mode===f.PROXY?`${g.RULES}${Object.keys(null!==(t=this.config.mapping)&&void 0!==t?t:{}).length.toString().padStart(3)}`:`${this.mockConfig.strict?g.STRICT_MOCKS:g.MOCKS}${this.mockConfig.mocks.size.toString().padStart(3)}`),length:7},{color:56,text:`${this.config.websocket?g.WEBSOCKET:g.NO}`,length:4},{color:57,text:`${this.config.simpleLogs?g.NO:g.COLORED}`,length:4},{color:93,text:`${this.config.disableWebSecurity?g.NO:g.SHIELD}`,length:4}]},I=function(){return t(this,void 0,void 0,(function*(){this.log([this.buildQuickStatus()]),this.notifyConfigListeners(this.config)}))};exports.quickStatus=I;const B=(e,t,n,o,r)=>`${W(128163,"error",e.message)}\n<p>An error happened while trying to proxy a remote exchange</p>\n<div class="alert alert-warning" role="alert">\n&#x24D8;&nbsp;This is not an error from the downstream service.\n</div>\n<div class="alert alert-danger" role="alert">\n<pre><code>${e.stack||`<i>${e.name} : ${e.message}</i>`}${e.errno?`<br/>(code : ${e.errno})`:""}</code></pre>\n</div>\nMore information about the request :\n<table class="table">\n<tbody>\n<tr>\n<td>server mode</td>\n<td>${t}</td>\n</tr>\n<tr>\n<td>phase</td>\n<td>${n}</td>\n</tr>\n<tr>\n<td>requested URL</td>\n<td>${o}</td>\n</tr>\n<tr>\n<td>downstream URL</td>\n<td>${r||"&lt;no-target-url&gt;"}</td>\n</tr>\n</tbody>\n</table>\n</div></body></html>`,q=(e,t,n)=>`<table id="table-access" class="table table-striped" style="display: block; width: 100%; overflow-y: auto">\n<thead>\n<tr>\n<th scope="col"${!0===n.captureResponseBody?' style="min-width: 120px"':""}>...</th>\n<th scope="col">Date</th>\n<th scope="col">Level</th>\n<th scope="col">Protocol</th>\n<th scope="col">Method</th>\n<th scope="col">Status</th>\n<th scope="col">Duration</th>\n<th scope="col">Upstream Path</th>\n<th scope="col">Downstream Path</th>\n</tr>\n</thead>\n<tbody id="access">\n</tbody>\n</table>\n<table id="table-proxy" class="table table-striped" style="display: none; width: 100%; overflow-y: auto">\n<thead>\n<tr>\n<th scope="col">Date</th>\n<th scope="col">Level</th>\n<th scope="col">Message</th>\n</tr>\n</thead>\n<tbody id="proxy">\n</tbody>\n</table>\n<script type="text/javascript">\nfunction start() {\ndocument.getElementById('table-access').style.height =\n(document.documentElement.clientHeight - 150) + 'px';\nconst socket = new WebSocket("ws${t.ssl?"s":""}://${e}/local-traffic-logs${n.captureResponseBody?"?wantsResponseMessage=true":""}");\nsocket.onmessage = function(event) {\nlet data = event.data\nlet uniqueHash;\ntry {\nconst { uniqueHash: uniqueHash1, ...data1 } = JSON.parse(event.data);\ndata = data1;\nuniqueHash = uniqueHash1;\n} catch(e) { }\nif (document.getElementById('mock-mode')?.checked) return;\nif (${!0===n.captureResponseBody} && \ndata?.downstreamPath?.startsWith('recorder://') &&\n!data?.upstreamPath?.endsWith('?forceLogInRecorderPage=true'))\nreturn;\nconst time = new Date().toISOString().split('T')[1].replace('Z', '');\nconst actions = getActionsHtmlText(uniqueHash, data.response);\nif(data.statusCode && uniqueHash) {\nconst color = getColorFromStatusCode(data.statusCode);\nconst statusCodeColumn = document.querySelector("#event-" + data.randomId + " .statusCode");\nif (statusCodeColumn)\nstatusCodeColumn.innerHTML = '<span class="badge bg-' + color + '">' + data.statusCode + '</span>';\n\nconst durationColumn = document.querySelector("#event-" + data.randomId + " .duration");\nif (durationColumn) {\nconst duration = data.duration > 10000 ? Math.floor(data.duration / 1000) + 's' :\ndata.duration + 'ms';\ndurationColumn.innerHTML = duration;\n}\n\nconst protocolColumn = document.querySelector("#event-" + data.randomId + " .protocol");\nif (protocolColumn) {\nprotocolColumn.innerHTML = data.protocol;\n}\n\nconst replayColumn = document.querySelector("#event-" + data.randomId + " .replay");\nif (replayColumn) {\nreplayColumn.innerHTML = actions;\n}\n} else if (uniqueHash) {\naddNewRequest(data.randomId, actions, time, data.level, data.protocol, data.method, \n'<span class="badge bg-secondary">...</span>', '&#x23F1;',\ndata.upstreamPath, data.downstreamPath);\n} else if(data.event) {\ndocument.getElementById("proxy")\n.insertAdjacentHTML('afterbegin', '<tr><td scope="col">' + time + '</td>' +\n'<td scope="col">' + (data.level || 'info')+ '</td>' + \n'<td scope="col">' + data.event + '</td></tr>');\n}\ncleanup();\n};\nsocket.onerror = function(error) {\nconsole.log(\`[error] \${JSON.stringify(error)}\`);\nsetTimeout(start, 5000);\n};\n};\nfunction show(id) {\n[...document.querySelectorAll('table')].forEach((table, index) => {\ntable.style.display = index === id ? 'block': 'none'\n});\n[...document.querySelectorAll('.navbar-nav .nav-item .nav-link')].forEach((link, index) => {\nif (index === id) { link.classList.add('active') } else link.classList.remove('active');\n});\n}\nfunction remove(event) {\nevent.target.closest('tr').remove();\nif (window.updateState) window.updateState();\n}\nfunction cleanup() {\nconst currentLimit = parseInt(document.getElementById('limit').value)\nfor (let table of ['access', 'proxy']) {\nwhile (currentLimit && document.getElementById(table).childNodes.length && \ndocument.getElementById(table).childNodes.length > currentLimit) {\n[...document.getElementById(table).childNodes].slice(-1)[0].remove();\n}\n}\n}\nfunction replay(event) {\nconst uniqueHash = event.target.dataset.uniquehash;\nconst { method, url, headers, body } = JSON.parse(atob(uniqueHash));\nfetch(url, {\nmethod,\nheaders,\nbody: !body || !body.length ? undefined : atob(body)\n});\n}\nfunction getActionsHtmlText(uniqueHash, response) {\nconst edit = ${!0===n.captureResponseBody} && uniqueHash\n? '<button data-response="' + (response ?? "") +\n'" data-uniquehash="' + uniqueHash + \n'" data-bs-toggle="modal" data-bs-target="#edit-request" type="button" ' +\n'class="btn btn-primary">&#x1F4DD;</button>'\n: ''\nconst remove = ${!0===n.captureResponseBody} && uniqueHash\n? '<button onclick="javascript:remove(event)" type="button" ' +\n'class="btn btn-primary">&#x274C;</button>'\n: ''\nconst replay = ${!1===n.captureResponseBody} && uniqueHash ? '<button data-response="' + \nbtoa(JSON.stringify(response ?? {})) +\n'" data-uniquehash="' + uniqueHash + '" onclick="javascript:replay(event)" ' +\n'type="button" class="btn btn-primary">&#x1F501;</button>' : '';\nreturn edit + replay + remove\n}\nfunction addNewRequest(\nrandomId, actions, time, level, protocol, method, \nstatusCode, duration, upstreamPath, downstreamPath\n) {\ndocument.getElementById("access")\n.insertAdjacentHTML('afterbegin', '<tr id="event-' + randomId + '">' +\n'<td scope="col" class="replay">' + actions + '</td>' +\n'<td scope="col">' + time + '</td>' +\n'<td scope="col">' + (level || 'info')+ '</td>' + \n'<td scope="col" class="protocol">' + protocol + '</td>' + \n'<td scope="col" class="method">' + method + '</td>' + \n'<td scope="col" class="statusCode">' + statusCode + '</td>' +\n'<td scope="col" class="duration text-end">' + duration + '</td>' +\n'<td scope="col" class="upstream-path">' + upstreamPath + '</td>' + \n'<td scope="col">' + downstreamPath + '</td>' + \n'</tr>');\n}\nfunction getColorFromStatusCode(statusCode) {\nreturn Math.floor(statusCode / 100) === 1 ? "info" :\nMath.floor(statusCode / 100) === 2 ? "success" :\nMath.floor(statusCode / 100) === 3 ? "dark" :\nMath.floor(statusCode / 100) === 4 ? "warning" :\nMath.floor(statusCode / 100) === 5 ? "danger" :\n"secondary";\n}\nwindow.addEventListener("DOMContentLoaded", start);\n<\/script>`,N=(e,t,n)=>{let o={};try{o=JSON.parse(t.toString("ascii"))}catch(e){}if("object"!=typeof o||Object.keys(o).filter((e=>!["strict","mode","mocks","autoRecord"].includes(e))).length||!Array.isArray(o.mocks)&&void 0!==o.mocks)return void e.log([[{text:`${g.MOCKS} invalid mocks update received`,color:m.WARNING}]]);const{mocks:r,mode:s,strict:i,autoRecord:a}=o,l=r?new Map(r.map((({response:t,uniqueHash:n})=>[z(e.config,n),t]))):null,d=s!==e.mode&&s===f.PROXY,c=(!d||!0===a)&&(null!=a?a:e.mockConfig.autoRecord),u=void 0!==c&&c!=e.mockConfig.autoRecord,p=s!==e.mode&&s===f.MOCK||null!==l&&e.mockConfig.mocks.size!==l.size,h=null!=i?i:e.mockConfig.strict,v=null!=s?s:e.mode,y=!!h!=!!e.mockConfig.strict,b=n;ee(e,b?{mode:v,mockConfig:{autoRecord:!1,strict:h,mocks:new Map}}:{mode:v,mockConfig:{strict:h,autoRecord:c,mocks:null!=l?l:e.mockConfig.mocks}}),setTimeout((()=>{var t;return e.log([d?[{text:`${g.RULES} ${Object.keys(null!==(t=e.config.mapping)&&void 0!==t?t:{}).length.toString().padStart(5)} loaded mapping rules`,color:m.INFO}]:null,p?[{text:`${h?g.STRICT_MOCKS:g.MOCKS} ${(null!=l?l:e.mockConfig.mocks).size.toString().padStart(5)} loaded mocks`,color:m.INFO}]:null,y?[{text:`${h?g.STRICT_MOCKS:g.MOCKS} mocks strict mode : ${null!=h?h:e.mockConfig.strict}`,color:m.INFO}]:null,u?[{text:`${v===f.PROXY?g.AUTO_RECORD:h?g.STRICT_MOCKS:g.MOCKS} mocks auto-record : ${c}`,color:m.INFO}]:null,d||p||u||y||b?e.buildQuickStatus():null].filter((e=>e)))}),1)};exports.recorderHandler=N;const T=(e,n,o,i,a,l,d,c,u)=>t(void 0,void 0,void 0,(function*(){const t={hostname:e.hostname,path:i,port:e.port?e.port:"https:"===e.protocol?443:80,protocol:e.protocol,rejectUnauthorized:!1,method:a.method,headers:Object.assign(Object.assign({},Object.assign({},...Object.entries(l).filter((([e])=>!e.startsWith(":")&&"transfer-encoding"!==e.toLowerCase())).map((([e,t])=>({[e]:t}))))),{host:e.hostname})};let p=null;const m=p||[...L].includes(e.protocol)?null:yield new Promise((i=>{const l="https:"===e.protocol?(0,s.request)(t,i):(0,r.request)(t,i);l.on("error",(e=>{p=Buffer.from(B(e,u,"request",n,o)),i(null)})),c&&(l.write(d),l.end()),c||(a.on("data",(e=>l.write(e))),a.on("end",(()=>l.end())))}));if(p)throw p;return{alpnProtocol:"HTTP1.1",error:null,data:null,hasRun:!1,events:{},on:function(e,t){return"response"===e?null==t?void 0:t(Object.assign(Object.assign({},m.headers),{":status":m.statusCode,":statusmessage":m.statusMessage})):m.on(e,t)},end:function(){return this},request:function(){return this},write:function(){return this}}})),j={logs:(e,t)=>J(`${W(128250,"logs","")}\n<nav class="navbar navbar-expand-lg navbar-dark bg-primary nav-fill">\n<div class="container-fluid">\n<ul class="navbar-nav">\n<li class="nav-item">\n<a class="nav-link active" aria-current="page" href="javascript:show(0)">Access</a>\n</li>\n<li class="nav-item">\n<a class="nav-link" href="javascript:show(1)">Proxy</a>\n</li>\n</ul>\n<span class="navbar-text">\nLimit : <select id="limit" onchange="javascript:cleanup()"><option value="-1">0 (clear)</option><option value="10">10</option>\n<option value="50">50</option><option value="100">100</option><option value="200">200</option>\n<option selected="selected" value="500">500</option><option value="0">Infinity (discouraged)</option>\n</select> rows\n</span>\n</div>\n</nav>\n${q(e,t.config,{captureResponseBody:!1})}\n</body></html>`),config:(e,t)=>J(`${W(127899,"config","")}\n<link href="${M}jsoneditor/dist/jsoneditor.min.css" rel="stylesheet" type="text/css">\n<script src="${M}jsoneditor/dist/jsoneditor.min.js"><\/script>\n<script src="${M}node-forge/dist/forge.min.js"><\/script>\n<div id="ssl-modal" class="modal" tabindex="-1" role="dialog">\n<div class="modal-dialog" role="document">\n<div class="modal-content">\n<div class="modal-header">\n<h5 class="modal-title">SSL keypair generation in progress</h5>\n</div>\n<div class="modal-body">\n<p>Wait a few seconds or move your mouse to increase the entropy.</p>\n</div>\n</div>\n</div>\n</div>\n<div id="jsoneditor" style="width: 400px; height: 400px;"></div>\n<script>\n// create the editor\nconst container = document.getElementById("jsoneditor")\nconst options = {mode: "code", allowSchemaSuggestions: true, schema: {\ntype: "object",\nproperties: {\n${Object.entries(Object.assign(Object.assign({},A),{ssl:{cert:"",key:""}})).map((([e,t])=>`${e}: {type: ${"unwantedHeaderNamesInMocks"===e?'"array","items": {"type":"string"}':"number"==typeof t?'"integer"':"string"==typeof t?'"string"':"boolean"==typeof t?'"boolean"':'"object"'}}`)).join(",\n ")}\n},\nrequired: [],\nadditionalProperties: false\n}}\n\nfunction save() {\nsocket.send(JSON.stringify(editor.get()));\n}\n\nfunction generateSslCertificate() {\nconst sslModal = new bootstrap.Modal(document.getElementById('ssl-modal'), {});\nsslModal.show()\nsetTimeout(function() {\nconst keypair = forge.pki.rsa.generateKeyPair(2048);\nconst certificate = forge.pki.createCertificate();\nconst now = new Date();\nconst fiveYears = new Date(new Date(now).setFullYear(now.getFullYear() + 5));\nObject.assign(certificate, {\npublicKey: keypair.publicKey,\nserialNumber: "01",\nvalidity: {\nnotBefore: now,\nnotAfter: fiveYears,\n},\n});\ncertificate.sign(keypair.privateKey, forge.md.sha256.create());\nconst key = forge.pki.privateKeyToPem(keypair.privateKey);\nconst cert = forge.pki.certificateToPem(certificate);\nconst existingConfig = editor.get();\neditor.set({ ...existingConfig, ssl: { key, cert },\nport: parseInt(("" + existingConfig.port).replace(/(80|[0-9])80$/, '443'))\n});\nsslModal.hide();\n}, 100);\n}\n\nconst editor = new JSONEditor(container, options);\nlet socket;\nconst initialJson = ${JSON.stringify(t.config)}\neditor.set(initialJson)\neditor.validate();\neditor.aceEditor.commands.addCommand({\nname: 'save',\nbindKey: {win: 'Ctrl-S', mac: 'Command-S'},\nexec: save,\n});\n\nwindow.addEventListener("DOMContentLoaded", function() {\ndocument.getElementById('jsoneditor').style.height =\n(document.documentElement.clientHeight - 150) + 'px';\ndocument.getElementById('jsoneditor').style.width =\nparseInt(window.getComputedStyle(\ndocument.querySelector('.container')).maxWidth) + 'px';\nconst sslButton = document.createElement('button');\nsslButton.addEventListener("click", generateSslCertificate);\nsslButton.type="button";\nsslButton.classList.add("btn");\nsslButton.classList.add("btn-primary");\nsslButton.innerHTML="&#x1F512;";\ndocument.querySelector('.jsoneditor-menu')\n.appendChild(sslButton);\nconst saveButton = document.createElement('button');\nsaveButton.addEventListener("click", save);\nsaveButton.type="button";\nsaveButton.classList.add("btn");\nsaveButton.classList.add("btn-primary");\nsaveButton.innerHTML="&#x1F4BE;";\ndocument.querySelector('.jsoneditor-menu')\n.appendChild(saveButton);\nsocket = new WebSocket("ws${t.config.ssl?"s":""}://${e}/local-traffic-config");\nsocket.onmessage = function(event) {\neditor.set(JSON.parse(event.data))\neditor.validate()\n}\n});\n<\/script>\n</body></html>`),recorder:(e,t,n)=>{var o,r,s,i,a,l,d,c,u,p;return(null===(o=n.url)||void 0===o?void 0:o.endsWith("?forceLogInRecorderPage=true"))?J('{"ping":"pong"}',{contentType:"application/json; charset=utf-8"}):"GET"===n.method&&(null===(s=null===(r=n.headers)||void 0===r?void 0:r.accept)||void 0===s?void 0:s.includes("application/json"))?J(JSON.stringify(Object.assign(Object.assign({},t.mockConfig),{mode:t.mode,mocks:[...t.mockConfig.mocks.entries()].map((([e,t])=>({uniqueHash:e,response:t})))})),{contentType:"application/json; charset=utf-8"}):["PUT","POST","DELETE"].includes(null!==(i=n.method)&&void 0!==i?i:"")?J('{"status": "acknowledged"}',{contentType:"application/json; charset=utf-8",onOutboundWrite:e=>N(t,e,"DELETE"===n.method)}):J(`${W(9210,"recorder","")}\n<link href="${M}jsoneditor/dist/jsoneditor.min.css" rel="stylesheet" type="text/css">\n<script src="${M}jsoneditor/dist/jsoneditor.min.js"><\/script>\n<script src="${M}pako/dist/pako.min.js"><\/script>\n<form>\n<div id="commands"${t.mockConfig.autoRecord?' style="filter:blur(8px)"':""}>\n<span>Mode : </span>\n<div class="btn-group" role="group" aria-label="Server Mode">\n<input type="radio" class="btn-check" name="server-mode" id="record-mode" autocomplete="off"${t.mode===f.PROXY?" checked":""}>\n<label class="btn btn-outline-primary" for="record-mode">&#9210; Record</label>\n<input type="radio" class="btn-check" name="server-mode" id="mock-mode" autocomplete="off"${t.mode===f.MOCK?" checked":""}>\n<label class="btn btn-outline-primary" for="mock-mode">&#x1F310; Mock</label>\n</div>\n<span>Actions : </span>\n<button type="button" class="btn btn-light" id="add-mock">&#x2795; Mock from dummy request</button>\n<button type="button" class="btn btn-light" id="upload-mocks">&#x1F4E5; Upload mocks</button>\n<button type="button" class="btn btn-light" id="download-mocks">&#x1F4E6; Download mocks</button>\n<button type="button" class="btn btn-light" id="delete-mocks">&#x1F5D1; Delete mocks</button>\n</div>\n<div class="row">\n<div class="col-lg" style="max-width: 200px">\n<div class="form-check form-switch" id="strict-mock-mode-form-control">\n<input class="form-check-input" type="checkbox" id="strict-mock-mode"${t.mockConfig.strict?' checked="checked"':""}>\n<label class="form-check-label" for="strict-mock-mode">Strict mock mode</label>\n</div>\n</div>\n<div class="col-lg" style="max-width: 200px">\n<div class="form-check form-switch">\n<input class="form-check-input" type="checkbox" id="auto-record-mode"${t.mockConfig.autoRecord?' checked="checked"':""}>\n<label class="form-check-label" for="auto-record-mode">Auto record mode</label>\n</div>\n</div>\n<div class="col-lg">&nbsp;</div>\n</div>\n<input type="hidden" id="limit" value="0"/>\n<div class="modal fade" id="edit-request" tabindex="-1" \naria-labelledby="edit-request-label" aria-hidden="true">\n<div class="modal-dialog" style="max-width: 900px">\n<div class="modal-content">\n<div class="modal-header">\n<h1 class="modal-title fs-5" id="edit-request-label">Edit request to /</h1>\n<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>\n</div>\n<div class="modal-body">\n<div class="container">\n<div class="row">\n<div class="col-lg">\n<h2>Request :</h2>\n<div id="uniqueHash-editor" style="width: 400px; height: 400px;"></div>\n</div>\n<div class="col-lg">\n<h2>Response : </h2>\n<div id="response-editor" style="width: 400px; height: 400px;"></div>\n</div>\n</div>\n</div>\n</div>\n<div class="modal-footer">\n<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>\n<button type="button" class="btn btn-primary" onclick="javascript:saveRequest()">Save changes</button>\n</div>\n</div>\n</div>\n</div>\n<script>\nconst xmlOrJsonPrologsInBase64 = [\n"eyJ","PD94bWw=","PCFET0NUWVBF","PCFkb2N0eXBl","PGh0bWw","PEhUTUw","H4sIAAAAAAAA", "W3tc"\n];\nfunction getMocksData () {\nreturn JSON.stringify(\n[...document.querySelectorAll('button[data-uniqueHash]')].map(button => ({\nresponse: button.attributes['data-response']?.value,\nuniqueHash: button.attributes['data-uniqueHash']?.value}))\n)\n}\nfunction updateState () {\nfetch("http${t.config.ssl?"s":""}://${e}${null!==(d=null===(l=Object.entries(null!==(a=t.config.mapping)&&void 0!==a?a:{}).find((([e,t])=>{var n;return null===(n=null==t?void 0:t.toString())||void 0===n?void 0:n.startsWith("recorder:")})))||void 0===l?void 0:l[0])&&void 0!==d?d:"/recorder/"}", {\nmethod: 'PUT',\nheaders: { 'Content-Type': 'application/json' },\nbody: '{"strict":' + document.getElementById('strict-mock-mode').checked +\n',"autoRecord":' + document.getElementById('auto-record-mode').checked +\n',"mode":"' + \n(document.getElementById('mock-mode').checked ? "mock" : "proxy") + '"' +\n',"mocks":' + getMocksData() + '}'\n})\n}\nfunction loadMocks(mocksHashes) {\nconst time = new Date().toISOString().split('T')[1].replace('Z', '');\nlet mocks = [];\ntry {\nmocks = mocksHashes.map(mock => ({...mock, \nrequest: JSON.parse(atob(mock.uniqueHash)),\nresponse: JSON.parse(atob(mock.response))\n}));\n} catch(e) { }\nmocks.forEach(mock => {\nconst randomId = window.crypto.randomUUID();\nconst actions = getActionsHtmlText(mock.uniqueHash, mock.response);\naddNewRequest(randomId, actions, time, 'info', 'HTTP/2', mock.request.method, \n'<span class="badge bg-' + \ngetColorFromStatusCode(mock.response.status) + '">' + \nmock.response.status + \n'</span>', \n'0ms', mock.request.url, \n'N/A');\n});\n}\ndocument.getElementById('add-mock').addEventListener('click', () => {\nconst iframe = document.createElement('iframe');\niframe.style.display = 'none';\niframe.onload = function() { iframe.parentNode.removeChild(iframe); };\niframe.src = "http${t.config.ssl?"s":""}://${e}${null!==(p=null===(u=Object.entries(null!==(c=t.config.mapping)&&void 0!==c?c:{}).find((([e,t])=>{var n;return null===(n=null==t?void 0:t.toString())||void 0===n?void 0:n.startsWith("recorder:")})))||void 0===u?void 0:u[0])&&void 0!==p?p:"/recorder/"}?forceLogInRecorderPage=true";\ndocument.body.appendChild(iframe);\n});\ndocument.getElementById('upload-mocks').addEventListener('click', () => {\nconst time = new Date().toISOString().split('T')[1].replace('Z', '');\nconst fileInput = document.createElement('input');\nfileInput.type = "file";\nfileInput.multiple = "multiple";\nfileInput.onchange = function() {\nconst fileReader = new FileReader();\n[...fileInput.files].reduce((promise, file) =>\npromise.then(result => new Promise(resolve => {\nfileReader.readAsText(file);\nfileReader.onload = function(){\nresolve(result.concat(fileReader.result));\n};\n})), Promise.resolve([]))\n.then(files => files.flatMap(file => JSON.parse(file)))\n.catch(e => [])\n.then(mocks => loadMocks(mocks))\n.then(() => updateState());\n}\nfileInput.click();\n});\ndocument.getElementById('download-mocks').addEventListener('click', () => {\nconst link = document.createElement('a');\nlink.href = URL.createObjectURL(new Blob([getMocksData()], {\ntype: "application/json",\n}));\nlink.download = "mocks-" + new Date().toISOString() + ".json";\nlink.click();\nURL.revokeObjectURL(link.href);\n})\ndocument.getElementById('delete-mocks').addEventListener('click', () => {\ndocument.getElementById('limit').value = -1;\ncleanup();\nupdateState();\ndocument.getElementById('limit').value = 0;\n})\ndocument.getElementById('record-mode').addEventListener('change', () => {\ndocument.getElementById('limit').value = 0;\ncleanup();\nupdateState();\n})\ndocument.getElementById('mock-mode').addEventListener('change', () => {\nupdateState();\n})\ndocument.getElementById('auto-record-mode').addEventListener('change', (e) => { \nupdateState();\ndocument.getElementById('table-access').style.filter = \ndocument.getElementById('auto-record-mode').checked ? 'blur(8px)' : 'blur(0px)';\ndocument.getElementById('commands').style.filter = \ndocument.getElementById('auto-record-mode').checked ? 'blur(8px)' : 'blur(0px)';\ndocument.getElementById('alert-about-auto-record-mode').style.display = \ndocument.getElementById('auto-record-mode').checked ? 'block' : 'none';\ndocument.getElementById('strict-mock-mode-form-control').style.filter = \ndocument.getElementById('auto-record-mode').checked ? 'blur(8px)' : 'blur(0px)';\n\n})\ndocument.getElementById('strict-mock-mode').addEventListener('change', (e) => { \nupdateState();\n})\nfunction saveRequest () {\n$('#edit-request').modal("hide");\n\nconst requestBeingEdited = window.requestBeingEdited;\nlet request = uniqueHashEditor.get();\nlet response = responseEditor.get();\nif (typeof request.body === "object") {\nrequest.body = JSON.stringify(request.body);\n}\nif (typeof response.body === "object") {\nresponse.body = JSON.stringify(response.body);\n}\nconst oldRequest = JSON.parse(atob(requestBeingEdited.attributes['data-uniqueHash'].value));\nconst oldResponse = JSON.parse(atob(requestBeingEdited.attributes['data-response'].value));\nconst requestProlog = requestBeingEdited.attributes['data-requestProlog']?.value;\nconst responseProlog = requestBeingEdited.attributes['data-responseProlog']?.value;\nconst requestPrologHasChanged = request.body.substring(0, 10) !== oldRequest.body.substring(0, 10);\nconst responsePrologHasChanged = response.body.substring(0, 10) !== response.body.substring(0, 10);\nif (requestProlog === "H4sIAAAAAAAA" && !requestPrologHasChanged) {\nrequest.body =\nbtoa([...pako.gzip(request.body)].map(e => String.fromCharCode(e)).join(""));\n} else if ((requestProlog === null || !request.body.startsWith(requestProlog ?? "")) && \nrequest.body.substring(0, 10) !== oldRequest.body.substring(0, 10)) {\nrequest.body = btoa(request.body);\n}\nif (responseProlog === "H4sIAAAAAAAA" && !responsePrologHasChanged) {\nresponse.body =\nbtoa([...pako.gzip(response.body)].map(e => String.fromCharCode(e)).join(""));\n} else if ((responseProlog === null || !response.body.startsWith(responseProlog ?? "")) && \nresponse.body.substring(0, 10) !== oldResponse.body.substring(0, 10)) {\nresponse.body = btoa(response.body);\n}\nrequest = btoa(JSON.stringify(request));\nresponse = btoa(JSON.stringify(response));\nrequestBeingEdited.setAttribute('data-uniqueHash', request);\nrequestBeingEdited.setAttribute('data-response', response);\nconst row = requestBeingEdited.closest('tr');\nrow.querySelector("td.method").innerHTML = uniqueHashEditor.get().method;\nrow.querySelector("td.upstream-path").innerHTML = uniqueHashEditor.get().url;\nwindow.requestBeingEdited = undefined;\nupdateState();\n}\ndocument.getElementById('edit-request').addEventListener('show.bs.modal', event => {\nconst request = JSON.parse(atob(event.relatedTarget.attributes['data-uniqueHash'].value));\nconst response = JSON.parse(atob(event.relatedTarget.attributes['data-response'].value));\nconst requestProlog = xmlOrJsonPrologsInBase64.find(prolog => request.body?.startsWith(prolog));\nconst responseProlog = xmlOrJsonPrologsInBase64.find(prolog => response.body?.startsWith(prolog));\nif (requestProlog) {\nevent.relatedTarget.setAttribute('data-requestProlog', requestProlog);\nrequest.body = request.body.startsWith("H4sIAAAAAAAA") \n? pako.ungzip(new Uint8Array(atob(request.body).split("").map(e => e.charCodeAt(0))), {to: "string"})\n: atob(request.body);\nrequest.body = request.body.startsWith("{\\"") || request.body.startsWith("[{\\"")\n? JSON.parse(request.body) : request.body;\n}\nif (responseProlog) {\nevent.relatedTarget.setAttribute('data-responseProlog', responseProlog);\nresponse.body = response.body.startsWith("H4sIAAAAAAAA") \n? pako.ungzip(new Uint8Array(atob(response.body).split("").map(e => e.charCodeAt(0))), {to: "string"})\n: atob(response.body);\nresponse.body = response.body.startsWith("{\\"") || response.body.startsWith("[{\\"")\n? JSON.parse(response.body) : response.body;\n}\nwindow.requestBeingEdited = event.relatedTarget;\nwindow.uniqueHashEditor.set(request);\nwindow.responseEditor.set(response);\ndocument.getElementById('edit-request-label').innerText = "Edit request to " + request.url;\n})\n\nsetTimeout(() => {\nloadMocks(${JSON.stringify([...t.mockConfig.mocks.entries()].map((([e,t])=>({uniqueHash:e,response:t}))))});\nwindow.uniqueHashEditor = new JSONEditor(document.getElementById("uniqueHash-editor"), {\nmode: "code", allowSchemaSuggestions: true, schema: {\ntype: "object",\nproperties: {\nmethod: {type: "string"},\nurl: {type: "string"},\nbody: {oneOf: [{type:"string"},{type:"object"},{type:"array"}]},\nheaders: {type: "object"},\n},\nrequired: [],\nadditionalProperties: false\n}});\nwindow.responseEditor = new JSONEditor(document.getElementById("response-editor"), {\nmode: "code", allowSchemaSuggestions: true, schema: {\ntype: "object",\nproperties: {\nbody: {oneOf: [{type:"string"},{type:"object"},{type:"array"}]},\nheaders: {type: "object"},\nstatus: {type: "integer"}\n},\nrequired: [],\nadditionalProperties: false\n}});\n${t.mockConfig.autoRecord?";document.getElementById('strict-mock-mode-form-control').style.filter='blur(8px)';;document.getElementById('table-access').style.filter='blur(8px)';":""}\ndocument.forms[0].reset();\n}, 10)\n<\/script>\n</form>\n<div class="alert alert-warning" role="alert"\nstyle="display:${t.mockConfig.autoRecord?"block":"none"};left:20%;right:20%;position:absolute;z-index:1;" id="alert-about-auto-record-mode">\n&#x24D8;&nbsp;Auto-record mode and recorder webapp are known to be mutually exclusive.\n<br/><br/>Changing the mocks on both sides is somehow hard to sort out.\n<br/>This is triggering concurrent modifications in the mock config.\n<hr/>\nHere is what you can do :\n<ul>\n<li>If you want to record mocks using a frontend app, turn off the auto-record mode.</li>\n<li>If you want to record mocks with the recorder API only, close this app.</li>\n</ul>\n</div>\n${q(e,t.config,{captureResponseBody:!0})}\n</body>\n</html>`)},file:(e,t,n,o)=>{const r=null==o?void 0:o.target,s=(0,d.resolve)("/",r.hostname,...r.pathname.replace(/[?#].*$/,"").replace(/^\/+/,"").split("/").map(decodeURIComponent));return{alpnProtocol:"file",error:null,data:null,hasRun:!1,run:function(){return this.hasRun?Promise.resolve():new Promise((e=>(0,a.readFile)(s,((t,n)=>{if(this.hasRun=!0,!t||"EISDIR"!==t.code)return this.error=t,this.data=n,void e(void 0);(0,a.readdir)(s,((t,n)=>{this.error=t,this.data=n,t?e(void 0):Promise.all(n.map((e=>new Promise((t=>(0,a.lstat)((0,d.resolve)(r.pathname,e),((n,o)=>t([e,o,n])))))))).then((t=>{const n=t.filter((e=>!e[2]&&e[1].isDirectory())).concat(t.filter((e=>!e[2]&&e[1].isFile())));this.data=`${W(128194,"directory",r.href)}<p>Directory content of <i>${r.href.replace(/\//g,"&#x002F;")}</i></p><ul class="list-group"><li class="list-group-item">&#x1F4C1;<a href="${r.pathname.endsWith("/")?"..":"."}">&lt;parent&gt;</a></li>${n.filter((e=>!e[2])).map((e=>`<li class="list-group-item">&#x${(e[1].isDirectory()?128193:128196).toString(16)};<a href="${r.pathname.endsWith("/")?"":`${r.pathname.split("/").slice(-1)[0]}/`}${e[0]}">${e[0]}</a></li>`)).join("\n")}</li></ul></body></html>`,e(void 0)}))}))}))))},events:{},on:function(e,t){return this.events[e]=t,this.run().then((()=>{"response"===e&&this.events.response(s.endsWith(".svg")?{Server:"local","Content-Type":"image/svg+xml"}:{Server:"local"},0),"data"===e&&this.data&&(this.events.data(this.data),this.events.end()),"error"===e&&this.error&&this.events.error(this.error)})),this},end:function(){return this},request:function(){return this},write:function(){return this}}},data:(e,t,n,o)=>{var r,s,i,a,l,d;const[,c,u,p]=null!==(s=/^data:([^;,]*)?;?([^,]*)?,(.*)$/.exec(null!==(r=null==o?void 0:o.target.href)&&void 0!==r?r:"data:,"))&&void 0!==s?s:["","","",""],m=decodeURIComponent(p),g="base64"===u?Buffer.from(m,"base64url").toString("binary"):m;return J(t.config.replaceResponseBodyUrls?_(Buffer.from(g),{"content-type":c||"text/plain"},{mapping:null!==(i=t.config.mapping)&&void 0!==i?i:{},proxyHostnameAndPort:e,proxyHostname:null!==(a=null==o?void 0:o.proxyHostname)&&void 0!==a?a:"localhost",key:null!==(l=null==o?void 0:o.key)&&void 0!==l?l:"",direction:h.INBOUND,ssl:!!t.config.ssl,port:null!==(d=t.config.port)&&void 0!==d?d:null==A?void 0:A.port}):g,{contentType:c})}},P=Object.keys(j),L=P.map((e=>`${e}:`)),A={mapping:Object.assign({},...P.filter((e=>"data"!==e&&"file"!==e)).map((e=>({[`/${e}/`]:`${e}://`})))),port:8080,replaceRequestBodyUrls:!1,replaceResponseBodyUrls:!1,dontUseHttp2Downstream:!1,dontTranslateLocationHeader:!1,logAccessInTerminal:!1,simpleLogs:!1,websocket:!0,disableWebSecurity:!1,connectTimeout:3e3,socketTimeout:3e3,unwantedHeaderNamesInMocks:[]},H=(...e)=>t(void 0,[...e],void 0,(function*(e=!0){return new Promise((t=>(0,a.readFile)(y,((n,o)=>{n&&!e&&k(null,[[{text:`${g.ERROR_1} config error. Using default value`,color:m.ERROR}]]);let r=null;try{r=Object.assign({},A,JSON.parse((null!=o?o:"{}").toString()))}catch(e){return r=null!=r?r:Object.assign({},A),k({config:void 0},[[{text:`${g.ERROR_2} config syntax incorrect, ignoring`,color:m.ERROR}]]).then((()=>t(r)))}n&&"ENOENT"===n.code&&e&&y===v?(0,a.writeFile)(y,JSON.stringify(A,null,2),(e=>k(null,e?[[{text:`${g.ERROR_4} config file NOT created`,color:m.ERROR}]]:[[{text:`${g.COLORED} config file created`,color:m.INFO}]]).then((()=>t(r))))):t(r)}))))}));exports.load=H;const U=e=>""==e?"":(0,d.normalize)(e).replace(/\\/g,"/"),M="https://cdn.jsdelivr.net/npm/",D=["host","connection","keep-alive","upgrade","transfer-encoding","upgrade-insecure-requests","proxy-connection"],W=(e,t,n)=>`<!doctype html>\n<html lang="en">\n<head>\n<title>&#x${e.toString(16)}; local-traffic ${t} | ${n}</title>\n<link href="${M}bootstrap/dist/css/bootstrap.min.css" rel="stylesheet"/>\n<script src="${M}jquery/dist/jquery.min.js"><\/script>\n<script src="${M}bootstrap/dist/js/bootstrap.bundle.min.js"><\/script>\n</head>\n<body><div class="container"><h1>&#x${e.toString(16)}; local-traffic ${t}</h1>\n<br/>`,F=({response:e})=>({alpnProtocol:"mock",error:null,data:null,hasRun:!1,run:function(){return this.hasRun?Promise.resolve():new Promise((t=>{try{this.data=JSON.parse(Buffer.from(e,"base64").toString("utf-8"))}catch(e){this.data={}}t(void 0)}))},events:{},on:function(e,t){return this.events[e]=t,this.run().then((()=>{var t;"response"===e&&this.events.response(Object.assign(Object.assign({},this.data.headers),{"X-LocalTraffic-Mock":"1"}),this.data.status),"data"===e&&this.data&&(this.events.data(Buffer.from(null!==(t=this.data.body)&&void 0!==t?t:"","base64")),this.events.end()),"error"===e&&this.error&&this.events.error(this.error)})),this},end:function(){return this},request:function(){return this},write:function(){return this}}),J=(e,t)=>({alpnProtocol:"static",error:null,data:null,outboundData:null,run:function(){return"string"==typeof e?new Promise((t=>{this.data=e,t(void 0)})):e.then((e=>{this.data=e.toString("utf8")}))},events:{},on:function(e,n){return this.events[e]=n,this.run().then((()=>{var n;"response"===e&&this.events.response({Server:"local","Content-Type":null!==(n=null==t?void 0:t.contentType)&&void 0!==n?n:"text/html"},0),"data"===e&&this.data&&(this.events.data(this.data),this.events.end()),"error"===e&&this.error&&this.events.error(this.error)})),this},write:function(e){var n;return this.outboundData=e,e instanceof Buffer&&(null===(n=null==t?void 0:t.onOutboundWrite)||void 0===n||n.call(t,e)),this},end:function(){return this},request:function(){return this}}),_=(e,n,o)=>t(void 0,void 0,void 0,(function*(){var r,s;return(null!==(s=null===(r=n["content-encoding"])||void 0===r?void 0:r.toString())&&void 0!==s?s:"").split(",").reduce(((e,n)=>t(void 0,void 0,void 0,(function*(){const t=n.trim().toLowerCase(),o="gzip"===t||"x-gzip"===t?l.gunzip:"deflate"===t?l.inflate:"br"===t?l.brotliDecompress:"identity"===t||""===t?(e,t)=>{t(null,e)}:null;if(null===o)throw new Error(`${t} compression not supported by the proxy`);const r=yield e;return yield new Promise(((e,t)=>o(r,((n,o)=>{n&&t(n),e(o)}))))}))),Promise.resolve(e)).then((e=>{const t=e.length>1e7,r=["text/html","application/javascript","application/json"].some((e=>{var t;return(null!==(t=n["content-type"])&&void 0!==t?t:"").toString().includes(e)}));return!t&&(r||!/[^\x00-\xFF]/.test(e.toString()))?K(e.toString(),{direction:o.direction,proxyHostnameAndPort:o.proxyHostnameAndPort,ssl:o.ssl,mapping:o.mapping}).replace(/\?protocol=wss?%3A&hostname=[^&]+&port=[0-9]+&pathname=/g,`?protocol=ws${o.ssl?"s":""}%3A&hostname=${o.proxyHostname}&port=${o.port}&pathname=${encodeURIComponent(o.key.replace(/\/+$/,""))}`):e})).then((e=>{var t,o;return(null!==(o=null===(t=n["content-encoding"])||void 0===t?void 0:t.toString())&&void 0!==o?o:"").split(",").reverse().reduce(((e,t)=>{const n=t.trim().toLowerCase(),o="gzip"===n||"x-gzip"===n?l.gzip:"deflate"===n?l.deflate:"br"===n?l.brotliCompress:"identity"===n||""===n?(e,t)=>{t(null,e)}:null;if(null===o)throw new Error(`${n} compression not supported by the proxy`);return e.then((e=>new Promise((t=>o(e,((e,n)=>{if(e)throw e;t(n)}))))))}),Promise.resolve(Buffer.from(e)))}))}));exports.replaceBody=_;const K=(e,{direction:t,proxyHostnameAndPort:n,ssl:o,mapping:r})=>Object.entries(r).map((([e,t])=>[e,"string"==typeof t?t:t.replaceBody])).reduce(((e,[r,s])=>L.some((e=>s.startsWith(e)))||""!==r&&!r.match(/^[-a-zA-Z0-9()@:%_\+.~#?&//=]*$/)?e:t===h.INBOUND?e.replace(new RegExp(s.replace(new RegExp(`^(${P.join("|")})://`),"").replace(/[*+?^${}()|[\]\\]/g,"").replace(/^https/,"https?")+"/*","ig"),`http${o?"s":""}://${n}${r.replace(/\/+$/,"")}/`):e.split(`http${o?"s":""}://${n}${r.replace(/\/+$/,"")}`).join(s)),e).split(`${n}/:`).join(`${n}:`);exports.replaceTextUsingMapping=K;const z=(e,t)=>{try{const n="object"==typeof t?t:JSON.parse(Buffer.from(t,"base64").toString("utf-8"));return["access-control-max-age","authorization","cache-control","cookie","date","dnt","expires","if-modified-since","if-unmodified-since","keep-alive","last-modified","pragma","proxy-authenticate","proxy-authorization","referer","retry-after","signed-headers","server-timing","sec-ch-ua","sec-ch-ua-mobile","sec-ch-ua-platform","sec-fetch-dest","sec-fetch-mode","sec-fetch-site","sec-fetch-user","upgrade-insecure-requests","user-agent",...Array.isArray(e.unwantedHeaderNamesInMocks)?e.unwantedHeaderNamesInMocks:[]].forEach((e=>{var t;null===(t=null==n?void 0:n.headers)||void 0===t||delete t[e]})),n.headers=Object.keys(n.headers).sort().reduce(((e,t)=>(e[t]=n.headers[t],e)),{}),Buffer.from(JSON.stringify(n),"utf-8").toString("base64")}catch(e){return t}};exports.cleanEntropy=z;const G=(e,t,n)=>{t.writeHead(e,{"content-type":"text/html","content-length":n.length}),t.end(n)};exports.send=G;const Y=(e,t)=>{var n,o,r,s,a,l,d,c;const u=(null!==(r=null!==(o=null===(n=e.headers[":authority"])||void 0===n?void 0:n.toString())&&void 0!==o?o:e.headers.host)&&void 0!==r?r:"localhost").replace(/:.*/,""),p=e.headers[":authority"]||`${e.headers.host}${(null!==(s=e.headers.host)&&void 0!==s?s:"").match(/:[0-9]+$/)?"":80!==t.port||t.ssl?443===t.port&&t.ssl?"":`:${null!==(a=t.port)&&void 0!==a?a:8080}`:""}`,m=new i.URL(`http${t.ssl?"s":""}://${p}${null!==(l=e.url)&&void 0!==l?l:""}`),g=m.href.substring(m.origin.length),h=Object.assign({},Object.assign({},...Object.entries(null!==(d=t.mapping)&&void 0!==d?d:{}).map((([e,t])=>{var n,o;const r="string"==typeof t?t:null!==(n=null==t?void 0:t.downstreamUrl)&&void 0!==n?n:"";return{[e]:new i.URL((null===(o=null==r?void 0:r.startsWith)||void 0===o?void 0:o.call(r,"data:"))?r:U(r))}}))));let f=null;const[v,y]=null!==(c=Object.entries(h).find((([e])=>{var t;return f=null!==(t=g.match(RegExp(e.replace(/^\//,"^/"))))&&void 0!==t?t:null})))&&void 0!==c?c:["/"],b=f&&y?new i.URL(y.href.replace(/\$\$(\d+)/g,((e,t)=>f[parseInt(t)]))):null;return{proxyHostname:u,proxyHostnameAndPort:p,url:m,path:g,key:v,target:b}};exports.determineMapping=Y;const X=function(e,t,n){var o,a,l,d,c,u,p,h,f,v;if(n.on("error",(()=>{e.log([[{text:`${g.WEBSOCKET} websocket connection reset`,color:m.WARNING}]])})),!e.config.websocket)return n.end("HTTP/1.1 503 Service Unavailable\r\n\r\n"),{};const{key:y,target:b,path:O,url:k}=Y(t,e.config);if(O.startsWith("/local-traffic-logs"))return x(n,null!==(o=t.headers["sec-websocket-key"])&&void 0!==o?o:""),{logsListeners:e.logsListeners.concat({stream:n,wantsMask:!(null!==(l=null===(a=t.headers["user-agent"])||void 0===a?void 0:a.toString())&&void 0!==l?l:"").includes("Chrome"),wantsResponseMessage:[...k.searchParams.entries()].some((([e,t])=>"wantsResponseMessage"===e&&"true"===t))})};if("/local-traffic-config"===O){x(n,null!==(d=t.headers["sec-websocket-key"])&&void 0!==d?d:"");let o=null;return n.on("data",(t=>{const n=R(t,o);if(null===o&&n.body.length<n.payloadLength)o=n;else{if(n.body.length>=n.payloadLength&&0===n.body.length)return{};if(n.body.length>=n.payloadLength){let t;o=null;try{t=JSON.parse(n.body)}catch(t){return e.log([[{text:`${g.ERROR_4} config file NOT read, try again later`,color:m.WARNING}]]),{}}ee(e,{pendingConfigSave:t})}}})),{configListeners:e.configListeners.concat({stream:n,wantsMask:!(null!==(u=null===(c=t.headers["user-agent"])||void 0===c?void 0:c.toString())&&void 0!==u?u:"").includes("Chrome")})}}const w=new i.URL(`${null!==(p=null==b?void 0:b.protocol)&&void 0!==p?p:"https"}//${null!==(h=null==b?void 0:b.host)&&void 0!==h?h:"localhost"}${null===(v=null===(f=t.url)||void 0===f?void 0:f.replace(new RegExp(`^${y}`,"g"),b.pathname))||void 0===v?void 0:v.replace(/^\/*/,"/")}`),E={hostname:w.hostname,path:w.pathname,port:w.port,protocol:w.protocol,rejectUnauthorized:!1,method:t.method,headers:Object.assign(Object.assign({},t.headers),{host:w.hostname,origin:w.origin}),host:w.hostname},$="https:"===w.protocol?(0,s.request)(E):(0,r.request)(E);return $.end(),$.on("error",(t=>{e.log([[{text:`${g.WEBSOCKET} websocket request has errored ${t.errno?`(${t.errno})`:""}`,color:m.WARNING}]])})),$.on("upgrade",((t,o)=>{const r=`HTTP/${t.httpVersion} ${t.statusCode} ${t.statusMessage}\r\n${Object.entries(t.headers).flatMap((([e,t])=>(Array.isArray(t)?t:[t]).map((t=>[e,t])))).map((([e,t])=>`${e}: ${t}\r\n`)).join("")}\r\n`;n.write(r),n.allowHalfOpen=!0,o.allowHalfOpen=!0,o.on("data",(e=>n.write(e))),n.on("data",(e=>o.write(e))),o.on("error",(t=>{e.log([[{text:`${g.WEBSOCKET} downstream socket has errored ${t.errno?`(${t.errno})`:""}`,color:m.WARNING}]])})),n.on("error",(t=>{e.log([[{text:`${g.WEBSOCKET} upstream socket has errored ${t.errno?`(${t.errno})`:""}`,color:m.WARNING}]])}))})),{}};exports.websocketServe=X;const Z=function(e,n,r){return t(this,void 0,void 0,(function*(){var s,a,l,d,p,v,O,k,w,R,x,E,$,S,C,I,q,N,P,H,M,W,J,X,Z,Q,V,ee,te,ne,oe;if(!n.headers.host&&!n.headers[":authority"])return void G(400,r,Buffer.from(B(new Error("client must supply a 'host' header"),e.mode,"proxy",new i.URL(`http${e.config.ssl?"s":""}://unknowndomain${n.url}`))));const{proxyHostname:re,proxyHostnameAndPort:se,url:ie,path:ae,key:le,target:de}=Y(n,e.config),ce=null!=de?de:e.mode===f.MOCK?new i.URL(`http${e.config.ssl?"s":""}://${se}/`):null;if(!ce)return void G(502,r,Buffer.from(B(new Error(`No mapping found in config file ${y}`),e.mode,"proxy",ie)));const ue="data:"===ce.protocol?"":"//",pe=ce.host.replace(RegExp(/\/+$/),""),me=ce.href.substring(`${ce.protocol}${ue}`.length+ce.host.length),ge="file:"===ce.protocol||"data:"===ce.protocol?me:`${me}${U(ae.replace(RegExp(U(le)),""))}`.replace(/^\/*/,"data:"===ce.protocol?"":"/"),he=new i.URL(`${ce.protocol}${ue}${pe}${ge}`),fe=L.some((e=>ce.protocol===e)),ve=(0,c.randomBytes)(20).toString("hex");let ye=null;const be=e.config.replaceRequestBodyUrls||!!e.logsListeners.length;e.config.ssl&&(yield new Promise((e=>setTimeout(e,1))));const Oe=parseInt(null!==(s=n.headers["content-length"])&&void 0!==s?s:"0")>0,ke=!!(null==n?void 0:n.readableLength)||Oe,we=!!(null==n?void 0:n.stream)&&Oe,Re=!!(null===(l=null===(a=n.headers)||void 0===a?void 0:a.accept)||void 0===l?void 0:l.includes("text/event-stream")),xe=!((e.config.ssl&&!1===we||!e.config.ssl&&!1===ke)&&("0"===n.headers["content-length"]||void 0===n.headers["content-length"]));if(be){const t=null!==(d=null==n?void 0:n.stream)&&void 0!==d?d:n;let o=Buffer.from([]);yield Promise.race([new Promise((t=>setTimeout(t,e.config.connectTimeout))),new Promise((e=>{xe?(t.on("data",(e=>{o=Buffer.concat([o,e])})),t.on("end",e),t.on("error",e)):e(void 0)}))]),xe&&!o.length&&(yield e.log([[{text:`${g.ERROR_4} body replacement error ${ae.slice(-17)}`,color:m.WARNING}]])),ye=e.config.replaceRequestBodyUrls?yield _(o,n.headers,{proxyHostnameAndPort:se,proxyHostname:re,key:le,mapping:null!==(p=e.config.mapping)&&void 0!==p?p:{},port:null!==(v=e.config.port)&&void 0!==v?v:A.port,ssl:!!e.config.ssl,direction:h.OUTBOUND}):o}const Ee=e.logsListeners.some((e=>e.wantsResponseMessage)),$e=e.mockConfig.autoRecord&&e.mode===f.PROXY,Se=z(e.config,{method:null!==(O=n.method)&&void 0!==O?O:"GET",url:null!==(k=n.url)&&void 0!==k?k:"",headers:Object.assign({},...Object.entries(n.headers).filter((([e])=>!e.startsWith(":"))).map((([e,t])=>({[e]:t})))),body:(e.mode===f.MOCK||Ee||$e)&&null!==(w=null==ye?void 0:ye.toString("base64"))&&void 0!==w?w:""});e.config.logAccessInTerminal&&!he.pathname.startsWith("/:/")&&(yield e.log([[{color:"GET"===n.method?22:"POST"===n.method?52:"PUT"===n.method?94:"DELETE"===n.method?244:"OPTIONS"===n.method?19:"PATCH"===n.method?162:"HEAD"===n.method?53:"TRACE"===n.method?6:"CONNECT"===n.method?2:0,text:(null!==(R=n.method)&&void 0!==R?R:"GET").toString(),length:null===(x=n.method)||void 0===x?void 0:x.length},{color:8,text:he.pathname.toString().padStart(62-(null!==($=null===(E=n.method)||void 0===E?void 0:E.length)&&void 0!==$?$:3)).substring(0,62-(null!==(C=null===(S=n.method)||void 0===S?void 0:S.length)&&void 0!==C?C:3)),length:62-(null!==(q=null===(I=n.method)||void 0===I?void 0:I.length)&&void 0!==q?q:3)}]]));const Ce=e.mode===f.MOCK&&!fe,Ie=Ce?null!==(N=e.mockConfig.mocks.get(Se))&&void 0!==N?N:null===(P=Array.from(e.mockConfig.mocks.entries()).filter((([t])=>{var n;const o=JSON.parse(Buffer.from(Se,"base64").toString("ascii")),r=JSON.parse(Buffer.from(t,"base64").toString("ascii"));return r.method===o.method&&r.url===o.url&&(!r.body||r.body===o.body)&&Object.entries(null!==(n=r.headers)&&void 0!==n?n:{}).every((([t,n])=>{var r,s,i,a;return!n||(null===(i=null===(s=null===(r=e.config)||void 0===r?void 0:r.unwantedHeaderNamesInMocks)||void 0===s?void 0:s.includes)||void 0===i?void 0:i.call(s,t))||(null===(a=o.headers)||void 0===a?void 0:a[t])===n}))})).sort((([e],[t])=>{var n,o;const r=JSON.parse(Buffer.from(t,"base64").toString("ascii")),s=JSON.parse(Buffer.from(e,"base64").toString("ascii")),i=r.body?1:0,a=s.body?1:0;return Object.keys(null!==(n=r.headers)&&void 0!==n?n:{}).length+i-Object.keys(null!==(o=s.headers)&&void 0!==o?o:{}).length-a}))[0])||void 0===P?void 0:P[1]:null;if(Ce&&!Ie&&e.mockConfig.strict)return void G(502,r,Buffer.from(B(new Error("No corresponding mock found in the server. \nTry switching back to the proxy mode"),e.mode,"mock",ie)));let Be=null;const qe=b(),Ne=Object.assign(Object.assign({},[...Object.entries(n.headers)].filter((([e])=>!D.includes(e.toLowerCase()))).reduce(((e,[t,n])=>(e[t]=(e[t]||"")+(Array.isArray(n)?n:[n]).map((e=>null==e?void 0:e.replace(ie.hostname,pe))).join(", "),e)),{})),{origin:ce.href,referer:he.toString(),"content-length":null!==(M=null!==(H=null==ye?void 0:ye.length)&&void 0!==H?H:n.headers["content-length"])&&void 0!==M?M:0,":authority":pe,":method":n.method,":path":ge,":scheme":ce.protocol.replace(":","")}),Te=Ce&&Ie?F({response:Ie}):fe?j[ce.protocol.replace(/:$/,"")](se,e,n,{target:he,proxyHostname:re,key:le}):yield((e,n,r)=>t(void 0,void 0,void 0,(function*(){var e,t;let s=null,i="https:"===(null===(e=null==r?void 0:r.target)||void 0===e?void 0:e.protocol)&&!n.config.dontUseHttp2Downstream;const a=i?n.mode!==f.PROXY&&(null===(t=null==n?void 0:n.mockConfig)||void 0===t?void 0:t.strict)?null:yield Promise.race([new Promise((e=>{const t=(0,o.connect)(r.target,{timeout:n.config.connectTimeout,sessionTimeout:n.config.socketTimeout,rejectUnauthorized:!1,protocol:r.target.protocol},((n,o)=>{i=i&&!!o.alpnProtocol,e(i?t:null)}));t.on("error",(e=>{s=i?Buffer.from(B(e,n.mode,"connection",r.url,r.target)):null}))})),new Promise((e=>setTimeout((()=>{i=!1,e(null)}),n.config.connectTimeout)))]):null;if(s)throw s;return i?a:null})))(0,e,{target:he,url:ie}).then((t=>t||T(ce,ie,he,ge,n,Ne,ye,be,e.mode))).catch((e=>(Be=e,null))),je=(null===(J=null===(W=null==Te?void 0:Te.alpnProtocol)||void 0===W?void 0:W.startsWith)||void 0===J?void 0:J.call(W,"h2"))?"HTTP/2":null!==(X=null==Te?void 0:Te.alpnProtocol)&&void 0!==X?X:"HTTP1.1";e.notifyLogsListeners({level:"info",protocol:je,method:n.method,upstreamPath:ae,downstreamPath:he.href,randomId:ve,uniqueHash:Se}),Be instanceof Buffer||(Be=null);const Pe=!Be&&(null==Te?void 0:Te.request(Ne,{endStream:e.config.ssl?!(null==we||we):!ke}));if("object"==typeof Pe&&(null===(Z=null==Pe?void 0:Pe.on)||void 0===Z||Z.call(Pe,"error",(t=>{const n=-505===t.errno;Be=Buffer.from(B(t,e.mode,"stream"+(n?" (error -505 usually means that the downstream service does not support this http version)":""),ie,he))}))),Be)return void G(502,r,Be);Be=null,we&&Pe&&!be?(n.stream.on("data",(e=>{Pe.write(e)})),n.stream.on("end",(()=>Pe.end()))):ke&&Pe&&!be?(n.on("data",(e=>{Pe.write(e)})),n.on("end",(()=>Pe.end()))):Pe&&be&&xe&&!Pe.writableEnded&&(Pe.write(ye),Pe.end());const{outboundResponseHeaders:Le}=yield new Promise((e=>{var t,n;return null!==(n=null===(t=null==Pe?void 0:Pe.on)||void 0===t?void 0:t.call(Pe,"response",(t=>{e({outboundResponseHeaders:t})})))&&void 0!==n?n:e({outboundResponseHeaders:{}})}));let Ae=null;try{Le.location&&(Ae=new i.URL(Le.location.startsWith("/")?`${ce.origin}${Le.location.replace(/^\/+/,"/")}`:Le.location.replace(/^file:\/+/,"file:///").replace(/^(http)(s?):\/+/,"$1$2://")))}catch(t){yield e.log([[{text:`${g.ERROR_4} location replacement error ${(null!==(Q=Le.location)&&void 0!==Q?Q:"").slice(-13)}`,color:m.WARNING}]])}const He=e.config.replaceResponseBodyUrls&&Ae?new i.URL(K(Ae.href,{direction:h.INBOUND,proxyHostnameAndPort:se,ssl:!!e.config.ssl,mapping:null!==(V=e.config.mapping)&&void 0!==V?V:{}}).replace(new RegExp(`^(${L.join("|")})/+`),"")):Ae,Ue=Ae?(null==He?void 0:He.origin)!==Ae.origin||e.config.dontTranslateLocationHeader?He:`${ie.origin}${He.href.substring(He.origin.length)}`:Ae,Me=null!=Be?Be:yield new Promise((e=>{var t,n;let o=Buffer.alloc(0);Pe?(null===(t=null==Pe?void 0:Pe.on)||void 0===t||t.call(Pe,"data",(t=>{o=Buffer.concat([o,"string"==typeof t?Buffer.from(t):t]),Re&&e(o)})),null===(n=null==Pe?void 0:Pe.on)||void 0===n||n.call(Pe,"end",(()=>{e(o)}))):e(o)})).then((t=>{var n,o;return e.config.replaceResponseBodyUrls&&t.length?L.some((e=>ce.protocol===e))?t:_(t,Le,{proxyHostnameAndPort:se,proxyHostname:re,key:le,direction:h.INBOUND,mapping:null!==(n=e.config.mapping)&&void 0!==n?n:{},port:null!==(o=e.config.port)&&void 0!==o?o:A.port,ssl:!!e.config.ssl}).catch((t=>(G(502,r,Buffer.from(B(t,e.mode,"stream",ie,he))),Buffer.from("")))):t})),De=Object.assign(Object.assign({},Object.entries(Object.assign(Object.assign(Object.assign(Object.assign({},Le),e.config.replaceResponseBodyUrls&&!Re?{"content-length":`${Me.byteLength}`}:{}),e.config.disableWebSecurity?{"content-security-policy":"report only","access-control-allow-headers":"*","access-control-allow-method":"*","access-control-allow-origin":"*"}:{}),Re?{"cache-control":"no-cache","x-accel-buffering":"no"}:{})).filter((([e])=>!e.startsWith(":")&&!D.includes(e.toLowerCase()))).reduce(((e,[t,n])=>{const o=pe.split("").map(((e,t)=>pe.substring(t).startsWith(".")&&pe.substring(t))).filter((e=>e)),r=[pe].concat(o).reduce(((e,t)=>(Array.isArray(e)?e:[e]).map((e=>"string"==typeof e?e.replace(`Domain=${t}`,`Domain=${ie.hostname}`):e))),n);return e[t]=(e[t]||[]).concat(r),e}),{})),Ue?{location:[Ue]}:{});try{Object.entries(De).forEach((([e,t])=>t&&r.setHeader(e,t)))}catch(e){}const We=null!==(ee=Le[":status"])&&void 0!==ee?ee:200;try{e.config.ssl?r.writeHead(We,De):r.writeHead(We,"HTTP/2"===je?"":null!==(ne=null===(te=Le[":statusmessage"])||void 0===te?void 0:te.toString())&&void 0!==ne?ne:"",De)}catch(e){}Re?(r.write(Me),null===(oe=null==Pe?void 0:Pe.on)||void 0===oe||oe.call(Pe,"data",(e=>r.write(e)))):Me?r.end(Me):r.end();const Fe=b(),Je=Ee||$e?Buffer.from(JSON.stringify({body:null==Me?void 0:Me.toString("base64"),headers:Le,status:We})).toString("base64"):"";e.notifyLogsListeners({randomId:ve,statusCode:We,protocol:je,duration:Math.floor(Number(Fe-qe)/1e6),uniqueHash:Se,response:Je}),!$e||e.config.logAccessInTerminal||fe||(e.mockConfig.mocks.set(Se,Je),u.stdout.moveCursor(0,-1,(()=>u.stdout.clearLine(-1,e.quickStatus))))}))};exports.serve=Z;const Q=(e,t)=>{"EACCES"===t.code&&setTimeout((()=>e.log([[{text:`${g.NO} permission denied for this port`,color:m.ERROR}]])),10),"EADDRINUSE"===t.code&&setTimeout((()=>e.log([[{text:`${g.ERROR_6} port is already used. NOT started`,color:m.ERROR}]])),10)};exports.errorListener=Q;const V=e=>ee({config:Object.assign(Object.assign({},A),e)},{server:null});exports.start=V;const ee=(e,n)=>t(void 0,void 0,void 0,(function*(){var s,i,l,d,c,u,p,h,v,b,O,w,R,x,S,B,q,N,T,j,P,L,A,U,M,D;if(0===Object.keys(null!=n?n:{}).length&&e.server)return n;if(null==n?void 0:n.pendingConfigSave)return(0,a.writeFile)(y,JSON.stringify(n.pendingConfigSave,null,2),(t=>{var n,o;t?null===(n=e.log)||void 0===n||n.call(e,[[{text:`${g.ERROR_4} config file NOT saved`,color:m.ERROR}]]):null===(o=e.log)||void 0===o||o.call(e,[[{text:`${g.COLORED} config file saved... will reload`,color:m.INFO}]])})),e;if(null===(null==n?void 0:n.configListeners)&&(yield Promise.all((null!==(s=e.configListeners)&&void 0!==s?s:[]).map((e=>new Promise((t=>e.stream.end(t))))))),null===(null==n?void 0:n.logsListeners)&&(yield Promise.all((null!==(i=e.configListeners)&&void 0!==i?i:[]).map((e=>new Promise((t=>e.stream.end(t))))))),null===(null==n?void 0:n.server)&&e.server){const t=yield Promise.race([new Promise((t=>{var n;return null===(n=e.server)||void 0===n?void 0:n.close(t)})).then((()=>!0)),new Promise((e=>setTimeout(e,5e3))).then((()=>!1))]);t||(yield null===(l=e.log)||void 0===l?void 0:l.call(e,[[{text:`${g.RESTART} error during restart (websockets ?)`,color:m.WARNING}]]))}(null!==(d=e.configListeners)&&void 0!==d?d:[]).concat(null!==(c=e.logsListeners)&&void 0!==c?c:[]).filter((e=>e.stream.errored||e.stream.closed)).forEach((e=>e.stream.destroy()));const W=null!==(u=null==n?void 0:n.config)&&void 0!==u?u:e.config,F=null!==(h=null!==(p=null==n?void 0:n.mode)&&void 0!==p?p:e.mode)&&void 0!==h?h:f.PROXY,J=null!==(w=null!==(b=null===(v=null==n?void 0:n.mockConfig)||void 0===v?void 0:v.autoRecord)&&void 0!==b?b:null===(O=e.mockConfig)||void 0===O?void 0:O.autoRecord)&&void 0!==w&&w,_=null!==(B=null!==(x=null===(R=null==n?void 0:n.mockConfig)||void 0===R?void 0:R.strict)&&void 0!==x?x:null===(S=e.mockConfig)||void 0===S?void 0:S.strict)&&void 0!==B&&B,K=null!==(j=null!==(N=null===(q=null==n?void 0:n.mockConfig)||void 0===q?void 0:q.mocks)&&void 0!==N?N:null===(T=e.mockConfig)||void 0===T?void 0:T.mocks)&&void 0!==j?j:new Map,z=(null===(null==n?void 0:n.configListeners)?[]:null!==(L=null!==(P=null==n?void 0:n.configListeners)&&void 0!==P?P:e.configListeners)&&void 0!==L?L:[]).filter((e=>!e.stream.errored&&!e.stream.closed)),G=(null===(null==n?void 0:n.logsListeners)?[]:null!==(U=null!==(A=null==n?void 0:n.logsListeners)&&void 0!==A?A:e.logsListeners)&&void 0!==U?U:[]).filter((e=>!e.stream.errored&&!e.stream.closed)),Y=e;return Object.assign(Y,{config:W,logsListeners:G,configListeners:z,mode:F,mockConfig:{mocks:K,strict:_,autoRecord:J},configFileWatcher:void 0===Y.configFileWatcher?(0,a.watchFile)(y,(()=>t(void 0,void 0,void 0,(function*(){return ee(Y,yield function(e){return t(this,void 0,void 0,(function*(){var t,n,o,r,s;const i=e.config,a=yield H(!1),l=[];if(!a)return{};if(isNaN(null!==(t=null==a?void 0:a.port)&&void 0!==t?t:NaN)||(null!==(n=null==a?void 0:a.port)&&void 0!==n?n:-1)>65535||(null!==(o=null==a?void 0:a.port)&&void 0!==o?o:-1)<0)return yield e.log([[{text:`${g.PORT} port number invalid. Not refreshing`,color:m.ERROR}]]),{};if((null===(r=null==a?void 0:a.mapping)||void 0===r?void 0:r[""])||l.push([{text:`${g.ERROR_3} default mapping "" not provided.`,color:m.WARNING}]),"object"!=typeof a.mapping)return e.log([[{text:`${g.ERROR_5} mapping should be an object. Aborting`,color:m.ERROR}]]),{};a.replaceRequestBodyUrls!==i.replaceRequestBodyUrls&&l.push([{text:`${g.REWRITE} request body url ${a.replaceRequestBodyUrls?"":"NO "}rewriting`,color:m.INFO}]),a.replaceResponseBodyUrls!==i.replaceResponseBodyUrls&&l.push([{text:`${g.REWRITE} response body url ${a.replaceResponseBodyUrls?"":"NO "}rewriting`,color:m.INFO}]),a.dontTranslateLocationHeader!==i.dontTranslateLocationHeader&&l.push([{text:`${g.REWRITE} response location header ${a.dontTranslateLocationHeader?"NO ":""}translation`,color:m.INFO}]),a.dontUseHttp2Downstream!==i.dontUseHttp2Downstream&&l.push([{text:`${g.OUTBOUND} http/2 ${a.dontUseHttp2Downstream?"de":""}activated downstream`,color:m.INFO}]),a.disableWebSecurity!==i.disableWebSecurity&&l.push([{text:`${g.SHIELD} web security ${a.disableWebSecurity?"de":""}activated`,color:m.INFO}]),a.websocket!==i.websocket&&l.push([{text:`${g.WEBSOCKET} websocket ${a.websocket?"":"de"}activated`,color:m.INFO}]),a.logAccessInTerminal!==i.logAccessInTerminal&&l.push([{text:`${g.LOGS} access terminal logging ${a.logAccessInTerminal?"on":"off"}`,color:m.INFO}]),a.simpleLogs!==i.simpleLogs&&l.push([{text:`${g.COLORED} simple logs ${a.simpleLogs?"on":"off"}`,color:m.INFO}]),Object.keys(a.mapping).join("\n")!==Object.keys(null!==(s=i.mapping)&&void 0!==s?s:{}).join("\n")&&l.push([{text:`${g.RULES} ${Object.keys(a.mapping).length.toString().padStart(5)} loaded mapping rules`,color:m.INFO}]),a.port!==i.port&&l.push([{text:`${g.PORT} port changed from ${i.port} to ${a.port}`,color:m.INFO}]),a.ssl&&!i.ssl&&l.push([{text:`${g.INBOUND} ssl configuration added`,color:m.INFO}]),!a.ssl&&i.ssl&&l.push([{text:`${g.INBOUND} ssl configuration removed`,color:m.INFO}]);const d=a.port!==i.port||JSON.stringify(a.ssl)!==JSON.stringify(i.ssl);return d&&l.push([{text:`${g.RESTART} restarting server`,color:m.INFO}]),setTimeout((()=>null==e?void 0:e.log(l.concat([C.apply(Object.assign(Object.assign({},e),{config:a}))]))),1),{config:a,server:d?null:void 0}}))}(Y))})))):Y.configFileWatcher,log:k.bind(Y,Y),notifyConfigListeners:E.bind(Y),notifyLogsListeners:$.bind(Y),buildQuickStatus:C.bind(Y),quickStatus:I.bind(Y),server:null!==(null==n?void 0:n.server)||(null!==(D=null===(M=null==n?void 0:n.config)||void 0===M?void 0:M.port)&&void 0!==D?D:0)<0?(null==n?void 0:n.server)?Y.server:null:((null==W?void 0:W.ssl)?o.createSecureServer.bind(null,Object.assign(Object.assign({},W.ssl),{allowHTTP1:!0})):r.createServer)(((e,t)=>Z(Y,e,t))).addListener("error",(e=>Q(Y,e))).on("upgrade",((e,t)=>ee(Y,X(Y,e,t)))).listen(null==W?void 0:W.port)}),Y}));exports.update=ee;const te=null!==(e=u.argv.map((e=>e.trim())).filter((e=>e&&!["ts-node","node","npx","npm","exec"].some((t=>e.includes(t)&&!e.match(/npm-cache/)&&!e.match(/_npx/)))))[0])&&void 0!==e?e:"",ne=te.toLowerCase().replace(/[-_]/g,"").includes("localtraffic")&&!te.match(/(.|-)?(test|spec)\.m?[jt]sx?$/),oe=u.argv.some((e=>"--crash-test"===e));if(oe){const e=Math.floor(40151+9e3*Math.random()),t=(t,n)=>(0,r.request)({hostname:"localhost",port:e,path:"/config/",method:"GET",headers:{Accept:"text/html"},timeout:500},(e=>n({response:e,state:t}))).on("error",(e=>n({error:e,state:t}))).end();ee({config:Object.assign(Object.assign({},A),{port:e}),configFileWatcher:null},{server:null}).then((e=>new Promise((n=>setTimeout(t.bind(null,e,n),1e3))))).then((({state:e,response:t})=>200!==t.statusCode?Promise.reject("Crash test has failed"):ee(e,{config:{port:-1},server:null}))).then((e=>new Promise((n=>setTimeout(t.bind(null,e,n),1e3))))).then((({error:e})=>"ECONNREFUSED"!==(null==e?void 0:e.code)?Promise.reject("Server should have stopped"):k({config:{simpleLogs:!0}},[[{text:`${g.COLORED} Crash test successful`,color:m.INFO}]]))).then((()=>(0,u.exit)(0))).catch((()=>(0,u.exit)(1)))}!oe&&ne&&H().then(V).then((e=>e.quickStatus()));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "local-traffic",
3
- "version": "0.0.99",
3
+ "version": "0.1.0",
4
4
  "main": "./dist/local-traffic.js",
5
5
  "private": false,
6
6
  "keywords": [