web-listener 1.2.0 → 1.2.1

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.
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "web-listener",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "a small server abstraction for creating API and resource endpoints with middleware",
5
5
  "author": "David Evans",
6
6
  "license": "MIT",
package/run.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env -S node --disable-proto=delete --disallow-code-generation-from-strings --force-node-api-uncaught-exceptions-policy --no-addons --experimental-import-meta-resolve
2
- import{readFile as t,stat as e,realpath as o,readdir as n,access as r,constants as s}from"node:fs/promises";import{sep as i,join as c,resolve as a,dirname as f,extname as u,basename as p}from"node:path";import{spawn as l,spawnSync as h}from"node:child_process";import{fileURLToPath as d,pathToFileURL as w}from"node:url";import{readZip as m,Queue as g,Router as y,fileServer as $,staticContent as b,staticFileFinder as v,dynamicFileFinder as x,Negotiator as j,negotiateEncoding as k,zipFileFinder as E,requestHandler as S,addTeardown as O,getAbsolutePath as _,CONTINUE as N,proxy as M,assetServer as z,getSearch as A,getQuery as P,getPathParameter as J,WebListener as R,findCause as T,HTTPError as C,stringPredicate as B,compressFilesInDir as I,readMimeTypes as q,decompressMime as H,resetMime as U,registerMime as D}from"./index.js";import{text as G}from"node:stream/consumers";import{createServer as L}from"node:http";import{registerHooks as F}from"node:module";import{openSync as Z,constants as K,readSync as W,closeSync as Q}from"node:fs";import{inflateRawSync as V}from"node:zlib";const X=[];function Y(t){for(const e of X)if(t.startsWith(e.path)&&(t.length===e.path.length||t[e.path.length]===i)){const o=t.substring(e.path.length+1);return{...e,remaining:o?o.split(i):[]}}}async function tt(t,o){const n=Y(t);if(n)return n;const r=t.split(i);""===r[r.length-1]&&r.pop(),r[0]||(r.shift(),r.length>0&&(r[0]=i+r[0]));for(let t=r.length;t>0;--t){const n=c(...r.slice(0,t)),s=await e(n).catch(()=>null);if(!s)continue;if(!s.isFile())break;if(o&&t===r.length)return;const i={path:n,root:await m(n)};return X.push(i),{...i,remaining:r.slice(t)}}}async function et(e){const o=await tt(e,!0);if(o){const t=o.root.find(o.remaining);if(!t||t.isDirectory)throw new Error(`/${o.remaining.join("/")} not found in ${o.path}`);{const e=await t.open();try{return await G(e.createReadStream())}finally{await e.close()}}}return t(e,"utf-8")}function ot(t){const e=Y(t);return e?.root.find(e.remaining)}function nt(){X.length=0}const rt=new Map([["","dir"],["-a","host"],["-b","brotli"],["-c","config-file"],["-C","config-json"],["-d","dir"],["-e","ext"],["-g","gzip"],["-h","help"],["-H","header"],["-p","port"],["-P","proxy"],["-v","version"],["br","brotli"],["gz","gzip"],["zst","zstd"]]),st=new Map([["config-file",{type:"string"}],["config-json",{type:"string"}],["dir",{type:"string",multi:!0}],["exec",{type:"string",multi:!0}],["ext",{type:"string",multi:!0}],["port",{type:"number"}],["host",{type:"string"}],["zstd",{type:"boolean"}],["brotli",{type:"boolean"}],["gzip",{type:"boolean"}],["deflate",{type:"boolean"}],["proxy",{type:"string"}],["404",{type:"string"}],["spa",{type:"string"}],["header",{type:"string",multi:!0}],["dependencies",{type:"string"}],["mime",{type:"string",multi:!0}],["mime-types",{type:"string",multi:!0}],["redirect-map",{type:"string",multi:!0}],["write-compressed",{type:"boolean"}],["min-compress",{type:"number"}],["no-serve",{type:"boolean"}],["log",{type:"string"}],["help",{type:"boolean"}],["version",{type:"boolean"}]]);async function it(t,e,o){const n=new Map,r=async(t,e)=>{const o=await s(e.file,null);return e.includeMime&&(t.mime=[...ft(t.mime),...ft(o.mime)],o.mime=[]),e.includeBackgroundTasks&&(t.backgroundTasks.push(...o.backgroundTasks),o.backgroundTasks=[]),void 0!==e.serverPort?o.servers.filter(t=>t.port===e.serverPort):void 0!==e.serverIndex?e.serverIndex<0||e.serverIndex>=o.servers.length?[]:[o.servers[e.serverIndex]]:o.servers};async function s(t,e){const s=n.get(t);if(s){if(!0===s)throw new Error(`circular reference to ${t}`);return s}n.set(t,!0),null===e&&(e=await et(t));const i=o(JSON.parse(e),{file:t,path:""});for(let t=0;t<i.servers.length;){const e=i.servers[t];if(e.mount){for(let t=0;t<e.mount.length;++t){const o=e.mount[t];if("delegate"===o.type){const n=await r(i,o.config);if(1!==n.length)throw new Error(`${n.length>1?"multiple":"no"} servers found in ${o.config.file} matching requirements`);e.mount[t]={type:"nested",path:o.path,mount:n[0].mount}}}++t}else{const o=await r(i,e);if(!o)throw new Error(`no servers found in ${e.file} matching requirements`);i.servers.splice(t,1,...o),t+=o.length}}const c=i;return n.set(t,c),c}return s(a(e||"."),t)}function ct(t){const e=new Map;for(const[o,n=""]of t){const t=e.get(o);t?t.push(n):e.set(o,[n])}return Object.fromEntries(e.entries())}const at=new Map([["zstd",{value:"zstd",file:"{file}.zst"}],["brotli",{value:"br",file:"{file}.br"}],["gzip",{value:"gzip",file:"{file}.gz"}],["deflate",{value:"deflate",file:"{file}.deflate"}]]),ft=t=>Array.isArray(t)?t:t?[t]:[];const ut=t=>(e,o)=>{if(e!==t)throw new xt(`expected ${JSON.stringify(t)}`,o,8);return t},pt=t=>(e,o)=>{if(!t.has(e))throw new xt(`expected one of ${JSON.stringify(t)}`,o,7);return e},lt=t=>(e,o)=>{const n=[];let r=9;for(const s of t)try{return s(e,o)}catch(t){if(t instanceof xt){if(t.p>r)continue;t.p!==r&&(r=t.p,n.length=0)}else r=-1;n.push(t)}throw 1===n.length?n[0]:new AggregateError(n)},ht=(t,e)=>{if(null!==t)throw new xt("expected null, got "+typeof t,e);return null},dt=t=>(e,o)=>{if(!Array.isArray(e))throw new xt("expected list, got "+typeof e,o);return e.map((e,n)=>t(e,{...o,path:`${o.path}[${n}]`}))},wt=(t,e)=>{if("boolean"!=typeof t)throw new xt("expected boolean, got "+typeof t,e);return t},mt=(t,e,o)=>(n,r)=>{if("number"!=typeof n)throw new xt("expected number, got "+typeof n,r);if(t&&(0|n)!==n)throw new xt(`expected integer, got ${n}`,r);if("number"==typeof e&&n<e)throw new xt(`value cannot be less than ${e}`,r);if("number"==typeof o&&n>o)throw new xt(`value cannot be greater than ${o}`,r);return n},gt=()=>(t,e)=>{if("string"!=typeof t)throw new xt("expected string, got "+typeof t,e);try{return new RegExp(t)}catch{throw new xt("expected regular expression",e)}},yt=(t,e)=>(o,n)=>{if("string"!=typeof o)throw new xt("expected string, got "+typeof o,n);if(t&&!t.test(o))throw new xt(`expected string matching ${t}`,n);if("uri-reference"===e&&n.file){if(o.startsWith("file://"))return"file://"+a(f(n.file),o.substring(7));if(!o.includes("://"))return a(f(n.file),o)}return o},$t=(t,e,o)=>(n,r)=>{if("object"!=typeof n)throw new xt("expected object, got "+typeof n,r);if(!n)throw new xt("expected object, got null",r);if(Array.isArray(n))throw new xt("expected object, got list",r);const s=[],i=new Set;for(const[o,c]of Object.entries(n)){i.add(o);const n=(t.get(o)??e)(c,{...r,path:`${r.path}.${o}`});void 0!==n&&s.push([o,n])}for(const t of o)if(!i.has(t))throw new xt(`missing required property ${JSON.stringify(t)}`,r);for(const[e,o]of t)if(!i.has(e)){const t=o(void 0,{...r,path:`${r.path}.${e}`});void 0!==t&&s.push([e,t])}return Object.fromEntries(s)},bt=t=>t,vt=(t,e)=>{throw new xt("unknown property",e)};class xt extends Error{constructor(t,e,o=0){super(`${t} at ${e.path||"root"}`),this.p=o}}const jt=(t,e)=>Object.prototype.hasOwnProperty.call(t,e)?t[e]:void 0;class kt extends Error{}const Et=(t,e)=>Ot(t.imports??{},e),St=t=>t?t.startsWith("./")?t:"./"+t:void 0;function Ot(t,e){const o=new Map;for(const[n,r]of Object.entries(t)){const t=_t(r,e);void 0!==t&&o.set(n,t)}return o}function _t(t,e){if("string"==typeof t||null===t)return t;if(Array.isArray(t))for(const o of t){const t=_t(o,e);if(t)return t}else if(t)for(const[o,n]of Object.entries(t))if("default"===o||e.has(o)){const t=_t(n,e);if(t)return t}}const Nt=async(e,o=f(e))=>({isRoot:!1,id:e,dir:o,packageJson:JSON.parse(await t(e,{encoding:"utf-8"})),dependencies:new Map,getFilePaths:()=>(async t=>{const e=new Set,o=new g({t,o:"."});for(const t of o)for(const r of await n(t.t,{withFileTypes:!0,encoding:"utf-8"}))r.name.startsWith(".")||(r.isFile()?e.add(`${t.o}/${r.name}`):r.isDirectory()&&"node_modules"!==r.name&&o.push({t:c(t.t,r.name),o:`${t.o}/${r.name}`}));return e})(o)});async function Mt(t,e){const n=e&&w(e);try{return await Nt(d(import.meta.resolve(t+"/package.json",n)))}catch{}try{const e=await(async t=>{const e=new Set(["",i]);for(let n=await o(t,{encoding:"utf-8"});!e.has(n);n=f(n)){e.add(n);const t=c(n,"package.json");try{return await r(t,s.R_OK),await Nt(t)}catch{}}throw new Error(`package.json not found in ${t} or any parent folder`)})(f(d(import.meta.resolve(t,n))));if(e.packageJson.name===t)return e}catch{}return null}function zt(t,e,o,n){for(const[r,s]of e)t.set(o+r.substring(1),s?n+Tt(s.substring(1)):null)}function At(t){return Object.fromEntries([...t.entries()].filter(([t,e])=>null!==e).map(([t,e])=>[Tt(t),e]))}async function Pt(t,e,o,n){const r=new Map,s=[],i=[];for(const[e,c]of t){const t=e.indexOf("*"),a=c?.indexOf("*")??-1;if(!o(e)||null!==c&&(!n(c)||-1!==a!=(-1!==t)))throw new Error(`invalid entry: ${JSON.stringify(e)} => ${JSON.stringify(c)}`);if(-1!==t){const o=[e.length-1,e.substring(0,t),e.substring(t+1)],n=[t,e.length];c?s.push({i:o,u:[c.length-1,c.substring(0,a),c.substring(a+1)],l:n}):i.push({i:o,l:n})}else r.set(e,{u:c,l:[Number.POSITIVE_INFINITY,0]})}if(s.length){const t=await e();for(const e of t)for(const t of s){const o=Jt(t.u,e);if(!1!==o){const n=t.i[1]+o+t.i[2],s=r.get(n);(!s||Rt(t.l,s.l)>0)&&r.set(n,{u:e,l:t.l})}}}for(const t of i)for(const[e,o]of r)null!==o.u&&Rt(t.l,o.l)>0&&!1!==Jt(t.i,e)&&(o.u=null);return[...r].map(([t,e])=>[t,e.u])}const Jt=(t,e)=>!!(e.length>=t[0]&&e.startsWith(t[1])&&e.endsWith(t[2]))&&e.substring(t[1].length,e.length-t[2].length),Rt=(t,e)=>t[0]-e[0]||t[1]-e[1],Tt=t=>encodeURIComponent(t).replaceAll(/%2f/gi,"/").replaceAll(/%40/g,"@").replaceAll(/%23/g,"#");async function Ct(t,{environment:n=["browser","import","production"],mapFilePath:r="/importmap.json",sourcesBasePath:s="",modulesBasePath:i="/node_modules",...a}){const f=new y,u=await(async(t,e,o,n,r)=>{o.endsWith("/")&&(o=o.substring(0,o.length-1)),n.endsWith("/")&&(n=n.substring(0,n.length-1));const s=new Set,i=new Map,c=t.map(t=>{const e=r(t.packageJson,t.dir);let c=e;for(let t=2;s.has(c);++t)c=`${e}_${t}`;s.add(c);const a={h:t,m:[],$:t.isRoot?n:`${o}/${Tt(c)}`,v:t.isRoot?null:c};return i.set(t.id,a),a});await Promise.all(c.map(async t=>{t.m=await Pt(((t,e)=>Ot((t=>{const e=t.exports;if(void 0===e)return{".":{browser:St(t.browser),module:St(t.module),default:St(t.main)??"./index.js"},"./*":"./*"};if(Array.isArray(e)||"object"!=typeof e||!e)return{".":e};for(const t of Object.keys(e))if(t.startsWith("."))return e;return{".":e}})(t),e))(t.h.packageJson,e),async()=>t.j??=await t.h.getFilePaths(),t=>"."===t||t.startsWith("./"),t=>t.startsWith("./"))}));const a=[];let f=new Map;const u=[];for(const t of c){const o=new Map;t.h.packageJson.name&&t.h.packageJson.exports&&zt(o,t.m,t.h.packageJson.name,t.$);for(const[e,n]of t.h.dependencies){const t=i.get(n);if(!t)throw new Error("internal reference mismatch");zt(o,t.m,e,t.$)}const n=await Pt(Et(t.h.packageJson,e),async()=>(t.j??=await t.h.getFilePaths(),new Set([...o.keys(),...t.j])),t=>t.startsWith("#")&&t.length>1,t=>t.startsWith("./")||!t.startsWith("."));for(const[e,r]of n){if(!r){o.set(e,null);continue}const n=o.get(r);if(void 0!==n)o.set(e,n);else{if(!r.startsWith("./"))throw new Error(`unable to resolve import ${r}`);o.set(e,t.$+Tt(r.substring(1)))}}t.h.isRoot?f=o:u.push([t.$+"/",o]),a.push({dir:t.h.dir,subPath:t.v,imports:o})}const p=[];for(const[t,e]of u){const o=new Map(e);for(const[t,e]of f)o.get(t)===e&&o.delete(t);o.size&&p.push([t,At(o)])}return{packages:a,importMap:{imports:At(f),scopes:Object.fromEntries(p)}}})(await(async t=>{const n=await e(t);if(n.isDirectory())t=c(t,"package.json");else if(!n.isFile())throw new Error(`invalid package.json path: ${t}`);const r=await Nt(await o(t));r.isRoot=!0;const s=new Set([r.id]),i=[r];for(const t of i){const e=new Map;for(const o of Object.keys(t.packageJson.peerDependencies??{}))e.set(o,!1);for(const[o,n]of Object.entries(t.packageJson.peerDependenciesMeta??{}))e.has(o)&&e.set(o,n.optional??!1);for(const o of Object.keys(t.packageJson.optionalDependencies??{}))e.set(o,!0);for(const o of Object.keys(t.packageJson.dependencies??{}))e.set(o,!1);const o=c(t.dir,"a.js");await Promise.all([...e].map(async([e,n])=>{const r=await Mt(e,o);if(!r){if(n)return;throw new Error(`package ${e} not found (required by ${t.dir})`)}s.has(r.id)||(s.add(r.id),i.push(r)),t.dependencies.set(e,r.id)}))}return i})(t),new Set(n),i,s,Bt);for(const{dir:t,subPath:e}of u.packages)e&&f.mount("/"+e,await $(t,{...a,hide:[...a.hide??[],"node_modules"],indexFiles:[]}));const p=JSON.stringify(u.importMap);if(r){const t={headers:a.headers,encodings:["br","gzip"],minCompression:100};f.get(r,b(Buffer.from(p,"utf-8"),"application/importmap+json",t)),f.get(r+".js",b(Buffer.from(`const s=document.createElement('script');s.type='importmap';s.textContent=JSON.stringify(${p});document.head.append(s);`,"utf-8"),"text/javascript; charset=utf-8",t))}return Object.assign(f,{importMapJSON:p})}const Bt=t=>(t.name||"-")+(t.version?`@${t.version}`:""),It=new Map([[".mjs","module"],[".cjs","commonjs"],[".mts","module-typescript"],[".cts","commonjs-typescript"],[".json","json"],[".wasm","wasm"]]);F({resolve(t,e,o){if("web-listener"===t)t=c(f(d(import.meta.url)),"index.js");else{const o=URL.parse(t,e.parentURL);if(o&&"file:"===o.protocol&&ot(d(o)))return{url:o.toString(),format:It.get(u(o.pathname)),shortCircuit:!0}}return o(t,e)},load(t,e,o){if(t.startsWith("file://")){const e=d(t),o=ot(e);if(o&&!o.isDirectory)return{source:(t=>{const e=t.meta();if(!e.s)return Buffer.alloc(0);const o=Buffer.alloc(e.s),n=Z(t.zipFilePath,K.O_RDONLY);try{if(W(n,o,0,e.s,e.p)!==e.s)throw new Error("zip content has changed");return e.z?V(o,{maxOutputLength:t.stat().size}):o}finally{Q(n)}})(o),format:It.get(u(e))??"commonjs",shortCircuit:!0}}return o(t,e)}});const qt=new Set;async function Ht(t,e){qt.has(t)?e(`${t} has already been loaded into the module cache and will not be updated`):qt.add(t),await tt(t,!0);const o=await import(t),n=o?.default;if(!n||"function"!=typeof n&&"object"!=typeof n)throw new Error(`${t} must "export default" a request handler`);return n}async function Ut(t,o){const n=await e(t).catch(()=>null);if(n?.isDirectory())return"static-paths"===o.mode?v(t,o):x(t,o);const r=await tt(t,!1);if(!r)throw new kt(`content to serve not found at ${t}`);const s=r.root.find(r.remaining);if(!s?.isDirectory)throw new Error(`/${r.remaining.join("/")} in ${r.path} is not a directory`);const i=o;return i.negotiator||(i.negotiator=new j([k(["deflate"])])),E(s,i)}class Dt{constructor(t){this.k=t?t=>t:t=>t.toLowerCase(),this.S=new Map,this.O=[],this._=""}add(t,e){if("/"===t[0])this.S.set(this.k(t),e);else{if("~"!==t[0])throw new Error(`invalid URL: ${t}`);{const o="*"!==t[1],n=t.substring(o?1:2);this.O.push({N:new RegExp(n,o?"":"i"),u:e})}}}setDefault(t){this._=t}get(t){const e=this.S.get(this.k(t));if(void 0!==e)return e;for(const e of this.O){e.N.lastIndex=0;const o=e.N.exec(t);if(o)return e.u.replaceAll(/\$(?:([0-9]+)|([a-zA-Z][a-zA-Z0-9]*))/g,(t,e,n)=>e?o[Number.parseInt(e)]??"":o.groups&&Object.prototype.hasOwnProperty.call(o.groups,n)?o.groups[n]??"":"")}return this._}}function*Gt(t){let e=[];const o=/(\s+|#[^\n]*)|(;)|(?:"((?:[^"\\]+|\\.)*)")|(?:'((?:[^'\\]+|\\.)*)')|((?:[^#;\s\\"']+|\\.)+)/y;for(;o.lastIndex<t.length;){const n=o.exec(t);if(!n)throw new Error("invalid nginx syntax");const[,r,s,i,c,a]=n;if(!r)if(s)yield e,e=[];else if(a&&!a.includes("\\"))e.push({token:a,literal:!0});else{const t=i??c??a;if(void 0===t)throw new Error("nginx tokenisation error");e.push({token:t.replaceAll(/\\(.)/g,"$1"),literal:!1})}}if(e.length)throw new Error("unterminated statement - ensure all statements end with a semicolon")}const Lt=(t,e,o="raw")=>t.replaceAll(/\$\{(?:(raw|html|json|int|uri)\()?([^${}():]+)(?:(\))?:-((?:[^})\\]|\\.)*))?(\))?\}/g,(t,n,r,s,i,c)=>{if((s?1:0)+(c?1:0)!=(n?1:0))return t;const a=e(r),f=Ft[n??o];let u=a.M;return s&&u&&f&&(u=f(u)),u??=i?.replaceAll(/\\(.)/g,"$1")??"",c&&f&&(u=f(u)),!n&&f&&a.A!==o&&(u=f(u)),Zt(u)}),Ft={html:t=>Zt(t).replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#39;"),json:t=>JSON.stringify(Zt(t)),int:t=>{if(Array.isArray(t))return"0";const e=/^(?:\+|(-))?0*(\d+)$/.exec(t);return e?(e[1]??"")+e[2]:"0"},uri:t=>Array.isArray(t)?t.map(encodeURIComponent):encodeURIComponent(t)},Zt=t=>Array.isArray(t)?t.join("/"):t;async function Kt(t,e=()=>{},o){const n=new y;o&&n.use(S((t,e)=>{const n=Date.now();return O(t,()=>{const r=Date.now()-n;o({method:t.method??"GET",path:_(t),status:e.statusCode,duration:r})}),N}));for(const o of t)switch(o.type){case"nested":n.mount(o.path,await Kt(o.mount,e));break;case"headers":{const t=new Map(Object.entries(o.headers));n.mount(o.path,(e,o)=>(o.setHeaders(t),N));break}case"files":if("/dev/null"!==o.dir){const t=o.options.negotiation&&o.options.negotiation.length>0?new j(o.options.negotiation):void 0;n.mount(o.path,z(await Ut(o.dir,{...o.options,negotiator:t}),o.options))}break;case"proxy":n.mount(o.path,M(o.target,{...o.options,responseHeaders:[(t,e,n)=>({...n,...o.options.headers})]}));break;case"fixture":{const t=(t,e)=>{for(const[n,r]of Object.entries(o.headers))"string"==typeof r?e.setHeader(n,Lt(r,Wt(t))):"number"==typeof r?e.setHeader(n,r):e.setHeader(n,r.map(e=>Lt(e,Wt(t))));e.statusCode=o.status,e.end(Lt(o.body,Wt(t)))};"GET"===o.method&&n.onRequest("HEAD",o.path,t),n.onRequest(o.method,o.path,t);break}case"redirect":n.at(o.path,S((t,e)=>{let n=Lt(o.target,Wt(t),"uri");"/"===o.target[0]&&(n=n.replace(/^\/{2,}/,"/")),e.setHeader("location",n),e.statusCode=o.status,e.end()}));break;case"redirect-map":{const t=new Dt(o.options.caseSensitive);if("string"==typeof o.mapping){let e;try{e=await et(o.mapping)}catch(t){throw t&&"object"==typeof t&&"code"in t&&"ENOENT"===t.code?new kt(`redirect-map file not found at ${o.mapping}`):t}t:for(const o of Gt(e)){const e=o[0];if(e.literal)switch(e.token){case"default":if(2===o.length){t.setDefault(o[1].token);continue t}break;case"hostnames":throw new Error("redirect-map does not support hostnames");case"include":throw new Error("redirect-map does not support nested mapping files")}if(2!==o.length)throw new Error(`unknown statement in mapping file: ${o.map(t=>JSON.stringify(t)).join(" ")}`);t.add(e.token,o[1].token)}}else for(const[e,n]of Object.entries(o.mapping))t.add(e,n);n.use((e,n)=>{const r=t.get(e.url??"/");return r&&r!==(e.url??"/")?(n.setHeader("location",r),n.statusCode=o.status,n.end()):N});break}case"dependencies":n.mount(o.path,await Ct(o.package,{...o.options,modulesBasePath:o.path}));break;case"custom":{const t=await Ht(o.import,e);"string"==typeof o.method&&"get"===o.method.toLowerCase()?n.get(o.path,t):o.method?n.onRequest(o.method,o.path,t):n.mount(o.path,t);break}}return n}const Wt=t=>e=>"?"===e?{M:A(t)||void 0,A:"uri"}:"?"===e[0]?{M:P(t,e.substring(1)),A:"raw"}:{M:J(t,e),A:"raw"};class Qt{constructor(t,e){this.P=!1,this.J=!1,this.R=!1,this.T=t,this.C=e,this.B=new Map,this.I=new Set}async set(t,e,o){if(!this.J&&!this.R){clearTimeout(this.q),this.q=void 0;try{this.J=!0;const n=[],r=[];let s=!1;const i=this.I;this.I=new Set;t:for(let t=0;t<e.length;++t){const o=e[t];for(const t of i)if(te(t.config,o)){s||=t.isRunning(),this.I.add(t),i.delete(t);continue t}s=!0,r.push(async()=>{this.I.add(await this.H(o))})}for(const t of i)n.push(t.close);const c=new Set;for(let e=0;e<t.length;++e){const o=t[e],n=o.port;n<=0||n>65535?this.T(0,`servers[${e}] must have a specific port from 1 to 65535`):c.has(n)?this.T(0,`skipping servers[${e}] because port ${n} has already been defined`):(c.add(n),r.push(async()=>{const t=await this.U(o,this.B.get(n));t?this.B.set(n,t):this.B.delete(n)}))}this.P||=r.length>0;for(const[t,e]of this.B)c.has(t)||(r.push(e.close),this.B.delete(t));let a=!1;const f=async t=>{let e=[];if(await Promise.all(t.map(async t=>{try{await t()}catch(t){s&&!this.R&&t instanceof kt?(this.T(1,`${t.message} (retrying)`),a=!0):e.push(t)}})),e.length)throw await this.D(),e.length>1?new AggregateError(e):e[0]};await f(n),await f(r),this.R?this.D():a?this.q=setTimeout(()=>{nt(),this.set(t,e,o)},1e3):this.B.size?this.T(1,"all servers ready"):this.T(1,"no servers configured")}catch(t){o(t)}finally{this.J=!1}}}async H(t){const e=this.C("35",t.command),o=new AbortController;return new Promise((n,r)=>{this.T(2,`${e} ${this.C("2","starting")}`);let s=!0;const i=l(t.command,t.arguments,{cwd:t.cwd,env:{...process.env,TERM:"",COLORTERM:"",NO_COLOR:"1",...t.environment},killSignal:t.options.killSignal,uid:t.options.uid,gid:t.options.gid,stdio:["ignore","pipe","pipe"],signal:o.signal});t.options.displayStdout?Xt(i.stdout,`${e} ${this.C("2","[stdout]")} `,process.stderr):i.stdout.resume(),t.options.displayStderr?Xt(i.stderr,`${e} ${this.C("2","[stderr]")} `,process.stderr):i.stderr.resume(),i.addListener("error",t=>{this.T(0,`${e} startup failed: ${t.message}`),s=!1,r(t)}),i.addListener("exit",(t,o)=>{null!==t?this.T(2,`${e} closed ${this.C("2",`(exit code ${t})`)}`):this.T(2,`${e} closed ${this.C("2",`(exit signal ${o})`)}`),s=!1}),i.addListener("spawn",()=>n({config:t,isRunning:()=>s,close:()=>new Promise(o=>{null!==i.signalCode||null!==i.exitCode?o():(this.T(2,`${e} ${this.C("2",`closing (signal ${t.options.killSignal})`)}`),i.addListener("exit",o),i.kill(t.options.killSignal))})}))})}async U({port:t,host:e,options:o,mount:n},r){const s=this.C("34",`http://${e}:${t}`),i=await Kt(n,t=>this.T(1,`${s} ${this.C("33","warning")}: ${t}`),o.logRequests?t=>{const e=this.C("1",t.method.replaceAll(/[^a-zA-Z0-9\-_]/g,"?")),o=this.C(Vt[t.status/100|0]??"",String(t.status)),n=this.C("2",`(${t.duration}ms)`);this.T(0,`${s} ${e} ${t.path} ${o} ${n}`)}:void 0),c=new R(i);let a,f;if(c.addEventListener("error",t=>{t.preventDefault();const{error:e,context:o,request:n}=t.detail;(T(e,C)?.statusCode??500)>=500&&this.T(0,`${s} ${this.C("91","error")}: ${o} ${n?.url} ${e}`)}),r&&e===r.host&&((t,e)=>{for(const o of ee)if(t[o]!==e[o])return!1;return!0})(o,r.options))a=r.server,this.T(2,`${s} updated`),r.detach();else{if(r?(this.T(2,`${s} ${this.C("2","restarting (step 1: shutdown)")}`),await r.close(),this.T(2,`${s} ${this.C("2","restarting (step 2: start)")}`)):this.T(2,`${s} ${this.C("2","starting")}`),this.R)return;a=L(o),a.setTimeout(o.socketTimeout),f=Yt(a,t,e,o.backlog)}const u=c.attach(a,o);return f&&(await f,await new Promise(t=>setTimeout(t,1)),this.T(2,`${s} ready`)),{host:e,options:o,server:a,detach:()=>u("restart",o.restartTimeout),close:()=>new Promise(t=>{const e=u("shutdown",o.shutdownTimeout,!0,()=>{a.close(()=>{this.T(2,`${s} closed`),t()}),a.closeAllConnections()}).countConnections();e>0&&this.T(2,`${s} ${this.C("2",`closing (remaining connections: ${e})`)}`)})}}async D(){this.B.size&&(this.T(2,this.C("2","shutting down")),await Promise.all([...this.B.values(),...this.I].map(t=>t.close()))),this.P&&this.T(2,"shutdown complete")}shutdown(){this.R||(clearTimeout(this.q),this.q=void 0,this.R=!0,this.J||this.D())}}const Vt=["","37","32","36","31","41;97"];function Xt(t,e,o){let n="";const r=t=>o.write(e+t.replaceAll(/\x1b\[[\d;]*[A-K]/g,"").replaceAll(/[\x00-\x1f]/g,t=>`\\x${t.charCodeAt(0).toString(16).padStart(2,"0")}`)+"\n");t.addListener("data",t=>{n+=t;const e=n.split("\n");n=e.pop();for(const t of e)r(t)}),t.addListener("end",()=>{n&&r(n)})}const Yt=async(t,e,o,n=511)=>new Promise((r,s)=>{t.once("error",s),t.listen(e,o,n,()=>{t.off("error",s),r()})});function te(t,e){return t.command===e.command&&t.arguments.length===e.arguments.length&&t.arguments.every((t,o)=>t===e.arguments[o])&&t.cwd===e.cwd&&JSON.stringify(t.environment)===JSON.stringify(e.environment)&&t.options.uid===e.options.uid&&t.options.gid===e.options.gid&&t.options.killSignal===e.options.killSignal&&t.options.displayStdout===e.options.displayStdout&&t.options.displayStderr===e.options.displayStderr}const ee=["requestTimeout","keepAliveTimeout","keepAliveTimeoutBuffer","connectionsCheckingInterval","headersTimeout","highWaterMark","maxHeaderSize","noDelay","requireHostHeader","keepAlive","keepAliveInitialDelay","uniqueHeaders","backlog","socketTimeout"];function oe(t){return t.reduce((t,e)=>({rawSize:t.rawSize+e.rawSize,bestSize:t.bestSize+e.bestSize,created:t.created+e.created}),{rawSize:0,bestSize:0,created:0})}const ne=t=>t<2e3?`${t}B`.padStart(8," "):`${(t/1024).toFixed(1)}kB`.padStart(8," "),re=["none","ready","progress"];process.on("SIGUSR1",()=>{});let se=2;const ie=(t,e)=>t<=se&&process.stderr.write(e+"\n");function ce(t){process.stdin.destroy(),ie(0,t instanceof Error?t.message:String(t))}process.on("unhandledRejection",ce),process.on("uncaughtException",ce);const ae=process.stderr.isTTY&&!process.env.NO_COLOR?(t,e)=>t?`\x1b[${t}m${e}\x1b[0m`:e:(t,e)=>e,fe=(t=>{const e=[];for(let o=0;o<t.length;++o){const n=t[o];if("--"===n)continue;const r=/^--([^ =\-][^ =]*)=(.*)$/.exec(n);if(r){e.push([r[1],r[2]]);continue}const s=/^-([^ =]*)([^ =])=(.*)$/.exec(n);if(s&&"-"!==n[1]){for(const t of s[1])e.push(["-"+t,""]);e.push(["-"+s[2],s[3]]);continue}if("-"!==n[0]||"-"===n){if(0!==o)throw new Error(`value without key: ${n}`);e.push(["",n]);continue}let i=t[o+1];if(i&&"-"===i[0]&&i.length>1&&(i=void 0),void 0!==i&&++o,"-"===n[1])e.push([n.slice(2),i??""]);else{for(const t of n.slice(1,n.length-1))e.push(["-"+t,""]);e.push(["-"+n[n.length-1],i??""])}}const o=new Map;for(const[t,n]of e){const e=(rt.get(t)??t).toLowerCase(),r=st.get(e);if(!r)throw new Error(`unknown flag: ${t}`);let s;switch(r.type){case"string":s=n;break;case"number":s=Number.parseFloat(n);break;case"boolean":s=["","on","true","yes","y","1"].includes(n.toLowerCase())}if(r.multi){let t=o.get(e);t||(t=[],o.set(e,t)),t.push(s)}else{if(o.has(e))throw new Error(`multiple values for ${e}`);o.set(e,s)}}return o})(process.argv.slice(2)),ue=f(d(import.meta.url));if(fe.get("version")||fe.get("help")){let e={name:"web-listener",version:"unknown"};try{e=JSON.parse(await t(c(ue,"package.json"),"utf-8"))}catch{}fe.get("help")?h("man",["-M",ue,e.name],{stdio:["inherit","inherit","inherit"]}):process.stdout.write(`${e.name} ${e.version}\n`),process.exit(0)}(async()=>{const e=new Qt(ie,ae);process.on("unhandledRejection",()=>e.shutdown()),process.on("uncaughtException",()=>e.shutdown());const o=function(t){const e=o=>{const n=o.$ref;if(n&&n.startsWith("#/$defs/")){const e=jt(t.$defs,n.substring(8));if(!e)throw new Error(`unable to find ${n} in schema`);o={...e,...o}}const r=((t,e)=>{if(void 0!==t.const)return ut(t.const);if(t.enum)return pt(new Set(t.enum));if(t.anyOf)return lt(t.anyOf.map(e));switch(t.type){case"null":return ht;case"array":return dt(e(t.items));case"boolean":return wt;case"integer":return mt(!0,t.minimum,t.maximum);case"number":return mt(!1,t.minimum,t.maximum);case"object":const o=t.additionalProperties??!0,n=$t(new Map(Object.entries(t.properties??{}).map(([t,o])=>[t,e(o)])),"object"==typeof o?e(o):o?bt:vt,t.required??[]);if(t.$comment?.startsWith("flatten:")){const e=t.$comment.substring(8);return(t,o)=>n(t,o)[e]}return n;case"string":if("regex"===t.format)return gt();let r=null;return t.pattern&&(r=new RegExp(t.pattern)),yt(r,t.format??"");default:throw new Error(`unknown part type ${JSON.stringify(t)}`)}})(o,e);if(void 0!==o.default){const t=JSON.stringify(o.default);return(e,o)=>r(void 0===e?JSON.parse(t):e,o)}return(t,e)=>void 0===t?void 0:r(t,e)};return e(t)}(await(async()=>JSON.parse(await t(c(f(d(import.meta.url)),"schema.json"),"utf-8")))());function n(){process.stdin.destroy(),e.shutdown()}async function r(){nt();const t=await(async(t,e)=>{const o=(t,o=[])=>e.get(t)??o,n=t=>e.get(t),r=t=>e.get(t),s=n("config-file"),i=n("config-json"),c=r("port"),a=n("host"),f=o("dir",["."]),u=o("exec").map(t=>t.split(" ")),p=o("ext").map(t=>t.startsWith(".")?t:`.${t}`),l=o("header").map(t=>(t=>{const e=t.match(/: ?/);return e?[t.substring(0,e.index),t.substring(e.index+e[0].length)]:[t]})(t)),h=n("404"),d=n("spa"),w=n("proxy"),m=n("dependencies"),g=r("min-compress"),y=o("mime"),$=o("mime-types"),b=o("redirect-map"),v=n("log");if(Number(Boolean(s))+Number(Boolean(i))+Number(Boolean(w))>1)throw new Error("multiple config files are not supported");let x;if(s)x=await it(null,s,t);else if(i)x=await it(i,"",t);else{let e;d?e={statusCode:200,filePath:d}:h&&(e={statusCode:404,filePath:h});const o=[];for(let t=0;t<f.length;++t){const n=f[t],r=t===f.length-1;o.push({type:"files",dir:n,options:{fallback:r?e:void 0}})}w&&o.push({type:"proxy",target:w}),x=t({servers:[{port:8080,mount:o}]},{file:"",path:""})}for(const t of u)x.backgroundTasks.push({command:t[0],arguments:t.slice(1),cwd:process.cwd(),environment:{},options:{killSignal:"SIGTERM",displayStdout:!0,displayStderr:!0}});const j=1===x.servers.length?x.servers[0]:void 0;if(void 0!==c){if((0|c)!==c)throw new Error("port must be an integer");if(!j)throw new Error("cannot specify port on commandline when defining multiple servers");j.port=c}if(void 0!==a)for(const t of x.servers)t.host=a;if(b.length>0)for(const t of x.servers)for(const e of b)t.mount.unshift({type:"redirect-map",mapping:e,status:307,options:{caseSensitive:!1}});if(void 0!==m)for(const t of x.servers)t.mount.push({type:"dependencies",path:"/node_modules",package:m,options:{}});const k=(t,e)=>{for(const o of x.servers)for(const n of o.mount)if("files"===n.type){n.options.negotiation??=[];let o=n.options.negotiation.find(e=>e.feature===t);o||(o={feature:t,options:[]},n.options.negotiation=[...n.options.negotiation,o]),o.options.find(t=>t.value===e.value)||o.options.push(e)}};for(const[t,o]of at)e.get(t)&&k("encoding",o);if(p.length)for(const t of x.servers)for(const e of t.mount)"files"===e.type&&(e.options.implicitSuffixes=p);if(l.length){const t={type:"headers",path:"/",headers:ct(l)};for(const e of x.servers)e.mount.unshift(t)}switch((y.length||$.length)&&(x.mime=[...ft(x.mime),...y,...$.map(t=>`file://${t}`)]),e.get("write-compressed")&&(x.writeCompressed=!0),void 0!==g&&(x.minCompress=g),e.get("no-serve")&&(x.noServe=!0),v){case"none":case"ready":case"progress":x.log=v;for(const t of x.servers)t.options.logRequests=!1;for(const t of x.backgroundTasks)t.options.displayStderr=!1,t.options.displayStdout=!1;break;case"full":x.log="progress"}return x})(o,fe);se=re.indexOf(t.log),await(async t=>{const e=[];for(const o of Array.isArray(t)?t:[t])"string"!=typeof o?e.push(new Map(Object.entries(o))):o.startsWith("file://")?e.push(q(await et(o.substring(7)))):e.push(H(o));U();for(const t of e)D(t)})(t.mime),t.writeCompressed&&await(async(t,e,o)=>{let n=0;for(const r of t)for(const t of r.mount)if("files"===t.type){const r=t.options.negotiation?.find(t=>"encoding"===t.feature);if(!r?.options?.length){o(2,`skipping ${t.dir} because no compression is configured`);continue}const s=r.match?` matching ${r.match}`:"";o(2,`compressing files in ${t.dir}${s} using ${r.options.map(t=>t.value).join(", ")}`);const i=B(r.match,!0),c=await I(t.dir,r.options,{minCompression:e,filter:(t,e)=>!["image","video","audio","font"].includes(e.split("/")[0])&&i(p(t))}),a=oe(c.filter(({mime:t})=>t.startsWith("text/"))),f=oe(c.filter(({mime:t})=>!t.startsWith("text/")));o(2,`text: ${ne(a.rawSize)} / ${ne(a.bestSize)} compressed`),o(2,`other: ${ne(f.rawSize)} / ${ne(f.bestSize)} compressed`),n+=a.created+f.created}o(2,`${((t,e,o=e+"s")=>1===t?`1 ${e}`:`${t} ${o}`)(n,"compressed file")} written`)})(t.servers,t.minCompress,ie),t.noServe?n():e.set(t.servers,t.backgroundTasks,t=>{if(t instanceof AggregateError)for(const e of t.errors)ie(0,e instanceof Error?e.message:String(e));else ie(0,t instanceof Error?t.message:String(t));process.stdin.destroy(),process.exit(1)})}function s(){return ie(2,"refreshing config"),r()}r(),process.on("SIGHUP",()=>s()),process.stdin.on("data",t=>{t.includes("\n")&&s()});let i=!1;process.on("SIGINT",()=>{i||(i=!0,ie(2,""),n())})})();
2
+ import{readFile as t,stat as e,realpath as n,readdir as o,access as r,constants as s}from"node:fs/promises";import{sep as i,join as c,resolve as a,dirname as f,extname as u,basename as p}from"node:path";import{spawn as l,spawnSync as h}from"node:child_process";import{fileURLToPath as d,pathToFileURL as w}from"node:url";import{readZip as m,Queue as g,Router as y,fileServer as $,staticContent as b,staticFileFinder as v,dynamicFileFinder as x,Negotiator as j,negotiateEncoding as E,zipFileFinder as k,requestHandler as S,addTeardown as O,getAbsolutePath as _,CONTINUE as N,proxy as M,assetServer as z,getSearch as A,getQuery as P,getPathParameter as J,WebListener as R,findCause as T,HTTPError as C,stringPredicate as B,compressFilesInDir as I,readMimeTypes as q,decompressMime as H,resetMime as U,registerMime as D}from"./index.js";import{text as G}from"node:stream/consumers";import{createServer as L}from"node:http";import{registerHooks as F}from"node:module";import{openSync as Z,constants as K,readSync as W,closeSync as Q}from"node:fs";import{inflateRawSync as V}from"node:zlib";const X=[];function Y(t){for(const e of X)if(t.startsWith(e.path)&&(t.length===e.path.length||t[e.path.length]===i)){const n=t.substring(e.path.length+1);return{...e,remaining:n?n.split(i):[]}}}async function tt(t,n){const o=Y(t);if(o)return o;const r=t.split(i);""===r[r.length-1]&&r.pop(),r[0]||(r.shift(),r.length>0&&(r[0]=i+r[0]));for(let t=r.length;t>0;--t){const o=c(...r.slice(0,t)),s=await e(o).catch(()=>null);if(!s)continue;if(!s.isFile())break;if(n&&t===r.length)return;const i={path:o,root:await m(o)};return X.push(i),{...i,remaining:r.slice(t)}}}async function et(e){const n=await tt(e,!0);if(n){const t=n.root.find(n.remaining);if(!t||t.isDirectory)throw new Error(`/${n.remaining.join("/")} not found in ${n.path}`);{const e=await t.open();try{return await G(e.createReadStream())}finally{await e.close()}}}return t(e,"utf-8")}function nt(t){const e=Y(t);return e?.root.find(e.remaining)}function ot(){X.length=0}const rt=new Map([["","dir"],["-a","host"],["-b","brotli"],["-c","config-file"],["-C","config-json"],["-d","dir"],["-e","ext"],["-g","gzip"],["-h","help"],["-H","header"],["-p","port"],["-P","proxy"],["-v","version"],["br","brotli"],["gz","gzip"],["zst","zstd"]]),st=new Map([["config-file",{type:"string"}],["config-json",{type:"string"}],["dir",{type:"string",multi:!0}],["exec",{type:"string",multi:!0}],["ext",{type:"string",multi:!0}],["port",{type:"number"}],["host",{type:"string"}],["zstd",{type:"boolean"}],["brotli",{type:"boolean"}],["gzip",{type:"boolean"}],["deflate",{type:"boolean"}],["proxy",{type:"string"}],["404",{type:"string"}],["spa",{type:"string"}],["header",{type:"string",multi:!0}],["dependencies",{type:"string"}],["mime",{type:"string",multi:!0}],["mime-types",{type:"string",multi:!0}],["redirect-map",{type:"string",multi:!0}],["write-compressed",{type:"boolean"}],["min-compress",{type:"number"}],["no-serve",{type:"boolean"}],["log",{type:"string"}],["help",{type:"boolean"}],["version",{type:"boolean"}]]);async function it(t,e,n){const o=new Map,r=async(t,e)=>{const n=await s(e.file,null);return e.includeMime&&(t.mime=[...ft(t.mime),...ft(n.mime)],n.mime=[]),e.includeBackgroundTasks&&(t.backgroundTasks.push(...n.backgroundTasks),n.backgroundTasks=[]),void 0!==e.serverPort?n.servers.filter(t=>t.port===e.serverPort):void 0!==e.serverIndex?e.serverIndex<0||e.serverIndex>=n.servers.length?[]:[n.servers[e.serverIndex]]:n.servers};async function s(t,e){const s=o.get(t);if(s){if(!0===s)throw new Error(`circular reference to ${t}`);return s}o.set(t,!0),null===e&&(e=await et(t));const i=n(JSON.parse(e),{file:t,path:""});for(let t=0;t<i.servers.length;){const e=i.servers[t];if(e.mount){for(let t=0;t<e.mount.length;++t){const n=e.mount[t];if("delegate"===n.type){const o=await r(i,n.config);if(1!==o.length)throw new Error(`${o.length>1?"multiple":"no"} servers found in ${n.config.file} matching requirements`);e.mount[t]={type:"nested",path:n.path,mount:o[0].mount}}}++t}else{const n=await r(i,e);if(!n)throw new Error(`no servers found in ${e.file} matching requirements`);i.servers.splice(t,1,...n),t+=n.length}}const c=i;return o.set(t,c),c}return s(a(e||"."),t)}function ct(t){const e=new Map;for(const[n,o=""]of t){const t=e.get(n);t?t.push(o):e.set(n,[o])}return Object.fromEntries(e.entries())}const at=new Map([["zstd",{value:"zstd",file:"{file}.zst"}],["brotli",{value:"br",file:"{file}.br"}],["gzip",{value:"gzip",file:"{file}.gz"}],["deflate",{value:"deflate",file:"{file}.deflate"}]]),ft=t=>Array.isArray(t)?t:t?[t]:[];const ut=t=>(e,n)=>{if(e!==t)throw new xt(`expected ${JSON.stringify(t)}`,n,8);return t},pt=t=>(e,n)=>{if(!t.has(e))throw new xt(`expected one of ${JSON.stringify(t)}`,n,7);return e},lt=t=>(e,n)=>{const o=[];let r=9;for(const s of t)try{return s(e,n)}catch(t){if(t instanceof xt){if(t.p>r)continue;t.p!==r&&(r=t.p,o.length=0)}else r=-1;o.push(t)}throw 1===o.length?o[0]:new AggregateError(o)},ht=(t,e)=>{if(null!==t)throw new xt("expected null, got "+typeof t,e);return null},dt=t=>(e,n)=>{if(!Array.isArray(e))throw new xt("expected list, got "+typeof e,n);return e.map((e,o)=>t(e,{...n,path:`${n.path}[${o}]`}))},wt=(t,e)=>{if("boolean"!=typeof t)throw new xt("expected boolean, got "+typeof t,e);return t},mt=(t,e,n)=>(o,r)=>{if("number"!=typeof o)throw new xt("expected number, got "+typeof o,r);if(t&&(0|o)!==o)throw new xt(`expected integer, got ${o}`,r);if("number"==typeof e&&o<e)throw new xt(`value cannot be less than ${e}`,r);if("number"==typeof n&&o>n)throw new xt(`value cannot be greater than ${n}`,r);return o},gt=()=>(t,e)=>{if("string"!=typeof t)throw new xt("expected string, got "+typeof t,e);try{return new RegExp(t)}catch{throw new xt("expected regular expression",e)}},yt=(t,e)=>(n,o)=>{if("string"!=typeof n)throw new xt("expected string, got "+typeof n,o);if(t&&!t.test(n))throw new xt(`expected string matching ${t}`,o);if("uri-reference"===e&&o.file){if(n.startsWith("file://"))return"file://"+a(f(o.file),n.substring(7));if(!n.includes("://"))return a(f(o.file),n)}return n},$t=(t,e,n)=>(o,r)=>{if("object"!=typeof o)throw new xt("expected object, got "+typeof o,r);if(!o)throw new xt("expected object, got null",r);if(Array.isArray(o))throw new xt("expected object, got list",r);const s=[],i=new Set;for(const[n,c]of Object.entries(o)){i.add(n);const o=(t.get(n)??e)(c,{...r,path:`${r.path}.${n}`});void 0!==o&&s.push([n,o])}for(const t of n)if(!i.has(t))throw new xt(`missing required property ${JSON.stringify(t)}`,r);for(const[e,n]of t)if(!i.has(e)){const t=n(void 0,{...r,path:`${r.path}.${e}`});void 0!==t&&s.push([e,t])}return Object.fromEntries(s)},bt=t=>t,vt=(t,e)=>{throw new xt("unknown property",e)};class xt extends Error{constructor(t,e,n=0){super(`${t} at ${e.path||"root"}`),this.p=n}}const jt=(t,e)=>Object.prototype.hasOwnProperty.call(t,e)?t[e]:void 0;class Et extends Error{}const kt=(t,e)=>Ot(t.imports??{},e),St=t=>t?t.startsWith("./")?t:"./"+t:void 0;function Ot(t,e){const n=new Map;for(const[o,r]of Object.entries(t)){const t=_t(r,e);void 0!==t&&n.set(o,t)}return n}function _t(t,e){if("string"==typeof t||null===t)return t;if(Array.isArray(t))for(const n of t){const t=_t(n,e);if(t)return t}else if(t)for(const[n,o]of Object.entries(t))if("default"===n||e.has(n)){const t=_t(o,e);if(t)return t}}const Nt=async(e,n=f(e))=>({isRoot:!1,id:e,dir:n,packageJson:JSON.parse(await t(e,{encoding:"utf-8"})),dependencies:new Map,getFilePaths:()=>(async t=>{const e=new Set,n=new g({t,o:"."});for(const t of n)for(const r of await o(t.t,{withFileTypes:!0,encoding:"utf-8"}))r.name.startsWith(".")||(r.isFile()?e.add(`${t.o}/${r.name}`):r.isDirectory()&&"node_modules"!==r.name&&n.push({t:c(t.t,r.name),o:`${t.o}/${r.name}`}));return e})(n)});async function Mt(t,e){const o=e&&w(e);try{return await Nt(d(import.meta.resolve(t+"/package.json",o)))}catch{}try{const e=await(async t=>{const e=new Set(["",i]);for(let o=await n(t,{encoding:"utf-8"});!e.has(o);o=f(o)){e.add(o);const t=c(o,"package.json");try{return await r(t,s.R_OK),await Nt(t)}catch{}}throw new Error(`package.json not found in ${t} or any parent folder`)})(f(d(import.meta.resolve(t,o))));if(e.packageJson.name===t)return e}catch{}return null}function zt(t,e,n,o){for(const[r,s]of e)t.set(n+r.substring(1),s?o+Tt(s.substring(1)):null)}function At(t){return Object.fromEntries([...t.entries()].filter(([t,e])=>null!==e).map(([t,e])=>[Tt(t),e]))}async function Pt(t,e,n,o){const r=new Map,s=[],i=[];for(const[e,c]of t){const t=e.indexOf("*"),a=c?.indexOf("*")??-1;if(!n(e)||null!==c&&(!o(c)||-1!==a!=(-1!==t)))throw new Error(`invalid entry: ${JSON.stringify(e)} => ${JSON.stringify(c)}`);if(-1!==t){const n=[e.length-1,e.substring(0,t),e.substring(t+1)],o=[t,e.length];c?s.push({i:n,u:[c.length-1,c.substring(0,a),c.substring(a+1)],l:o}):i.push({i:n,l:o})}else r.set(e,{u:c,l:[Number.POSITIVE_INFINITY,0]})}if(s.length){const t=await e();for(const e of t)for(const t of s){const n=Jt(t.u,e);if(!1!==n){const o=t.i[1]+n+t.i[2],s=r.get(o);(!s||Rt(t.l,s.l)>0)&&r.set(o,{u:e,l:t.l})}}}for(const t of i)for(const[e,n]of r)null!==n.u&&Rt(t.l,n.l)>0&&!1!==Jt(t.i,e)&&(n.u=null);return[...r].map(([t,e])=>[t,e.u])}const Jt=(t,e)=>!!(e.length>=t[0]&&e.startsWith(t[1])&&e.endsWith(t[2]))&&e.substring(t[1].length,e.length-t[2].length),Rt=(t,e)=>t[0]-e[0]||t[1]-e[1],Tt=t=>encodeURIComponent(t).replaceAll(/%2f/gi,"/").replaceAll(/%40/g,"@").replaceAll(/%23/g,"#");async function Ct(t,{environment:o=["browser","import","production"],mapFilePath:r="/importmap.json",sourcesBasePath:s="",modulesBasePath:i="/node_modules",...a}){const f=new y,u=await(async(t,e,n,o,r)=>{n.endsWith("/")&&(n=n.substring(0,n.length-1)),o.endsWith("/")&&(o=o.substring(0,o.length-1));const s=new Set,i=new Map,c=t.map(t=>{const e=r(t.packageJson,t.dir);let c=e;for(let t=2;s.has(c);++t)c=`${e}_${t}`;s.add(c);const a={h:t,m:[],$:t.isRoot?o:`${n}/${Tt(c)}`,v:t.isRoot?null:c};return i.set(t.id,a),a});await Promise.all(c.map(async t=>{t.m=await Pt(((t,e)=>Ot((t=>{const e=t.exports;if(void 0===e)return{".":{browser:St(t.browser),module:St(t.module),default:St(t.main)??"./index.js"},"./*":"./*"};if(Array.isArray(e)||"object"!=typeof e||!e)return{".":e};for(const t of Object.keys(e))if(t.startsWith("."))return e;return{".":e}})(t),e))(t.h.packageJson,e),async()=>t.j??=await t.h.getFilePaths(),t=>"."===t||t.startsWith("./"),t=>t.startsWith("./"))}));const a=[];let f=new Map;const u=[];for(const t of c){const n=new Map;t.h.packageJson.name&&t.h.packageJson.exports&&zt(n,t.m,t.h.packageJson.name,t.$);for(const[e,o]of t.h.dependencies){const t=i.get(o);if(!t)throw new Error("internal reference mismatch");zt(n,t.m,e,t.$)}const o=await Pt(kt(t.h.packageJson,e),async()=>(t.j??=await t.h.getFilePaths(),new Set([...n.keys(),...t.j])),t=>t.startsWith("#")&&t.length>1,t=>t.startsWith("./")||!t.startsWith("."));for(const[e,r]of o){if(!r){n.set(e,null);continue}const o=n.get(r);if(void 0!==o)n.set(e,o);else{if(!r.startsWith("./"))throw new Error(`unable to resolve import ${r}`);n.set(e,t.$+Tt(r.substring(1)))}}t.h.isRoot?f=n:u.push([t.$+"/",n]),a.push({dir:t.h.dir,subPath:t.v,imports:n})}const p=[];for(const[t,e]of u){const n=new Map(e);for(const[t,e]of f)n.get(t)===e&&n.delete(t);n.size&&p.push([t,At(n)])}return{packages:a,importMap:{imports:At(f),scopes:Object.fromEntries(p)}}})(await(async t=>{const o=await e(t);if(o.isDirectory())t=c(t,"package.json");else if(!o.isFile())throw new Error(`invalid package.json path: ${t}`);const r=await Nt(await n(t));r.isRoot=!0;const s=new Set([r.id]),i=[r];for(const t of i){const e=new Map;for(const n of Object.keys(t.packageJson.peerDependencies??{}))e.set(n,!1);for(const[n,o]of Object.entries(t.packageJson.peerDependenciesMeta??{}))e.has(n)&&e.set(n,o.optional??!1);for(const n of Object.keys(t.packageJson.optionalDependencies??{}))e.set(n,!0);for(const n of Object.keys(t.packageJson.dependencies??{}))e.set(n,!1);const n=c(t.dir,"a.js");await Promise.all([...e].map(async([e,o])=>{const r=await Mt(e,n);if(!r){if(o)return;throw new Error(`package ${e} not found (required by ${t.dir})`)}s.has(r.id)||(s.add(r.id),i.push(r)),t.dependencies.set(e,r.id)}))}return i})(t),new Set(o),i,s,Bt);for(const{dir:t,subPath:e}of u.packages)e&&f.mount("/"+e,await $(t,{...a,hide:[...a.hide??[],"node_modules"],indexFiles:[]}));const p=JSON.stringify(u.importMap);if(r){const t={headers:a.headers,encodings:["br","gzip"],minCompression:100};f.get(r,b(Buffer.from(p,"utf-8"),"application/importmap+json",t)),f.get(r+".js",b(Buffer.from(`const s=document.createElement('script');s.type='importmap';s.textContent=JSON.stringify(${p});document.head.append(s);`,"utf-8"),"text/javascript; charset=utf-8",t))}return Object.assign(f,{importMapJSON:p})}const Bt=t=>(t.name||"-")+(t.version?`@${t.version}`:""),It=new Map([[".mjs","module"],[".cjs","commonjs"],[".mts","module-typescript"],[".cts","commonjs-typescript"],[".json","json"],[".wasm","wasm"]]);F({resolve(t,e,n){if("web-listener"===t)t=c(f(d(import.meta.url)),"index.js");else{const n=URL.parse(t,e.parentURL);if(n&&"file:"===n.protocol&&nt(d(n)))return{url:n.toString(),format:It.get(u(n.pathname)),shortCircuit:!0}}return n(t,e)},load(t,e,n){if(t.startsWith("file://")){const e=d(t),n=nt(e);if(n&&!n.isDirectory)return{source:(t=>{const e=t.meta();if(!e.s)return Buffer.alloc(0);const n=Buffer.alloc(e.s),o=Z(t.zipFilePath,K.O_RDONLY);try{if(W(o,n,0,e.s,e.p)!==e.s)throw new Error("zip content has changed");return e.z?V(n,{maxOutputLength:t.stat().size}):n}finally{Q(o)}})(n),format:It.get(u(e))??"commonjs",shortCircuit:!0}}return n(t,e)}});const qt=new Set;async function Ht(t,e){qt.has(t)?e(`${t} has already been loaded into the module cache and will not be updated`):qt.add(t),await tt(t,!0);const n=await import(t),o=n?.default;if(!o||"function"!=typeof o&&"object"!=typeof o)throw new Error(`${t} must "export default" a request handler`);return o}async function Ut(t,n){const o=await e(t).catch(()=>null);if(o?.isDirectory())return"static-paths"===n.mode?v(t,n):x(t,n);const r=await tt(t,!1);if(!r)throw new Et(`content to serve not found at ${t}`);const s=r.root.find(r.remaining);if(!s?.isDirectory)throw new Error(`/${r.remaining.join("/")} in ${r.path} is not a directory`);const i=n;return i.negotiator||(i.negotiator=new j([E(["deflate"])])),k(s,i)}class Dt{constructor(t){this.k=t?t=>t:t=>t.toLowerCase(),this.S=new Map,this.O=[],this._=""}add(t,e){if("/"===t[0])this.S.set(this.k(t),e);else{if("~"!==t[0])throw new Error(`invalid URL: ${t}`);{const n="*"!==t[1],o=t.substring(n?1:2);this.O.push({N:new RegExp(o,n?"":"i"),u:e})}}}setDefault(t){this._=t}get(t){const e=this.S.get(this.k(t));if(void 0!==e)return e;for(const e of this.O){e.N.lastIndex=0;const n=e.N.exec(t);if(n)return e.u.replaceAll(/\$(?:([0-9]+)|([a-zA-Z][a-zA-Z0-9]*))/g,(t,e,o)=>e?n[Number.parseInt(e)]??"":n.groups&&Object.prototype.hasOwnProperty.call(n.groups,o)?n.groups[o]??"":"")}return this._}}function*Gt(t){let e=[];const n=/(\s+|#[^\n]*)|(;)|(?:"((?:[^"\\]+|\\.)*)")|(?:'((?:[^'\\]+|\\.)*)')|((?:[^#;\s\\"']+|\\.)+)/y;for(;n.lastIndex<t.length;){const o=n.exec(t);if(!o)throw new Error("invalid nginx syntax");const[,r,s,i,c,a]=o;if(!r)if(s)yield e,e=[];else if(a&&!a.includes("\\"))e.push({token:a,literal:!0});else{const t=i??c??a;if(void 0===t)throw new Error("nginx tokenisation error");e.push({token:t.replaceAll(/\\(.)/g,"$1"),literal:!1})}}if(e.length)throw new Error("unterminated statement - ensure all statements end with a semicolon")}const Lt=(t,e,n="raw")=>t.replaceAll(/\$\{(?:(raw|html|json|int|uri)\()?([^${}():]+)(?:(\))?:-((?:[^})\\]|\\.)*))?(\))?\}/g,(t,o,r,s,i,c)=>{if((s?1:0)+(c?1:0)!=(o?1:0))return t;const a=e(r),f=Ft[o??n];let u=a.M;return s&&u&&f&&(u=f(u)),u??=i?.replaceAll(/\\(.)/g,"$1")??"",c&&f&&(u=f(u)),!o&&f&&a.A!==n&&(u=f(u)),Zt(u)}),Ft={html:t=>Zt(t).replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#39;"),json:t=>JSON.stringify(Zt(t)),int:t=>{if(Array.isArray(t))return"0";const e=/^(?:\+|(-))?0*(\d+)$/.exec(t);return e?(e[1]??"")+e[2]:"0"},uri:t=>Array.isArray(t)?t.map(encodeURIComponent):encodeURIComponent(t)},Zt=t=>Array.isArray(t)?t.join("/"):t;async function Kt(t,e=()=>{},n){const o=new y;n&&o.use(S((t,e)=>{const o=Date.now();return O(t,()=>{const r=Date.now()-o;n({method:t.method??"GET",path:_(t),status:e.statusCode,duration:r})}),N}));for(const n of t)switch(n.type){case"nested":o.mount(n.path,await Kt(n.mount,e));break;case"headers":{const t=new Map(Object.entries(n.headers));o.mount(n.path,(e,n)=>(n.setHeaders(t),N));break}case"files":if("/dev/null"!==n.dir){const t=n.options.negotiation&&n.options.negotiation.length>0?new j(n.options.negotiation):void 0;o.mount(n.path,z(await Ut(n.dir,{...n.options,negotiator:t}),n.options))}break;case"proxy":o.mount(n.path,M(n.target,{...n.options,responseHeaders:[(t,e,o)=>({...o,...n.options.headers})]}));break;case"fixture":{const t=(t,e)=>{for(const[o,r]of Object.entries(n.headers))"string"==typeof r?e.setHeader(o,Lt(r,Wt(t))):"number"==typeof r?e.setHeader(o,r):e.setHeader(o,r.map(e=>Lt(e,Wt(t))));e.statusCode=n.status,e.end(Lt(n.body,Wt(t)))};"GET"===n.method&&o.onRequest("HEAD",n.path,t),o.onRequest(n.method,n.path,t);break}case"redirect":o.at(n.path,S((t,e)=>{let o=Lt(n.target,Wt(t),"uri");"/"===n.target[0]&&(o=o.replace(/^\/{2,}/,"/")),e.setHeader("location",o),e.statusCode=n.status,e.end()}));break;case"redirect-map":{const t=new Dt(n.options.caseSensitive);if("string"==typeof n.mapping){let e;try{e=await et(n.mapping)}catch(t){throw t&&"object"==typeof t&&"code"in t&&"ENOENT"===t.code?new Et(`redirect-map file not found at ${n.mapping}`):t}t:for(const n of Gt(e)){const e=n[0];if(e.literal)switch(e.token){case"default":if(2===n.length){t.setDefault(n[1].token);continue t}break;case"hostnames":throw new Error("redirect-map does not support hostnames");case"include":throw new Error("redirect-map does not support nested mapping files")}if(2!==n.length)throw new Error(`unknown statement in mapping file: ${n.map(t=>JSON.stringify(t)).join(" ")}`);t.add(e.token,n[1].token)}}else for(const[e,o]of Object.entries(n.mapping))t.add(e,o);o.use((e,o)=>{const r=t.get(e.url??"/");return r&&r!==(e.url??"/")?(o.setHeader("location",r),o.statusCode=n.status,o.end()):N});break}case"dependencies":o.mount(n.path,await Ct(n.package,{...n.options,modulesBasePath:n.path}));break;case"custom":{const t=await Ht(n.import,e);"string"==typeof n.method&&"get"===n.method.toLowerCase()?o.get(n.path,t):n.method?o.onRequest(n.method,n.path,t):o.mount(n.path,t);break}}return o}const Wt=t=>e=>"?"===e?{M:A(t)||void 0,A:"uri"}:"?"===e[0]?{M:P(t,e.substring(1)),A:"raw"}:{M:J(t,e),A:"raw"};class Qt{constructor(t,e){this.P=!1,this.J=!1,this.R=!1,this.T=t,this.C=e,this.B=new Map,this.I=new Set}async set(t,e,n){if(!this.J&&!this.R){clearTimeout(this.q),this.q=void 0;try{this.J=!0;const o=[],r=[];let s=!1;const i=this.I;this.I=new Set;t:for(let t=0;t<e.length;++t){const n=e[t];for(const t of i)if(te(t.config,n)){s||=t.isRunning(),this.I.add(t),i.delete(t);continue t}s=!0,r.push(async()=>{this.I.add(await this.H(n))})}for(const t of i)o.push(t.close);const c=new Set;for(let e=0;e<t.length;++e){const n=t[e],o=n.port;o<=0||o>65535?this.T(0,`servers[${e}] must have a specific port from 1 to 65535`):c.has(o)?this.T(0,`skipping servers[${e}] because port ${o} has already been defined`):(c.add(o),r.push(async()=>{const t=await this.U(n,this.B.get(o));t?this.B.set(o,t):this.B.delete(o)}))}this.P||=r.length>0;for(const[t,e]of this.B)c.has(t)||(r.push(e.close),this.B.delete(t));let a=!1;const f=async t=>{let e=[];if(await Promise.all(t.map(async t=>{try{await t()}catch(t){s&&!this.R&&t instanceof Et?(this.T(1,`${t.message} (retrying)`),a=!0):e.push(t)}})),e.length)throw await this.D(),e.length>1?new AggregateError(e):e[0]};await f(o),await f(r),this.R?this.D():a?this.q=setTimeout(()=>{ot(),this.set(t,e,n)},1e3):this.B.size?this.T(1,"all servers ready"):this.T(1,"no servers configured")}catch(t){n(t)}finally{this.J=!1}}}async H(t){const e=this.C("35",t.command),n=new AbortController;return new Promise((o,r)=>{this.T(2,`${e} ${this.C("2","starting")}`);let s=!0;const i=l(t.command,t.arguments,{cwd:t.cwd,env:{...process.env,TERM:"",COLORTERM:"",NO_COLOR:"1",...t.environment},killSignal:t.options.killSignal,uid:t.options.uid,gid:t.options.gid,stdio:["ignore","pipe","pipe"],signal:n.signal});t.options.displayStdout?Xt(i.stdout,`${e} ${this.C("2","[stdout]")} `,process.stderr):i.stdout.resume(),t.options.displayStderr?Xt(i.stderr,`${e} ${this.C("2","[stderr]")} `,process.stderr):i.stderr.resume(),i.addListener("error",t=>{this.T(0,`${e} startup failed: ${t.message}`),s=!1,r(t)}),i.addListener("exit",(t,n)=>{null!==t?this.T(2,`${e} closed ${this.C("2",`(exit code ${t})`)}`):this.T(2,`${e} closed ${this.C("2",`(exit signal ${n})`)}`),s=!1}),i.addListener("spawn",()=>o({config:t,isRunning:()=>s,close:()=>new Promise(n=>{null!==i.signalCode||null!==i.exitCode?n():(this.T(2,`${e} ${this.C("2",`closing (signal ${t.options.killSignal})`)}`),i.addListener("exit",n),i.kill(t.options.killSignal))})}))})}async U({port:t,host:e,options:n,mount:o},r){const s=this.C("34",`http://${e}:${t}`),i=await Kt(o,t=>this.T(1,`${s} ${this.C("33","warning")}: ${t}`),n.logRequests?t=>{const e=this.C("1",t.method.replaceAll(/[^a-zA-Z0-9\-_]/g,"?")),n=this.C(Vt[t.status/100|0]??"",String(t.status)),o=this.C("2",`(${t.duration}ms)`);this.T(0,`${s} ${e} ${t.path} ${n} ${o}`)}:void 0),c=new R(i);let a,f;if(c.addEventListener("error",t=>{t.preventDefault();const{error:e,context:n,request:o}=t.detail;(T(e,C)?.statusCode??500)>=500&&this.T(0,`${s} ${this.C("91","error")}: ${n} ${o?.url} ${e}`)}),r&&e===r.host&&((t,e)=>{for(const n of ee)if(t[n]!==e[n])return!1;return!0})(n,r.options))a=r.server,this.T(2,`${s} updated`),r.detach();else{if(r?(this.T(2,`${s} ${this.C("2","restarting (step 1: shutdown)")}`),await r.close(),this.T(2,`${s} ${this.C("2","restarting (step 2: start)")}`)):this.T(2,`${s} ${this.C("2","starting")}`),this.R)return;a=L(n),a.setTimeout(n.socketTimeout),f=Yt(a,t,e,n.backlog)}const u=c.attach(a,n);return f&&(await f,await new Promise(t=>setTimeout(t,1)),this.T(2,`${s} ready`)),{host:e,options:n,server:a,detach:()=>u("restart",n.restartTimeout),close:()=>new Promise(t=>{const e=u("shutdown",n.shutdownTimeout,!0,()=>{a.close(()=>{this.T(2,`${s} closed`),t()}),a.closeAllConnections()}).countConnections();e>0&&this.T(2,`${s} ${this.C("2",`closing (remaining connections: ${e})`)}`)})}}async D(){this.B.size&&(this.T(2,this.C("2","shutting down")),await Promise.all([...this.B.values(),...this.I].map(t=>t.close()))),this.P&&this.T(2,"shutdown complete")}shutdown(){this.R||(clearTimeout(this.q),this.q=void 0,this.R=!0,this.J||this.D())}}const Vt=["","37","32","36","31","41;97"];function Xt(t,e,n){let o="";const r=t=>n.write(e+t.replaceAll(/\x1b\[[\d;]*[A-K]/g,"").replaceAll(/[\x00-\x1f]/g,t=>`\\x${t.charCodeAt(0).toString(16).padStart(2,"0")}`)+"\n");t.addListener("data",t=>{o+=t;const e=o.split("\n");o=e.pop();for(const t of e)r(t)}),t.addListener("end",()=>{o&&r(o)})}const Yt=async(t,e,n,o=511)=>new Promise((r,s)=>{t.once("error",s),t.listen(e,n,o,()=>{t.off("error",s),r()})});function te(t,e){return t.command===e.command&&t.arguments.length===e.arguments.length&&t.arguments.every((t,n)=>t===e.arguments[n])&&t.cwd===e.cwd&&JSON.stringify(t.environment)===JSON.stringify(e.environment)&&t.options.uid===e.options.uid&&t.options.gid===e.options.gid&&t.options.killSignal===e.options.killSignal&&t.options.displayStdout===e.options.displayStdout&&t.options.displayStderr===e.options.displayStderr}const ee=["requestTimeout","keepAliveTimeout","keepAliveTimeoutBuffer","connectionsCheckingInterval","headersTimeout","highWaterMark","maxHeaderSize","noDelay","requireHostHeader","keepAlive","keepAliveInitialDelay","uniqueHeaders","backlog","socketTimeout"];function ne(t){return t.reduce((t,e)=>({rawSize:t.rawSize+e.rawSize,bestSize:t.bestSize+e.bestSize,created:t.created+e.created}),{rawSize:0,bestSize:0,created:0})}const oe=t=>t<2e3?`${t}B`.padStart(8," "):`${(t/1024).toFixed(1)}kB`.padStart(8," "),re=["none","ready","progress"];process.on("SIGUSR1",()=>{});let se=2;const ie=(t,e)=>t<=se&&process.stderr.write(e+"\n");function ce(t){process.stdin.destroy(),ie(0,t instanceof Error?t.message:String(t))}process.on("unhandledRejection",ce),process.on("uncaughtException",ce);const ae=process.stderr.isTTY&&!process.env.NO_COLOR?(t,e)=>t?`\x1b[${t}m${e}\x1b[0m`:e:(t,e)=>e,fe=(t=>{const e=[];for(let n=0;n<t.length;++n){const o=t[n];if("--"===o)continue;const r=/^--([^ =\-][^ =]*)=(.*)$/.exec(o);if(r){e.push([r[1],r[2]]);continue}const s=/^-([^ =]*)([^ =])=(.*)$/.exec(o);if(s&&"-"!==o[1]){for(const t of s[1])e.push(["-"+t,""]);e.push(["-"+s[2],s[3]]);continue}if("-"!==o[0]||"-"===o){if(0!==n)throw new Error(`value without key: ${o}`);e.push(["",o]);continue}let i=t[n+1];if(i&&"-"===i[0]&&i.length>1&&(i=void 0),void 0!==i&&++n,"-"===o[1])e.push([o.slice(2),i??""]);else{for(const t of o.slice(1,o.length-1))e.push(["-"+t,""]);e.push(["-"+o[o.length-1],i??""])}}const n=new Map;for(const[t,o]of e){const e=(rt.get(t)??t).toLowerCase(),r=st.get(e);if(!r)throw new Error(`unknown flag: ${t}`);let s;switch(r.type){case"string":s=o;break;case"number":s=Number.parseFloat(o);break;case"boolean":s=["","on","true","yes","y","1"].includes(o.toLowerCase())}if(r.multi){let t=n.get(e);t||(t=[],n.set(e,t)),t.push(s)}else{if(n.has(e))throw new Error(`multiple values for ${e}`);n.set(e,s)}}return n})(process.argv.slice(2)),ue=f(d(import.meta.url));if(fe.get("version")||fe.get("help")){let e={name:"web-listener",version:"unknown"};try{e=JSON.parse(await t(c(ue,"package.json"),"utf-8"))}catch{}fe.get("help")?h("man",["-M",ue,e.name],{stdio:["inherit","inherit","inherit"]}):process.stdout.write(`${e.name} ${e.version}\n`),process.exit(0)}(async()=>{const e=new Qt(ie,ae);process.on("unhandledRejection",()=>e.shutdown()),process.on("uncaughtException",()=>e.shutdown());const n=function(t){const e=n=>{const o=n.$ref;if(o&&o.startsWith("#/$defs/")){const e=jt(t.$defs,o.substring(8));if(!e)throw new Error(`unable to find ${o} in schema`);n={...e,...n}}const r=((t,e)=>{if(void 0!==t.const)return ut(t.const);if(t.enum)return pt(new Set(t.enum));if(t.anyOf)return lt(t.anyOf.map(e));switch(t.type){case"null":return ht;case"array":return dt(e(t.items));case"boolean":return wt;case"integer":return mt(!0,t.minimum,t.maximum);case"number":return mt(!1,t.minimum,t.maximum);case"object":const n=t.additionalProperties??!0,o=$t(new Map(Object.entries(t.properties??{}).map(([t,n])=>[t,e(n)])),"object"==typeof n?e(n):n?bt:vt,t.required??[]);if(t.$comment?.startsWith("flatten:")){const e=t.$comment.substring(8);return(t,n)=>o(t,n)[e]}return o;case"string":if("regex"===t.format)return gt();let r=null;return t.pattern&&(r=new RegExp(t.pattern)),yt(r,t.format??"");default:throw new Error(`unknown part type ${JSON.stringify(t)}`)}})(n,e);if(void 0!==n.default){const t=JSON.stringify(n.default);return(e,n)=>r(void 0===e?JSON.parse(t):e,n)}return(t,e)=>void 0===t?void 0:r(t,e)};return e(t)}(await(async()=>JSON.parse(await t(c(f(d(import.meta.url)),"schema.json"),"utf-8")))());function o(){process.stdin.destroy(),e.shutdown()}async function r(){ot();const t=await(async(t,e)=>{const n=(t,n=[])=>e.get(t)??n,o=t=>e.get(t),r=t=>e.get(t),s=o("config-file"),i=o("config-json"),c=r("port"),a=o("host"),f=n("dir"),u=n("exec").map(t=>t.split(" ")),p=n("ext").map(t=>t.startsWith(".")?t:`.${t}`),l=n("header").map(t=>(t=>{const e=t.match(/: ?/);return e?[t.substring(0,e.index),t.substring(e.index+e[0].length)]:[t]})(t)),h=o("404"),d=o("spa"),w=o("proxy"),m=o("dependencies"),g=r("min-compress"),y=n("mime"),$=n("mime-types"),b=n("redirect-map"),v=o("log");if(Number(Boolean(s))+Number(Boolean(i))+Number(Boolean(w))>1)throw new Error("multiple config files are not supported");let x;s?x=await it(null,s,t):i?x=await it(i,"",t):(f.length||f.push("."),x=t({servers:[{port:8080,mount:[]}]},{file:"",path:""}));for(const t of u)x.backgroundTasks.push({command:t[0],arguments:t.slice(1),cwd:process.cwd(),environment:{},options:{killSignal:"SIGTERM",displayStdout:!0,displayStderr:!0}});const j=1===x.servers.length?x.servers[0]:void 0;if(void 0!==c){if((0|c)!==c)throw new Error("port must be an integer");if(!j)throw new Error("cannot specify port on commandline when defining multiple servers");j.port=c}if(void 0!==a)for(const t of x.servers)t.host=a;if(f.length||d||h){if(!j)throw new Error("cannot specify dir, spa, or 404 on commandline when defining multiple servers");let t;d?t={statusCode:200,filePath:d}:h&&(t={statusCode:404,filePath:h});for(let e=0;e<f.length;++e){const n=f[e],o=e===f.length-1;j.mount.push({type:"files",path:"/",dir:n,options:{fallback:o?t:void 0}})}}if(w){if(!j)throw new Error("cannot specify proxy on commandline when defining multiple servers");j.mount.push({type:"proxy",path:"/",target:w,options:{}})}if(b.length>0)for(const t of x.servers)for(const e of b)t.mount.unshift({type:"redirect-map",mapping:e,status:307,options:{caseSensitive:!1}});if(void 0!==m)for(const t of x.servers)t.mount.push({type:"dependencies",path:"/node_modules",package:m,options:{}});const E=(t,e)=>{for(const n of x.servers)for(const o of n.mount)if("files"===o.type){o.options.negotiation??=[];let n=o.options.negotiation.find(e=>e.feature===t);n||(n={feature:t,options:[]},o.options.negotiation=[...o.options.negotiation,n]),n.options.find(t=>t.value===e.value)||n.options.push(e)}};for(const[t,n]of at)e.get(t)&&E("encoding",n);if(p.length)for(const t of x.servers)for(const e of t.mount)"files"===e.type&&(e.options.implicitSuffixes=p);if(l.length){const t={type:"headers",path:"/",headers:ct(l)};for(const e of x.servers)e.mount.unshift(t)}switch((y.length||$.length)&&(x.mime=[...ft(x.mime),...y,...$.map(t=>`file://${t}`)]),e.get("write-compressed")&&(x.writeCompressed=!0),void 0!==g&&(x.minCompress=g),e.get("no-serve")&&(x.noServe=!0),v){case"none":case"ready":case"progress":x.log=v;for(const t of x.servers)t.options.logRequests=!1;for(const t of x.backgroundTasks)t.options.displayStderr=!1,t.options.displayStdout=!1;break;case"full":x.log="progress"}return x})(n,fe);se=re.indexOf(t.log),await(async t=>{const e=[];for(const n of Array.isArray(t)?t:[t])"string"!=typeof n?e.push(new Map(Object.entries(n))):n.startsWith("file://")?e.push(q(await et(n.substring(7)))):e.push(H(n));U();for(const t of e)D(t)})(t.mime),t.writeCompressed&&await(async(t,e,n)=>{let o=0;for(const r of t)for(const t of r.mount)if("files"===t.type){const r=t.options.negotiation?.find(t=>"encoding"===t.feature);if(!r?.options?.length){n(2,`skipping ${t.dir} because no compression is configured`);continue}const s=r.match?` matching ${r.match}`:"";n(2,`compressing files in ${t.dir}${s} using ${r.options.map(t=>t.value).join(", ")}`);const i=B(r.match,!0),c=await I(t.dir,r.options,{minCompression:e,filter:(t,e)=>!["image","video","audio","font"].includes(e.split("/")[0])&&i(p(t))}),a=ne(c.filter(({mime:t})=>t.startsWith("text/"))),f=ne(c.filter(({mime:t})=>!t.startsWith("text/")));n(2,`text: ${oe(a.rawSize)} / ${oe(a.bestSize)} compressed`),n(2,`other: ${oe(f.rawSize)} / ${oe(f.bestSize)} compressed`),o+=a.created+f.created}n(2,`${((t,e,n=e+"s")=>1===t?`1 ${e}`:`${t} ${n}`)(o,"compressed file")} written`)})(t.servers,t.minCompress,ie),t.noServe?o():e.set(t.servers,t.backgroundTasks,t=>{if(t instanceof AggregateError)for(const e of t.errors)ie(0,e instanceof Error?e.message:String(e));else ie(0,t instanceof Error?t.message:String(t));process.stdin.destroy(),process.exit(1)})}function s(){return ie(2,"refreshing config"),r()}r(),process.on("SIGHUP",()=>s()),process.stdin.on("data",t=>{t.includes("\n")&&s()});let i=!1;process.on("SIGINT",()=>{i||(i=!0,ie(2,""),o())})})();