fluxion-ts 0.12.0 → 0.13.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.
package/README.md CHANGED
@@ -26,6 +26,16 @@ Fluxion is a filesystem-routing dynamic server for Node.js.
26
26
  pnpm add fluxion
27
27
  ```
28
28
 
29
+ ## Command Line Interface
30
+
31
+ **You need [tsx](https://www.npmjs.com/package/tsx) to run fluxion**
32
+
33
+ ```bash
34
+ fluxion # loads fluxion.config.ts by default
35
+ fluxion --config custom-fluxion.config.ts
36
+
37
+ ```
38
+
29
39
  ## Quick Start
30
40
 
31
41
  Create `server.mjs`:
@@ -100,12 +110,12 @@ Fluxion registers files under `dir` based on glob patterns:
100
110
 
101
111
  Examples:
102
112
 
103
- | File | Route | Type |
104
- | --------------------------------------- | ------------------ | ----------- |
105
- | `dynamicDirectory/test.ts` | `/test.ts` | API handler |
106
- | `dynamicDirectory/user/profile.ts` | `/user/profile.ts` | API handler |
107
- | `dynamicDirectory/index.html` | `/index.html` | Static file |
108
- | `dynamicDirectory/assets/app.js` | `/assets/app.js` | Static file |
113
+ | File | Route | Type |
114
+ | ---------------------------------- | ------------------ | ----------- |
115
+ | `dynamicDirectory/test.ts` | `/test.ts` | API handler |
116
+ | `dynamicDirectory/user/profile.ts` | `/user/profile.ts` | API handler |
117
+ | `dynamicDirectory/index.html` | `/index.html` | Static file |
118
+ | `dynamicDirectory/assets/app.js` | `/assets/app.js` | Static file |
109
119
 
110
120
  ## API Handlers
111
121
 
package/dist/cli.cjs ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env tsx
2
+ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require("node:path");c=s(c);let l=require("node:cluster");l=s(l);let u=require("fast-json-stable-stringify");u=s(u);let d=require("node:fs");d=s(d);let f=require("node:os");f=s(f);let p=require("node:http");p=s(p);let m=require("node:https");m=s(m);let h=require("chokidar");h=s(h);let g=require("minimatch");function _(e){console.log(e),process.exit(0)}function v(e,t){let n=[`config`],r=[null,`status`,`stop`,`logs`];if(r.includes(e)||_(`Unknown command [${e}], please use one of [${r.join(`, `)}]`),t.forEach(e=>{n.includes(e.option)||_(`Unknown option [${e.option}], please use one of [${n.join(`, `)}]`)}),e===null){let e=t.find(e=>e.option===`config`)??{option:`config`,value:`fluxion.config.ts`};return(e.value===null||e.value.trim()===``)&&_(`Option [--config] requires a non-empty value`),{name:null,options:[{option:`config`,value:e.value}]}}if(e===`status`)return t.length!==0&&_(`Command [${e}] does not accept any options`),{name:`status`,options:[]};if(e===`stop`)return t.length!==0&&_(`Command [${e}] does not accept any options`),{name:`stop`,options:[]};if(e===`stop`)return t.length!==0&&_(`Command [${e}] does not accept any options`),{name:`logs`,options:[]};_(`Unknown command`)}function y(){let e=process.argv.slice(2),t=[],n=null;for(let r=0;r<e.length;r++){let i=e[r];if(i.startsWith(`--`)){let n=``,a=null;i.includes(`=`)?[n,a]=i.slice(2).split(`=`,2):(n=i.slice(2),a=e[r+1]??null,r++),t.some(e=>e.option===n)&&_(`Duplicate option [${n}]`),t.push({option:n,value:a});continue}n!==null&&_(`Already detect a command [${n}], but now got [${i}]`),n=i}return v(n,t)}function b(e=new Date){return`${e.getFullYear()}.${String(e.getMonth()+1).padStart(2,`0`)}.${String(e.getDate()).padStart(2,`0`)} ${String(e.getHours()).padStart(2,`0`)}:${String(e.getMinutes()).padStart(2,`0`)}:${String(e.getSeconds()).padStart(2,`0`)}.${String(e.getMilliseconds()).padStart(3,`0`)}`}const x=process.env.FLUXION_COLORS!==`0`;let S;(function(e){e.reset=x?`\x1B[0m`:``,e.bold=x?`\x1B[1m`:``,e.dim=x?`\x1B[2m`:``,e.italic=x?`\x1B[3m`:``,e.underline=x?`\x1B[4m`:``,e.blink=x?`\x1B[5m`:``,e.inverse=x?`\x1B[7m`:``,e.black=x?`\x1B[30m`:``,e.red=x?`\x1B[31m`:``,e.green=x?`\x1B[32m`:``,e.yellow=x?`\x1B[33m`:``,e.blue=x?`\x1B[34m`:``,e.magenta=x?`\x1B[35m`:``,e.cyan=x?`\x1B[36m`:``,e.white=x?`\x1B[37m`:``,e.brightBlack=x?`\x1B[90m`:``,e.brightRed=x?`\x1B[91m`:``,e.brightGreen=x?`\x1B[92m`:``,e.brightYellow=x?`\x1B[93m`:``,e.brightBlue=x?`\x1B[94m`:``,e.brightMagenta=x?`\x1B[95m`:``,e.brightCyan=x?`\x1B[96m`:``,e.brightWhite=x?`\x1B[97m`:``,e.bgBlack=x?`\x1B[40m`:``,e.bgRed=x?`\x1B[41m`:``,e.bgGreen=x?`\x1B[42m`:``,e.bgYellow=x?`\x1B[43m`:``,e.bgBlue=x?`\x1B[44m`:``,e.bgMagenta=x?`\x1B[45m`:``,e.bgCyan=x?`\x1B[46m`:``,e.bgWhite=x?`\x1B[47m`:``,e.bgBrightBlack=x?`\x1B[100m`:``,e.bgBrightRed=x?`\x1B[101m`:``,e.bgBrightGreen=x?`\x1B[102m`:``,e.bgBrightYellow=x?`\x1B[103m`:``,e.bgBrightBlue=x?`\x1B[104m`:``,e.bgBrightMagenta=x?`\x1B[105m`:``,e.bgBrightCyan=x?`\x1B[106m`:``,e.bgBrightWhite=x?`\x1B[107m`:``,e.purple=x?`\x1B[38;2;225;16;248m`:``,e.orange=x?`\x1B[38;2;248;147;16m`:``,e.darkGreen=x?`\x1B[38;2;22;101;52m`:``,e.claude=x?`\x1B[38;2;217;119;87m`:``,e.deepseek=x?`\x1B[38;2;57;100;254m`:``,e.gpt=x?`\x1B[38;2;41;60;77m`:``})(S||={});const C=e=>{try{return(0,u.default)(e)}catch{return`[unserializable]`}},ee={INFO:`${S.cyan}INFO${S.reset}`,WARN:`${S.orange}WARN${S.reset}`,ERROR:`${S.red}ERROR${S.reset}`,SUCC:`${S.green}SUCC${S.reset}`,DEBUG:`${S.blue}DEBUG${S.reset}`,VERBOSE:`${S.purple}VERBOSE${S.reset}`},te=e=>{let{level:t,timestamp:n,message:r,pid:i,...a}=e,o=`${S.darkGreen}[${n}]${S.reset}`,s=ee[t]??t,c=i===void 0?``:` [${i}]`,l=Object.keys(a).length>0?` ${S.dim}${C(a)}${S.reset}`:``;console.log(`${o} ${s}${c} ${r}${l}`)};function ne(e){let t=e.options.logger;return t===void 0||t===`one-line`?te:t===`json-line`?e=>console.log(C(e)):t}function re(e){let t=ne(e);return{write(e,n){let r=typeof n==`string`?{message:n,timestamp:b(),level:e}:{...n,timestamp:b(),level:e};try{t(r)}catch{}},info(e){this.write(`INFO`,e)},warn(e){this.write(`WARN`,e)},error(e){this.write(`ERROR`,e)},succ(e){this.write(`SUCC`,e)},debug(e){this.write(`DEBUG`,e)},verbose(e){this.write(`VERBOSE`,e)}}}function w(e,t){return{write(n,r){e.write(n,typeof r==`string`?{message:r,pid:t}:{...r,pid:t})},info(e){this.write(`INFO`,e)},warn(e){this.write(`WARN`,e)},error(e){this.write(`ERROR`,e)},succ(e){this.write(`SUCC`,e)},debug(e){this.write(`DEBUG`,e)},verbose(e){this.write(`VERBOSE`,e)}}}const T=typeof Error.isError==`function`?e=>Error.isError(e)?e.message:String(e):e=>e?.message||String(e),E=Symbol(`fluxion.router.StaticHandled`),D=Symbol(`fluxion.router.StaticHandled`),O=Symbol(`fluxion.handlerTimeout`),k=Symbol(`fluxion.middlewareTimeout`),A={".css":`text/css; charset=utf-8`,".html":`text/html; charset=utf-8`,".ico":`image/x-icon`,".js":`text/javascript; charset=utf-8`,".json":`application/json; charset=utf-8`,".map":`application/json; charset=utf-8`,".png":`image/png`,".jpg":`image/jpeg`,".jpeg":`image/jpeg`,".svg":`image/svg+xml`,".txt":`text/plain; charset=utf-8`,".webp":`image/webp`};function ie(e={}){let t=e.restartWhen??{},n=t.healthzTimeout??3e4;if(n!==1/0&&(!Number.isFinite(n)||n<1e4))throw Error(`[fluxion error] workerOptions.restartWhen.healthzTimeout must be a finite number >= 10000 (ms) or Infinity`);return{maxWorkerCount:e.maxWorkerCount??4,restartWhen:{memoryUsageGreaterThan:t.memoryUsageGreaterThan??1/0,healthzTimeout:n,uptimeGreaterThan:t.uptimeGreaterThan??1/0}}}function j(e,t){if(Buffer.isBuffer(e))return e;if(typeof e==`string`){if(!e.startsWith(`-----BEGIN`)){let n=c.default.isAbsolute(e)?e:c.default.join(t,e);if(d.default.existsSync(n))return d.default.readFileSync(n)}return Buffer.from(e)}throw Error(`[fluxion error] Certificate content must be a string or Buffer`)}function M(e,t){if(!e)return;if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`[fluxion error] FluxionOptions.https must be an object`);if(typeof e.key!=`string`)throw Error(`[fluxion error] FluxionOptions.https.key must be a string`);if(typeof e.cert!=`string`)throw Error(`[fluxion error] FluxionOptions.https.cert must be a string`);let n={key:j(e.key,t),cert:j(e.cert,t)};return e.ca!==void 0&&(Array.isArray(e.ca)?n.ca=e.ca.map(e=>j(e,t)):n.ca=j(e.ca,t)),n}function N(e){if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`[fluxion error] FluxionOptions must be an object`);let{dir:t,host:n,port:r,handlerTimeoutMs:i=5e3,middlewareTimeoutMs:a=3e3,staticResourceTimeoutMs:o=10*6e5,metaPort:s=r+1,moduleDir:l=process.cwd(),workerOptions:u={},maxRequestBytes:f=8e6,reloadDelay:p=500,include:m=[`**/*`],apiInclude:h=[`**/*.ts`],exclude:g=[`**/node_modules/**`,`**/.git/**`,`**/dist/**`,`**/build/**`,`**/.vscode/**`,`**/.idea/**`,`**/*.log`,`**/.DS_Store`,`**/coverage/**`,`**/.nyc_output/**`,`**/*.tmp`,`**/*.temp`],https:_,nativeWatcher:v=!1,metaSecret:y}=e,b=e.logger??`one-line`;if(b!==`one-line`&&b!==`json-line`&&typeof b!=`function`)throw Error(`[fluxion error] Invalid logger option, Must be 'one-line', 'json-line' or a custom logger function`);if(typeof t!=`string`)throw Error(`[fluxion error] FluxionOptions.dir must be a string`);let x=c.default.resolve(t);if(typeof l!=`string`)throw Error(`[fluxion error] FluxionOptions.moduleDir must be a string`);let S=c.default.resolve(l);if(typeof n!=`string`)throw Error(`[fluxion error] FluxionOptions.host must be a string`);if(!Number.isSafeInteger(i)||i<=100)throw Error(`[fluxion error] FluxionOptions.handlerTimeoutMs must be an integer greater than 100`);if(!Number.isSafeInteger(a)||a<=100)throw Error(`[fluxion error] FluxionOptions.middlewareTimeoutMs must be an integer greater than 100`);if(typeof p!=`number`||p<=0||!Number.isSafeInteger(p))throw Error(`[fluxion error] FluxionOptions.reloadDelay must be a positive integer`);if(p<50)throw Error(`[fluxion error] FluxionOptions.reloadDelay must be greater than or equal to 50`);if(typeof r!=`number`||!Number.isSafeInteger(r))throw Error(`[fluxion error] FluxionOptions.port must be a positive integer`);if(r<=1||r>65535)throw Error(`[fluxion error] FluxionOptions.port must be 1 ~ 65535`);if(typeof s!=`number`||!Number.isSafeInteger(s))throw Error(`[fluxion error] FluxionOptions.metaPort must be a positive integer`);if(s<=1||s>65535)throw Error(`[fluxion error] FluxionOptions.metaPort must be 1 ~ 65535`);if(s===r)throw Error(`[fluxion error] FluxionOptions.metaPort must be different from FluxionOptions.port`);if(typeof u!=`object`||!u||Array.isArray(u))throw Error(`[fluxion error] FluxionOptions.workerOptions must be an object`);if(typeof f!=`number`||f<=0||!Number.isSafeInteger(f))throw Error(`[fluxion error] FluxionOptions.maxRequestBytes must be a positive integer`);if(y!==void 0&&(typeof y!=`string`||y.length<20||/\s/.test(y)||!/[A-Za-z]/.test(y)||!/\d/.test(y)))throw Error(`[fluxion error] FluxionOptions.metaSecret must be a string with at least 20 characters, include both letters and digits, and contain no whitespace`);return d.default.existsSync(x)||d.default.mkdirSync(x,{recursive:!0}),{dir:x,host:n,port:r,handlerTimeoutMs:i,middlewareTimeoutMs:a,staticResourceTimeoutMs:o,reloadDelay:p,metaPort:s,moduleDir:S,workerOptions:ie(u),maxRequestBytes:f,logger:b,include:m,apiInclude:h,exclude:g,nativeWatcher:v,metaSecret:y,https:M(_,S),normalizedFlag:E}}const P=e=>[100,101].includes(e?.type),ae=e=>[202,200,201,203,204].includes(e?.type),F=e=>process.send?.(e),I=(e,t)=>e.send(t);function L(e,t,n=200){e.statusCode=n,e.setHeader(`Content-Type`,`application/json; charset=utf-8`),e.end(JSON.stringify(t))}function R(e,t,n=200){if(!e.writableEnded){if(e.headersSent){e.end();return}L(e,t,n)}}function oe(e,t,n){let r=p.default.createServer(async(r,i)=>{let a=r.method??`GET`,o;try{o=new URL(r.url??`/`,`http://fluxion.local`)}catch{L(i,{message:`Bad Request: invalid url`},400);return}if(a===`GET`&&o.pathname===`/_fluxion/healthz`){L(i,{ok:!0,role:`primary`,pid:process.pid,now:Date.now(),uptimeSeconds:Number(process.uptime().toFixed(3))});return}if(a===`GET`&&o.pathname===`/_fluxion/workers`){L(i,{ok:!0,now:Date.now(),workers:t()});return}if(a===`GET`&&o.pathname===`/_fluxion/routes`){if(!e.options.metaSecret){L(i,{message:`Not Found`},404);return}if(o.searchParams.get(`secret`)!==e.options.metaSecret){L(i,{message:`Forbidden`},403);return}let t=await n();L(i,{ok:!0,now:Date.now(),routes:t});return}L(i,{message:`Not Found`},404)});return r.on(`listening`,()=>{e.logger.info({message:`MetaApiStarted`,pid:process.pid,host:e.options.host,port:e.options.metaPort,prefix:`/_fluxion`})}),r.on(`error`,t=>{e.logger.error({message:`MetaApiError`,host:e.options.host,port:e.options.metaPort,code:t.code,error:T(t)}),process.exit(1)}),r.listen(e.options.metaPort,e.options.host),r}const z=e=>Number((e/1024/1024).toFixed(2)),B=6e4;function V(e){if(!l.default.isPrimary)throw Error(`[fluxion error] createPrimary should only be called in primary process`);let{workerOptions:t}=e.options,n=t.restartWhen,r=Math.max(1,f.default.cpus().length),i=Math.max(1,Math.min(t.maxWorkerCount??Math.min(2,r),r));e.logger.info({message:`PrimaryStarted`,pid:process.pid,workers:i,host:e.options.host,port:e.options.port,metaPort:e.options.metaPort});let a=new Map,o=new Map,s=0,c=new Map,u=e=>{let t=Date.now(),n=(c.get(e)??[]).filter(e=>t-e<B);return c.set(e,n),n.length},d=e=>{let t=Date.now(),n=(c.get(e)??[]).filter(e=>t-e<B);n.push(t),c.set(e,n)},p=e=>u(e)>=3;oe(e,()=>({primaryPid:process.pid,host:e.options.host,port:e.options.port,metaPort:e.options.metaPort,uptimeSeconds:Number(process.uptime().toFixed(3)),workers:Array.from(a.entries()).map(([e,t])=>{let{instance:n}=t,r=t.lastStats;return{workerId:e,slot:t.slot,pid:t.pid??n.process.pid??null,state:t.state,restartReason:t.restartReason??null,createdAt:t.createdAt,readyAt:t.readyAt??null,connected:n.isConnected(),dead:n.isDead(),exitedAfterDisconnect:n.exitedAfterDisconnect,lastPongAt:t.lastPongAt??null,lastRttMs:t.lastRttMs??null,stats:r===void 0?null:{at:r.at,uptimeSeconds:r.uptimeSeconds,cpu:r.cpu,memory:{...r.memory,rssMb:z(r.memory.rss),heapTotalMb:z(r.memory.heapTotal),heapUsedMb:z(r.memory.heapUsed),externalMb:z(r.memory.external),arrayBuffersMb:z(r.memory.arrayBuffers)}}}})}),()=>{let e=Array.from(a.values()).find(e=>e.state===`ready`&&e.instance.isConnected());return e?new Promise(t=>{let n=++s,r=setTimeout(()=>{o.delete(n),t([])},1e3);r.unref(),o.set(n,{resolve:t,timer:r});try{I(e.instance,{type:101,requestId:n})}catch{clearTimeout(r),o.delete(n),t([])}}):Promise.resolve([])});let m=(t,n)=>{for(let e of a.values())if(e.state===`restarting`)return;if(p(t.slot)){e.logger.warn({message:`WorkerRecycleSuppressed`,slot:t.slot,pid:t.pid,reason:n,windowMs:B,max:3});return}d(t.slot),t.state=`restarting`,t.restartReason=n,e.logger.warn({message:`WorkerRecycling`,slot:t.slot,pid:t.pid,reason:n}),t.instance.kill()},h=(e,t)=>{let r=z(t.memory.rss);if(r>n.memoryUsageGreaterThan){m(e,`memoryUsageGreaterThan: rss ${r}MB > ${n.memoryUsageGreaterThan}MB`);return}let i=t.uptimeSeconds*1e3;i>n.uptimeGreaterThan&&m(e,`uptimeGreaterThan: ${Math.round(i/1e3)}s > ${Math.round(n.uptimeGreaterThan/1e3)}s`)},g=e=>{for(let t of a.values()){if(t.state!==`ready`||t.lastPongAt===void 0)continue;let r=e-t.lastPongAt;r>n.healthzTimeout&&m(t,`healthzTimeout: no pong for ${Math.round(r/1e3)}s > ${Math.round(n.healthzTimeout/1e3)}s`)}},_=e=>{v(l.default.fork({WORKER_ID:String(e)}),e)},v=(t,n)=>{let r={state:`creating`,pid:t.process.pid,slot:n,createdAt:Date.now(),instance:t};a.set(t.id,r),t.on(`message`,i=>{if(ae(i)){if(i.type===202){let e=Date.now()-i.sentAt;r.pid=i.pid,r.lastPongAt=Date.now(),r.lastRttMs=e;return}if(i.type===201){r.state=`ready`,r.pid=i.pid,r.readyAt=Date.now(),e.logger.info({message:`WorkerReady`,workerId:t.id,slot:n,pid:i.pid});return}if(i.type===200){r.state=`created`,r.pid=i.pid,e.logger.info({message:`WorkerCreated`,workerId:t.id,slot:n,pid:i.pid});return}if(i.type===203){r.pid=i.pid,r.lastStats=i.stats,r.state===`ready`&&h(r,i.stats);return}if(i.type===204){let e=o.get(i.requestId);e&&(clearTimeout(e.timer),o.delete(i.requestId),e.resolve(i.routes))}}}),t.on(`exit`,(n,r)=>{let i=a.get(t.id);a.delete(t.id);let o=i?.slot,s=i?.state===`restarting`,c=i?.restartReason??null;if(e.logger.warn({message:`WorkerExited`,workerId:t.id,slot:o??null,pid:t.process.pid??`unknown`,code:n,signal:r??`none`,expected:s,reason:c}),o!==void 0){if(s){_(o);return}if(d(o),p(o)){e.logger.error({message:`WorkerRespawnSuppressed`,slot:o,windowMs:B,max:3});return}_(o)}})};for(let e=0;e<i;e++)_(e+1);setInterval(()=>{let e=Date.now();for(let t of a.values())if(t.instance.isConnected())try{I(t.instance,{type:100,sentAt:e})}catch{}g(Date.now())},5e3).unref()}function H(e,...t){return new Promise((n,r)=>{try{let i=e(...t);i instanceof Promise?i.then(n).catch(r):n(i)}catch(e){r(e)}})}function U(e){let t=e.headersDistinct[`x-forwarded-for`];if(t){let e=t[0]?.split(`,`)[0]?.trim();if(e&&e.length>0)return e}let n=e.headersDistinct[`x-real-ip`]?.[0].trim();return n===void 0?e.socket.remoteAddress??`unknown`:n}function W(e){if(e===void 0)return!1;let t=e.toLowerCase();return t.startsWith(`text/`)||t.includes(`json`)||t.includes(`xml`)||t.includes(`x-www-form-urlencoded`)||t.includes(`javascript`)}function G(e){if(e!==void 0)try{return new URL(e,`http://fluxion.local`)}catch{return}}function K(e){let t={};for(let[n,r]of e.entries()){let e=t[n];if(e===void 0){t[n]=r;continue}if(Array.isArray(e)){e.push(r);continue}t[n]=[e,r]}return t}var q=class extends Error{errno;code;constructor(e,t,n){super(e),this.name=`HttpException`,this.errno=t,this.code=n}},se=class extends q{constructor(e=`Payload Too Large`){super(e,413,`PAYLOAD_TOO_LARGE`)}};function J(e,t){return new se(`request body too large: ${e.toString()} bytes exceeds ${t.toString()} bytes`)}function Y(e){return Array.isArray(e)?e[0]:e}function X(){return{exists:!1,bytes:0,truncated:!1}}function ce(e,t,n,r){return t===0?X():W(n)?{exists:!0,value:e.toString(`utf8`),bytes:t,truncated:r}:{exists:!0,value:`<binary body: ${t} bytes>`,bytes:t,truncated:r}}async function le(e,t,n,r=8192){if(t===`GET`||t===`HEAD`||e.readableEnded)return{rawBody:void 0,preview:X()};let i=Y(e.headers[`content-length`]),a=i===void 0?NaN:Number.parseInt(i,10);return new Promise((t,i)=>{let o=[],s=[],c=0,l=0,u=!1,d=!1,f=()=>{e.off(`data`,m),e.off(`end`,h),e.off(`error`,g),e.off(`aborted`,_)},p=e=>{d||(d=!0,e())};if(Number.isFinite(a)&&a>n){f(),e.resume(),p(()=>i(J(a,n)));return}let m=t=>{let a=Buffer.isBuffer(t)?t:Buffer.from(t);if(c+=a.byteLength,c>n){f(),e.resume(),p(()=>i(J(c,n)));return}if(o.push(a),l<r){let e=r-l,t=a.subarray(0,e);s.push(t),l+=t.length,t.length<a.length&&(u=!0)}else u=!0},h=()=>{f(),p(()=>{let n=o.length>0?Buffer.concat(o):void 0;t({rawBody:n,preview:ce(s.length>0?Buffer.concat(s):Buffer.alloc(0),n?.byteLength??0,Y(e.headers[`content-type`]),u)})})},g=e=>{f(),p(()=>i(e))},_=()=>{f(),p(()=>i(Error(`request aborted while reading body`)))};e.on(`data`,m),e.once(`end`,h),e.once(`error`,g),e.once(`aborted`,_)})}async function ue(e,t,n){let{rawBody:r,preview:i}=await le(e,t,n);if(r===void 0||r.byteLength===0)return{body:{},preview:i};let a=Y(e.headers[`content-type`])?.toLowerCase()??``;if(a.includes(`json`)){let e=r.toString(`utf8`).trim();if(e.length===0)return{body:{},preview:i};try{let t=JSON.parse(e);return typeof t==`object`&&t&&!Array.isArray(t)?{body:t,preview:i}:{body:{value:t},preview:i}}catch{return{body:{raw:e},preview:i}}}return a.includes(`x-www-form-urlencoded`)?{body:K(new URLSearchParams(r.toString(`utf8`))),preview:i}:W(a)?{body:{raw:r.toString(`utf8`)},preview:i}:{body:{},preview:i}}function de(e){if(!e)return{};let t={},n=e.split(`;`);for(let e of n){let[n,...r]=e.split(`=`);if(!n)continue;let i=n.trim(),a=r.join(`=`).trim();t[i]=decodeURIComponent(a)}return t}const Z=(e,t,n)=>Promise.race([e,new Promise(e=>setTimeout(()=>e(n),t))]);function fe(e){let t=Object.freeze({logger:e.logger}),n=async(n,r)=>{let i=n.method??`GET`,a=U(n),o=G(n.url);if(o===void 0){R(r,{message:`Bad Request: req.url is undefined`},400);return}let s={method:i,ip:a,url:o,query:K(o.searchParams),body:{},headers:n.headers,cookie:de(n.headers.cookie),meta:{}},c={exists:!1,bytes:0,truncated:!1};e.logger.info({message:`request`,method:i,ip:a,path:o.pathname});let l=performance.now();r.once(`finish`,()=>{let t={workerId:process.env.WORKER_ID??`[primary]`,message:`response`,method:i,ip:a,path:o.pathname,status:r.statusCode,duration:(performance.now()-l).toFixed(4)};Object.keys(s.query).length>0&&(t.query=s.query),c.exists&&(t.body=c.value,t.bodyBytes=c.bytes,t.bodyTruncated=c.truncated),e.logger.info(t)});try{if(s.url.pathname.startsWith(`/_fluxion/`)){R(r,{message:`Not Found`},404);return}let i=await ue(n,s.method,e.options.maxRequestBytes);s.body=i.body,c=i.preview;let a=await e.router.getModule(o);if(!a){R(r,{message:`Not Found`},404);return}if(n.method&&a.methods&&!a.methods.includes(n.method)){R(r,{message:`Method Not Allowed`},405);return}let l=a.type===0?a.handlerTimeoutMs??e.options.handlerTimeoutMs:e.options.staticResourceTimeoutMs;if(a.middlewares)for(let i=0;i<a.middlewares.length;i++){if(await Z(H(a.middlewares[i],s,t,n,r),e.options.middlewareTimeoutMs,k)===k){e.logger.warn({message:`MiddlewareTimeout`,method:s.method,ip:s.ip}),R(r,{message:`Internal Server Error`},500);return}if(r.writableEnded)return;if(r.headersSent){r.end();return}}let u=await Z(H(a.handler,s,t,n,r),l,O);if(u===O){e.logger.warn({message:`HandlerTimeout`,method:s.method,ip:s.ip}),R(r,{message:`Handler timed out`},500);return}u!==D&&R(r,u)}catch(t){t instanceof q?(e.logger.error({message:`RequestFailed`,method:s.method,ip:s.ip,path:s.url.pathname,error:t.message}),R(r,{message:t.message},t.errno)):(e.logger.error({message:`RequestFailed`,method:s.method,ip:s.ip,path:s.url.pathname,error:T(t)}),R(r,{message:T(t)},t.errno??500))}},r=e.options.https?m.default.createServer({key:e.options.https.key,cert:e.options.https.cert,ca:e.options.https.ca},n):p.default.createServer(n);return new Promise((t,n)=>{let i=!1;r.on(`close`,()=>{e.logger.info({message:`ServerClosed`,host:e.options.host,port:e.options.port})}),r.once(`listening`,()=>{i=!0,e.logger.info({message:`ServerStarted`,pid:process.pid,protocol:e.options.https?`https`:`http`,host:e.options.host,port:e.options.port}),e.logger.info({message:`DynamicDirectory`,directory:e.options.dir}),t(r)}),r.on(`error`,t=>{e.logger.error({message:`ServerError`,error:T(t)}),i&&process.exit(1),n(t)}),r.listen(e.options.port,e.options.host)})}const pe=()=>{let e=process.cpuUsage(),t=Date.now();setInterval(()=>{let n=Date.now(),r=Math.max(1,(n-t)*1e3),i=process.cpuUsage(e),a=Number(((i.user+i.system)/r*100).toFixed(2));e=process.cpuUsage(),t=n;let o=process.memoryUsage();F({type:203,pid:process.pid,stats:{at:n,pid:process.pid,uptimeSeconds:Number(process.uptime().toFixed(3)),cpu:{userMicros:i.user,systemMicros:i.system,percent:a},memory:{rss:o.rss,heapTotal:o.heapTotal,heapUsed:o.heapUsed,external:o.external,arrayBuffers:o.arrayBuffers}}})},2e3).unref()};function me(e){if(l.default.isPrimary)throw Error(`[fluxion error] createWorker should only be called in worker process`);process.on(`message`,t=>{if(P(t)){if(t.type===100){F({type:202,pid:process.pid,sentAt:t.sentAt,receivedAt:Date.now()});return}t.type===101&&F({type:204,pid:process.pid,requestId:t.requestId,routes:e.router.getRoutes()})}}),F({type:200,pid:process.pid}),pe();let t,n=!1,r=r=>{n||(n=!0,e.logger.warn({message:`WorkerShuttingDown`,pid:process.pid,signal:r}),e.watcher.stop(),t||process.exit(0),setTimeout(()=>process.exit(1),1e4).unref(),t.close(t=>{t&&(e.logger.error({message:`WorkerShutdownFailed`,pid:process.pid,error:T(t)}),process.exit(1)),process.exit(0)}))};process.once(`SIGINT`,r),process.once(`SIGTERM`,r),fe(e).then(e=>{t=e,F({type:201,pid:process.pid})}).catch(t=>{e.logger.error({message:`WorkerBootstrapFailed`,pid:process.pid,error:T(t)}),e.watcher.stop(),process.exit(1)})}var Q=class{cx;timer=null;filesChanged=new Map;constructor(e){this.cx=e}async init(){let e=this.cx.options.dir;if(!d.default.existsSync(e))return this.cx.logger.warn(`Directory does not exist: ${e}`),this;let t=[],n=(e,r)=>{let i=d.default.readdirSync(e,{withFileTypes:!0});for(let a=0;a<i.length;a++){let o=i[a],s=c.default.join(e,o.name),l=c.default.join(r,o.name);if(o.isDirectory())n(s,l);else if(o.isFile()){let e=this.cx.router.register(s,l).catch(e=>{this.cx.logger.error(`Error registering file ${l}: ${e.message}`)});t.push(e)}}};return n(e,``),await Promise.all(t),this.cx.logger.info(`Initial registration complete for directory: ${e}`),this}queueUp(e,t){this.filesChanged.set(e,t),!this.timer&&(this.timer=setTimeout(async()=>{let e=[...this.filesChanged].map(([e,t])=>this.cx.router.register(e,t).catch(e=>this.cx.logger.error(`Error refreshing handlers: ${e.message}`)).finally(()=>this.filesChanged.delete(e)));await Promise.all(e),this.timer=null},this.cx.options.reloadDelay))}stopCore(){this.timer&&=(clearTimeout(this.timer),null),this.filesChanged.clear()}},he=class extends Q{watcher=null;constructor(e){super(e)}async start(){this.stop(),await this.init();let e=this.cx.options.dir;return this.watcher=h.default.watch(e,{persistent:!0,ignoreInitial:!0,usePolling:!1,awaitWriteFinish:{stabilityThreshold:100,pollInterval:50}}).on(`all`,(t,n)=>{n&&this.queueUp(n,c.default.relative(e,n))}).on(`error`,e=>{let t=e instanceof Error?e:Error(String(e));this.cx.logger.error(`Watcher error: ${t.message}`),this.cx.logger.error(`Restarting watcher...`),this.start()}).on(`ready`,()=>{this.cx.logger.info(`Watcher ready and watching directory: ${e}`)}),this.cx.logger.info(`Watcher started on directory: ${e}`),this}stop(){return this.watcher&&=(this.watcher.close(),null),this.stopCore(),this}},ge=class extends Q{watcher=null;constructor(e){super(e)}async start(){this.stop(),await this.init();let e=this.cx.options.dir;return this.watcher=d.default.watch(e,{recursive:!0},(t,n)=>{n&&this.queueUp(c.default.join(e,n),n)}).on(`error`,e=>{this.cx.logger.error(`Watcher error: ${e.message}`),this.cx.logger.error(`Restarting watcher...`),this.start()}),this.cx.logger.info(`Watcher started on directory: ${e}`),this}stop(){return this.watcher&&=(this.watcher.close(),null),this.stopCore(),this}};function _e(e){}const ve=_e;function $(e,t){if(typeof t!=`object`||!t)return!1;if(ve(t),typeof t.handler!=`function`)return e.logger.error(`handler must be a function`),!1;if(t.disposer!==void 0&&typeof t.disposer!=`function`)return e.logger.error(`disposer must be a function if provided`),!1;let n=t.handlerTimeoutMs;return n!==void 0&&(!Number.isSafeInteger(n)||n<100)?(e.logger.error(`handlerTimeoutMs must be an integer >= 100 if provided`),!1):t.type===0?!0:(e.logger.error(`You must use defineFluxionModule to create module`),!1)}function ye(e,t){delete require.cache[t];let n=require(t);if($(e,n.default))n=n.default;else if(!$(e,n))throw Error(`[fluxion error] Invalid handler module '${t}', make sure it satisfies defineFluxionModule(...) helper`);return n}var be=class{cx;handlers=new Map;constructor(e){this.cx=e}makeStaticResource(e){return{type:1,handler:async(t,n,r,i)=>{if(t.method!==`GET`&&t.method!==`HEAD`){i.statusCode=405,i.setHeader(`Allow`,`GET, HEAD`),i.end();return}if(!d.default.existsSync(e)){i.statusCode=404,i.end(`Not Found`);return}let a=d.default.statSync(e);if(!a.isFile()){i.statusCode=404,i.end(`Not Found`);return}let o=A[c.default.extname(e).toLowerCase()]??`application/octet-stream`;if(i.statusCode=200,i.setHeader(`Content-Type`,o),i.setHeader(`Content-Length`,String(a.size)),t.method===`HEAD`){i.end();return}return new Promise((t,n)=>{let a=d.default.createReadStream(e),o=()=>{a.off(`error`,s),a.off(`end`,c),i.off(`close`,l),r.off(`aborted`,l)},s=e=>{o(),n(e)},c=()=>{o(),t(D)},l=()=>{o(),a.destroy(),t(D)};a.on(`error`,s),a.on(`end`,c),i.on(`close`,l),r.on(`aborted`,l),a.pipe(i)})}}}async register(e,t){let n=this.handlers.get(t)?.disposer;if(n&&await H(n),!d.default.existsSync(e)){this.handlers.delete(t),this.cx.logger.info({action:`Delete`,url:t});return}if(!this.cx.options.include.some(e=>(0,g.minimatch)(t,e))){this.handlers.delete(t),this.cx.logger.info({action:`Skip`,url:t});return}if(this.cx.options.exclude.some(e=>(0,g.minimatch)(t,e))){this.handlers.delete(t),this.cx.logger.info({action:`Exclude`,url:t});return}if(this.cx.options.apiInclude.some(e=>(0,g.minimatch)(t,e))){let n=ye(this.cx,e);this.handlers.set(t,n),this.cx.logger.info({action:`RegisterApi`,url:t});return}this.handlers.set(t,this.makeStaticResource(e)),this.cx.logger.info({action:`RegisterStatic`,url:t})}getModule(e){let t=e.pathname.replace(/^[/]+/,``).replace(/[/]+$/,``);return this.handlers.get(t)}getRoutes(){return[...this.handlers.entries()].map(([e,t])=>({path:`/`+e,type:t.type===0?`api`:`static`,methods:t.methods?[...t.methods]:null})).sort((e,t)=>e.path.localeCompare(t.path))}};async function xe(e){let t={options:e.normalizedFlag===E?e:N(e)};t.logger=re(t),t.router=new be(t),l.default.isPrimary?V(t):(t.logger=w(t.logger,process.pid),t.watcher=await new(t.options.nativeWatcher?ge:he)(t).start(),me(t))}function Se(e){if(e.name===null){let t=e.options.find(e=>e.option===`config`)?.value??`fluxion.config.ts`;t=c.default.isAbsolute(t)?t:c.default.join(process.cwd(),t),xe(require(t).default)}}function Ce(){Se(y())}Ce();
package/dist/cli.mjs ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env tsx
2
+ import{createRequire as e}from"node:module";import t from"node:path";import n from"node:cluster";import r from"fast-json-stable-stringify";import i from"node:fs";import a from"node:os";import o from"node:http";import s from"node:https";import c from"chokidar";import{minimatch as l}from"minimatch";var u=e(import.meta.url);function d(e){console.log(e),process.exit(0)}function f(e,t){let n=[`config`],r=[null,`status`,`stop`,`logs`];if(r.includes(e)||d(`Unknown command [${e}], please use one of [${r.join(`, `)}]`),t.forEach(e=>{n.includes(e.option)||d(`Unknown option [${e.option}], please use one of [${n.join(`, `)}]`)}),e===null){let e=t.find(e=>e.option===`config`)??{option:`config`,value:`fluxion.config.ts`};return(e.value===null||e.value.trim()===``)&&d(`Option [--config] requires a non-empty value`),{name:null,options:[{option:`config`,value:e.value}]}}if(e===`status`)return t.length!==0&&d(`Command [${e}] does not accept any options`),{name:`status`,options:[]};if(e===`stop`)return t.length!==0&&d(`Command [${e}] does not accept any options`),{name:`stop`,options:[]};if(e===`stop`)return t.length!==0&&d(`Command [${e}] does not accept any options`),{name:`logs`,options:[]};d(`Unknown command`)}function p(){let e=process.argv.slice(2),t=[],n=null;for(let r=0;r<e.length;r++){let i=e[r];if(i.startsWith(`--`)){let n=``,a=null;i.includes(`=`)?[n,a]=i.slice(2).split(`=`,2):(n=i.slice(2),a=e[r+1]??null,r++),t.some(e=>e.option===n)&&d(`Duplicate option [${n}]`),t.push({option:n,value:a});continue}n!==null&&d(`Already detect a command [${n}], but now got [${i}]`),n=i}return f(n,t)}function m(e=new Date){return`${e.getFullYear()}.${String(e.getMonth()+1).padStart(2,`0`)}.${String(e.getDate()).padStart(2,`0`)} ${String(e.getHours()).padStart(2,`0`)}:${String(e.getMinutes()).padStart(2,`0`)}:${String(e.getSeconds()).padStart(2,`0`)}.${String(e.getMilliseconds()).padStart(3,`0`)}`}const h=process.env.FLUXION_COLORS!==`0`;let g;(function(e){e.reset=h?`\x1B[0m`:``,e.bold=h?`\x1B[1m`:``,e.dim=h?`\x1B[2m`:``,e.italic=h?`\x1B[3m`:``,e.underline=h?`\x1B[4m`:``,e.blink=h?`\x1B[5m`:``,e.inverse=h?`\x1B[7m`:``,e.black=h?`\x1B[30m`:``,e.red=h?`\x1B[31m`:``,e.green=h?`\x1B[32m`:``,e.yellow=h?`\x1B[33m`:``,e.blue=h?`\x1B[34m`:``,e.magenta=h?`\x1B[35m`:``,e.cyan=h?`\x1B[36m`:``,e.white=h?`\x1B[37m`:``,e.brightBlack=h?`\x1B[90m`:``,e.brightRed=h?`\x1B[91m`:``,e.brightGreen=h?`\x1B[92m`:``,e.brightYellow=h?`\x1B[93m`:``,e.brightBlue=h?`\x1B[94m`:``,e.brightMagenta=h?`\x1B[95m`:``,e.brightCyan=h?`\x1B[96m`:``,e.brightWhite=h?`\x1B[97m`:``,e.bgBlack=h?`\x1B[40m`:``,e.bgRed=h?`\x1B[41m`:``,e.bgGreen=h?`\x1B[42m`:``,e.bgYellow=h?`\x1B[43m`:``,e.bgBlue=h?`\x1B[44m`:``,e.bgMagenta=h?`\x1B[45m`:``,e.bgCyan=h?`\x1B[46m`:``,e.bgWhite=h?`\x1B[47m`:``,e.bgBrightBlack=h?`\x1B[100m`:``,e.bgBrightRed=h?`\x1B[101m`:``,e.bgBrightGreen=h?`\x1B[102m`:``,e.bgBrightYellow=h?`\x1B[103m`:``,e.bgBrightBlue=h?`\x1B[104m`:``,e.bgBrightMagenta=h?`\x1B[105m`:``,e.bgBrightCyan=h?`\x1B[106m`:``,e.bgBrightWhite=h?`\x1B[107m`:``,e.purple=h?`\x1B[38;2;225;16;248m`:``,e.orange=h?`\x1B[38;2;248;147;16m`:``,e.darkGreen=h?`\x1B[38;2;22;101;52m`:``,e.claude=h?`\x1B[38;2;217;119;87m`:``,e.deepseek=h?`\x1B[38;2;57;100;254m`:``,e.gpt=h?`\x1B[38;2;41;60;77m`:``})(g||={});const _=e=>{try{return r(e)}catch{return`[unserializable]`}},v={INFO:`${g.cyan}INFO${g.reset}`,WARN:`${g.orange}WARN${g.reset}`,ERROR:`${g.red}ERROR${g.reset}`,SUCC:`${g.green}SUCC${g.reset}`,DEBUG:`${g.blue}DEBUG${g.reset}`,VERBOSE:`${g.purple}VERBOSE${g.reset}`},y=e=>{let{level:t,timestamp:n,message:r,pid:i,...a}=e,o=`${g.darkGreen}[${n}]${g.reset}`,s=v[t]??t,c=i===void 0?``:` [${i}]`,l=Object.keys(a).length>0?` ${g.dim}${_(a)}${g.reset}`:``;console.log(`${o} ${s}${c} ${r}${l}`)};function b(e){let t=e.options.logger;return t===void 0||t===`one-line`?y:t===`json-line`?e=>console.log(_(e)):t}function x(e){let t=b(e);return{write(e,n){let r=typeof n==`string`?{message:n,timestamp:m(),level:e}:{...n,timestamp:m(),level:e};try{t(r)}catch{}},info(e){this.write(`INFO`,e)},warn(e){this.write(`WARN`,e)},error(e){this.write(`ERROR`,e)},succ(e){this.write(`SUCC`,e)},debug(e){this.write(`DEBUG`,e)},verbose(e){this.write(`VERBOSE`,e)}}}function S(e,t){return{write(n,r){e.write(n,typeof r==`string`?{message:r,pid:t}:{...r,pid:t})},info(e){this.write(`INFO`,e)},warn(e){this.write(`WARN`,e)},error(e){this.write(`ERROR`,e)},succ(e){this.write(`SUCC`,e)},debug(e){this.write(`DEBUG`,e)},verbose(e){this.write(`VERBOSE`,e)}}}const C=typeof Error.isError==`function`?e=>Error.isError(e)?e.message:String(e):e=>e?.message||String(e),w=Symbol(`fluxion.router.StaticHandled`),T=Symbol(`fluxion.router.StaticHandled`),E=Symbol(`fluxion.handlerTimeout`),D=Symbol(`fluxion.middlewareTimeout`),ee={".css":`text/css; charset=utf-8`,".html":`text/html; charset=utf-8`,".ico":`image/x-icon`,".js":`text/javascript; charset=utf-8`,".json":`application/json; charset=utf-8`,".map":`application/json; charset=utf-8`,".png":`image/png`,".jpg":`image/jpeg`,".jpeg":`image/jpeg`,".svg":`image/svg+xml`,".txt":`text/plain; charset=utf-8`,".webp":`image/webp`};function O(e={}){let t=e.restartWhen??{},n=t.healthzTimeout??3e4;if(n!==1/0&&(!Number.isFinite(n)||n<1e4))throw Error(`[fluxion error] workerOptions.restartWhen.healthzTimeout must be a finite number >= 10000 (ms) or Infinity`);return{maxWorkerCount:e.maxWorkerCount??4,restartWhen:{memoryUsageGreaterThan:t.memoryUsageGreaterThan??1/0,healthzTimeout:n,uptimeGreaterThan:t.uptimeGreaterThan??1/0}}}function k(e,n){if(Buffer.isBuffer(e))return e;if(typeof e==`string`){if(!e.startsWith(`-----BEGIN`)){let r=t.isAbsolute(e)?e:t.join(n,e);if(i.existsSync(r))return i.readFileSync(r)}return Buffer.from(e)}throw Error(`[fluxion error] Certificate content must be a string or Buffer`)}function A(e,t){if(!e)return;if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`[fluxion error] FluxionOptions.https must be an object`);if(typeof e.key!=`string`)throw Error(`[fluxion error] FluxionOptions.https.key must be a string`);if(typeof e.cert!=`string`)throw Error(`[fluxion error] FluxionOptions.https.cert must be a string`);let n={key:k(e.key,t),cert:k(e.cert,t)};return e.ca!==void 0&&(Array.isArray(e.ca)?n.ca=e.ca.map(e=>k(e,t)):n.ca=k(e.ca,t)),n}function j(e){if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`[fluxion error] FluxionOptions must be an object`);let{dir:n,host:r,port:a,handlerTimeoutMs:o=5e3,middlewareTimeoutMs:s=3e3,staticResourceTimeoutMs:c=10*6e5,metaPort:l=a+1,moduleDir:u=process.cwd(),workerOptions:d={},maxRequestBytes:f=8e6,reloadDelay:p=500,include:m=[`**/*`],apiInclude:h=[`**/*.ts`],exclude:g=[`**/node_modules/**`,`**/.git/**`,`**/dist/**`,`**/build/**`,`**/.vscode/**`,`**/.idea/**`,`**/*.log`,`**/.DS_Store`,`**/coverage/**`,`**/.nyc_output/**`,`**/*.tmp`,`**/*.temp`],https:_,nativeWatcher:v=!1,metaSecret:y}=e,b=e.logger??`one-line`;if(b!==`one-line`&&b!==`json-line`&&typeof b!=`function`)throw Error(`[fluxion error] Invalid logger option, Must be 'one-line', 'json-line' or a custom logger function`);if(typeof n!=`string`)throw Error(`[fluxion error] FluxionOptions.dir must be a string`);let x=t.resolve(n);if(typeof u!=`string`)throw Error(`[fluxion error] FluxionOptions.moduleDir must be a string`);let S=t.resolve(u);if(typeof r!=`string`)throw Error(`[fluxion error] FluxionOptions.host must be a string`);if(!Number.isSafeInteger(o)||o<=100)throw Error(`[fluxion error] FluxionOptions.handlerTimeoutMs must be an integer greater than 100`);if(!Number.isSafeInteger(s)||s<=100)throw Error(`[fluxion error] FluxionOptions.middlewareTimeoutMs must be an integer greater than 100`);if(typeof p!=`number`||p<=0||!Number.isSafeInteger(p))throw Error(`[fluxion error] FluxionOptions.reloadDelay must be a positive integer`);if(p<50)throw Error(`[fluxion error] FluxionOptions.reloadDelay must be greater than or equal to 50`);if(typeof a!=`number`||!Number.isSafeInteger(a))throw Error(`[fluxion error] FluxionOptions.port must be a positive integer`);if(a<=1||a>65535)throw Error(`[fluxion error] FluxionOptions.port must be 1 ~ 65535`);if(typeof l!=`number`||!Number.isSafeInteger(l))throw Error(`[fluxion error] FluxionOptions.metaPort must be a positive integer`);if(l<=1||l>65535)throw Error(`[fluxion error] FluxionOptions.metaPort must be 1 ~ 65535`);if(l===a)throw Error(`[fluxion error] FluxionOptions.metaPort must be different from FluxionOptions.port`);if(typeof d!=`object`||!d||Array.isArray(d))throw Error(`[fluxion error] FluxionOptions.workerOptions must be an object`);if(typeof f!=`number`||f<=0||!Number.isSafeInteger(f))throw Error(`[fluxion error] FluxionOptions.maxRequestBytes must be a positive integer`);if(y!==void 0&&(typeof y!=`string`||y.length<20||/\s/.test(y)||!/[A-Za-z]/.test(y)||!/\d/.test(y)))throw Error(`[fluxion error] FluxionOptions.metaSecret must be a string with at least 20 characters, include both letters and digits, and contain no whitespace`);return i.existsSync(x)||i.mkdirSync(x,{recursive:!0}),{dir:x,host:r,port:a,handlerTimeoutMs:o,middlewareTimeoutMs:s,staticResourceTimeoutMs:c,reloadDelay:p,metaPort:l,moduleDir:S,workerOptions:O(d),maxRequestBytes:f,logger:b,include:m,apiInclude:h,exclude:g,nativeWatcher:v,metaSecret:y,https:A(_,S),normalizedFlag:w}}const te=e=>[100,101].includes(e?.type),M=e=>[202,200,201,203,204].includes(e?.type),N=e=>process.send?.(e),P=(e,t)=>e.send(t);function F(e,t,n=200){e.statusCode=n,e.setHeader(`Content-Type`,`application/json; charset=utf-8`),e.end(JSON.stringify(t))}function I(e,t,n=200){if(!e.writableEnded){if(e.headersSent){e.end();return}F(e,t,n)}}function L(e,t,n){let r=o.createServer(async(r,i)=>{let a=r.method??`GET`,o;try{o=new URL(r.url??`/`,`http://fluxion.local`)}catch{F(i,{message:`Bad Request: invalid url`},400);return}if(a===`GET`&&o.pathname===`/_fluxion/healthz`){F(i,{ok:!0,role:`primary`,pid:process.pid,now:Date.now(),uptimeSeconds:Number(process.uptime().toFixed(3))});return}if(a===`GET`&&o.pathname===`/_fluxion/workers`){F(i,{ok:!0,now:Date.now(),workers:t()});return}if(a===`GET`&&o.pathname===`/_fluxion/routes`){if(!e.options.metaSecret){F(i,{message:`Not Found`},404);return}if(o.searchParams.get(`secret`)!==e.options.metaSecret){F(i,{message:`Forbidden`},403);return}let t=await n();F(i,{ok:!0,now:Date.now(),routes:t});return}F(i,{message:`Not Found`},404)});return r.on(`listening`,()=>{e.logger.info({message:`MetaApiStarted`,pid:process.pid,host:e.options.host,port:e.options.metaPort,prefix:`/_fluxion`})}),r.on(`error`,t=>{e.logger.error({message:`MetaApiError`,host:e.options.host,port:e.options.metaPort,code:t.code,error:C(t)}),process.exit(1)}),r.listen(e.options.metaPort,e.options.host),r}const R=e=>Number((e/1024/1024).toFixed(2)),z=6e4;function B(e){if(!n.isPrimary)throw Error(`[fluxion error] createPrimary should only be called in primary process`);let{workerOptions:t}=e.options,r=t.restartWhen,i=Math.max(1,a.cpus().length),o=Math.max(1,Math.min(t.maxWorkerCount??Math.min(2,i),i));e.logger.info({message:`PrimaryStarted`,pid:process.pid,workers:o,host:e.options.host,port:e.options.port,metaPort:e.options.metaPort});let s=new Map,c=new Map,l=0,u=new Map,d=e=>{let t=Date.now(),n=(u.get(e)??[]).filter(e=>t-e<z);return u.set(e,n),n.length},f=e=>{let t=Date.now(),n=(u.get(e)??[]).filter(e=>t-e<z);n.push(t),u.set(e,n)},p=e=>d(e)>=3;L(e,()=>({primaryPid:process.pid,host:e.options.host,port:e.options.port,metaPort:e.options.metaPort,uptimeSeconds:Number(process.uptime().toFixed(3)),workers:Array.from(s.entries()).map(([e,t])=>{let{instance:n}=t,r=t.lastStats;return{workerId:e,slot:t.slot,pid:t.pid??n.process.pid??null,state:t.state,restartReason:t.restartReason??null,createdAt:t.createdAt,readyAt:t.readyAt??null,connected:n.isConnected(),dead:n.isDead(),exitedAfterDisconnect:n.exitedAfterDisconnect,lastPongAt:t.lastPongAt??null,lastRttMs:t.lastRttMs??null,stats:r===void 0?null:{at:r.at,uptimeSeconds:r.uptimeSeconds,cpu:r.cpu,memory:{...r.memory,rssMb:R(r.memory.rss),heapTotalMb:R(r.memory.heapTotal),heapUsedMb:R(r.memory.heapUsed),externalMb:R(r.memory.external),arrayBuffersMb:R(r.memory.arrayBuffers)}}}})}),()=>{let e=Array.from(s.values()).find(e=>e.state===`ready`&&e.instance.isConnected());return e?new Promise(t=>{let n=++l,r=setTimeout(()=>{c.delete(n),t([])},1e3);r.unref(),c.set(n,{resolve:t,timer:r});try{P(e.instance,{type:101,requestId:n})}catch{clearTimeout(r),c.delete(n),t([])}}):Promise.resolve([])});let m=(t,n)=>{for(let e of s.values())if(e.state===`restarting`)return;if(p(t.slot)){e.logger.warn({message:`WorkerRecycleSuppressed`,slot:t.slot,pid:t.pid,reason:n,windowMs:z,max:3});return}f(t.slot),t.state=`restarting`,t.restartReason=n,e.logger.warn({message:`WorkerRecycling`,slot:t.slot,pid:t.pid,reason:n}),t.instance.kill()},h=(e,t)=>{let n=R(t.memory.rss);if(n>r.memoryUsageGreaterThan){m(e,`memoryUsageGreaterThan: rss ${n}MB > ${r.memoryUsageGreaterThan}MB`);return}let i=t.uptimeSeconds*1e3;i>r.uptimeGreaterThan&&m(e,`uptimeGreaterThan: ${Math.round(i/1e3)}s > ${Math.round(r.uptimeGreaterThan/1e3)}s`)},g=e=>{for(let t of s.values()){if(t.state!==`ready`||t.lastPongAt===void 0)continue;let n=e-t.lastPongAt;n>r.healthzTimeout&&m(t,`healthzTimeout: no pong for ${Math.round(n/1e3)}s > ${Math.round(r.healthzTimeout/1e3)}s`)}},_=e=>{v(n.fork({WORKER_ID:String(e)}),e)},v=(t,n)=>{let r={state:`creating`,pid:t.process.pid,slot:n,createdAt:Date.now(),instance:t};s.set(t.id,r),t.on(`message`,i=>{if(M(i)){if(i.type===202){let e=Date.now()-i.sentAt;r.pid=i.pid,r.lastPongAt=Date.now(),r.lastRttMs=e;return}if(i.type===201){r.state=`ready`,r.pid=i.pid,r.readyAt=Date.now(),e.logger.info({message:`WorkerReady`,workerId:t.id,slot:n,pid:i.pid});return}if(i.type===200){r.state=`created`,r.pid=i.pid,e.logger.info({message:`WorkerCreated`,workerId:t.id,slot:n,pid:i.pid});return}if(i.type===203){r.pid=i.pid,r.lastStats=i.stats,r.state===`ready`&&h(r,i.stats);return}if(i.type===204){let e=c.get(i.requestId);e&&(clearTimeout(e.timer),c.delete(i.requestId),e.resolve(i.routes))}}}),t.on(`exit`,(n,r)=>{let i=s.get(t.id);s.delete(t.id);let a=i?.slot,o=i?.state===`restarting`,c=i?.restartReason??null;if(e.logger.warn({message:`WorkerExited`,workerId:t.id,slot:a??null,pid:t.process.pid??`unknown`,code:n,signal:r??`none`,expected:o,reason:c}),a!==void 0){if(o){_(a);return}if(f(a),p(a)){e.logger.error({message:`WorkerRespawnSuppressed`,slot:a,windowMs:z,max:3});return}_(a)}})};for(let e=0;e<o;e++)_(e+1);setInterval(()=>{let e=Date.now();for(let t of s.values())if(t.instance.isConnected())try{P(t.instance,{type:100,sentAt:e})}catch{}g(Date.now())},5e3).unref()}function V(e,...t){return new Promise((n,r)=>{try{let i=e(...t);i instanceof Promise?i.then(n).catch(r):n(i)}catch(e){r(e)}})}function ne(e){let t=e.headersDistinct[`x-forwarded-for`];if(t){let e=t[0]?.split(`,`)[0]?.trim();if(e&&e.length>0)return e}let n=e.headersDistinct[`x-real-ip`]?.[0].trim();return n===void 0?e.socket.remoteAddress??`unknown`:n}function H(e){if(e===void 0)return!1;let t=e.toLowerCase();return t.startsWith(`text/`)||t.includes(`json`)||t.includes(`xml`)||t.includes(`x-www-form-urlencoded`)||t.includes(`javascript`)}function U(e){if(e!==void 0)try{return new URL(e,`http://fluxion.local`)}catch{return}}function W(e){let t={};for(let[n,r]of e.entries()){let e=t[n];if(e===void 0){t[n]=r;continue}if(Array.isArray(e)){e.push(r);continue}t[n]=[e,r]}return t}var G=class extends Error{errno;code;constructor(e,t,n){super(e),this.name=`HttpException`,this.errno=t,this.code=n}},K=class extends G{constructor(e=`Payload Too Large`){super(e,413,`PAYLOAD_TOO_LARGE`)}};function q(e,t){return new K(`request body too large: ${e.toString()} bytes exceeds ${t.toString()} bytes`)}function J(e){return Array.isArray(e)?e[0]:e}function Y(){return{exists:!1,bytes:0,truncated:!1}}function X(e,t,n,r){return t===0?Y():H(n)?{exists:!0,value:e.toString(`utf8`),bytes:t,truncated:r}:{exists:!0,value:`<binary body: ${t} bytes>`,bytes:t,truncated:r}}async function re(e,t,n,r=8192){if(t===`GET`||t===`HEAD`||e.readableEnded)return{rawBody:void 0,preview:Y()};let i=J(e.headers[`content-length`]),a=i===void 0?NaN:Number.parseInt(i,10);return new Promise((t,i)=>{let o=[],s=[],c=0,l=0,u=!1,d=!1,f=()=>{e.off(`data`,m),e.off(`end`,h),e.off(`error`,g),e.off(`aborted`,_)},p=e=>{d||(d=!0,e())};if(Number.isFinite(a)&&a>n){f(),e.resume(),p(()=>i(q(a,n)));return}let m=t=>{let a=Buffer.isBuffer(t)?t:Buffer.from(t);if(c+=a.byteLength,c>n){f(),e.resume(),p(()=>i(q(c,n)));return}if(o.push(a),l<r){let e=r-l,t=a.subarray(0,e);s.push(t),l+=t.length,t.length<a.length&&(u=!0)}else u=!0},h=()=>{f(),p(()=>{let n=o.length>0?Buffer.concat(o):void 0;t({rawBody:n,preview:X(s.length>0?Buffer.concat(s):Buffer.alloc(0),n?.byteLength??0,J(e.headers[`content-type`]),u)})})},g=e=>{f(),p(()=>i(e))},_=()=>{f(),p(()=>i(Error(`request aborted while reading body`)))};e.on(`data`,m),e.once(`end`,h),e.once(`error`,g),e.once(`aborted`,_)})}async function ie(e,t,n){let{rawBody:r,preview:i}=await re(e,t,n);if(r===void 0||r.byteLength===0)return{body:{},preview:i};let a=J(e.headers[`content-type`])?.toLowerCase()??``;if(a.includes(`json`)){let e=r.toString(`utf8`).trim();if(e.length===0)return{body:{},preview:i};try{let t=JSON.parse(e);return typeof t==`object`&&t&&!Array.isArray(t)?{body:t,preview:i}:{body:{value:t},preview:i}}catch{return{body:{raw:e},preview:i}}}return a.includes(`x-www-form-urlencoded`)?{body:W(new URLSearchParams(r.toString(`utf8`))),preview:i}:H(a)?{body:{raw:r.toString(`utf8`)},preview:i}:{body:{},preview:i}}function ae(e){if(!e)return{};let t={},n=e.split(`;`);for(let e of n){let[n,...r]=e.split(`=`);if(!n)continue;let i=n.trim(),a=r.join(`=`).trim();t[i]=decodeURIComponent(a)}return t}const Z=(e,t,n)=>Promise.race([e,new Promise(e=>setTimeout(()=>e(n),t))]);function oe(e){let t=Object.freeze({logger:e.logger}),n=async(n,r)=>{let i=n.method??`GET`,a=ne(n),o=U(n.url);if(o===void 0){I(r,{message:`Bad Request: req.url is undefined`},400);return}let s={method:i,ip:a,url:o,query:W(o.searchParams),body:{},headers:n.headers,cookie:ae(n.headers.cookie),meta:{}},c={exists:!1,bytes:0,truncated:!1};e.logger.info({message:`request`,method:i,ip:a,path:o.pathname});let l=performance.now();r.once(`finish`,()=>{let t={workerId:process.env.WORKER_ID??`[primary]`,message:`response`,method:i,ip:a,path:o.pathname,status:r.statusCode,duration:(performance.now()-l).toFixed(4)};Object.keys(s.query).length>0&&(t.query=s.query),c.exists&&(t.body=c.value,t.bodyBytes=c.bytes,t.bodyTruncated=c.truncated),e.logger.info(t)});try{if(s.url.pathname.startsWith(`/_fluxion/`)){I(r,{message:`Not Found`},404);return}let i=await ie(n,s.method,e.options.maxRequestBytes);s.body=i.body,c=i.preview;let a=await e.router.getModule(o);if(!a){I(r,{message:`Not Found`},404);return}if(n.method&&a.methods&&!a.methods.includes(n.method)){I(r,{message:`Method Not Allowed`},405);return}let l=a.type===0?a.handlerTimeoutMs??e.options.handlerTimeoutMs:e.options.staticResourceTimeoutMs;if(a.middlewares)for(let i=0;i<a.middlewares.length;i++){if(await Z(V(a.middlewares[i],s,t,n,r),e.options.middlewareTimeoutMs,D)===D){e.logger.warn({message:`MiddlewareTimeout`,method:s.method,ip:s.ip}),I(r,{message:`Internal Server Error`},500);return}if(r.writableEnded)return;if(r.headersSent){r.end();return}}let u=await Z(V(a.handler,s,t,n,r),l,E);if(u===E){e.logger.warn({message:`HandlerTimeout`,method:s.method,ip:s.ip}),I(r,{message:`Handler timed out`},500);return}u!==T&&I(r,u)}catch(t){t instanceof G?(e.logger.error({message:`RequestFailed`,method:s.method,ip:s.ip,path:s.url.pathname,error:t.message}),I(r,{message:t.message},t.errno)):(e.logger.error({message:`RequestFailed`,method:s.method,ip:s.ip,path:s.url.pathname,error:C(t)}),I(r,{message:C(t)},t.errno??500))}},r=e.options.https?s.createServer({key:e.options.https.key,cert:e.options.https.cert,ca:e.options.https.ca},n):o.createServer(n);return new Promise((t,n)=>{let i=!1;r.on(`close`,()=>{e.logger.info({message:`ServerClosed`,host:e.options.host,port:e.options.port})}),r.once(`listening`,()=>{i=!0,e.logger.info({message:`ServerStarted`,pid:process.pid,protocol:e.options.https?`https`:`http`,host:e.options.host,port:e.options.port}),e.logger.info({message:`DynamicDirectory`,directory:e.options.dir}),t(r)}),r.on(`error`,t=>{e.logger.error({message:`ServerError`,error:C(t)}),i&&process.exit(1),n(t)}),r.listen(e.options.port,e.options.host)})}const se=()=>{let e=process.cpuUsage(),t=Date.now();setInterval(()=>{let n=Date.now(),r=Math.max(1,(n-t)*1e3),i=process.cpuUsage(e),a=Number(((i.user+i.system)/r*100).toFixed(2));e=process.cpuUsage(),t=n;let o=process.memoryUsage();N({type:203,pid:process.pid,stats:{at:n,pid:process.pid,uptimeSeconds:Number(process.uptime().toFixed(3)),cpu:{userMicros:i.user,systemMicros:i.system,percent:a},memory:{rss:o.rss,heapTotal:o.heapTotal,heapUsed:o.heapUsed,external:o.external,arrayBuffers:o.arrayBuffers}}})},2e3).unref()};function ce(e){if(n.isPrimary)throw Error(`[fluxion error] createWorker should only be called in worker process`);process.on(`message`,t=>{if(te(t)){if(t.type===100){N({type:202,pid:process.pid,sentAt:t.sentAt,receivedAt:Date.now()});return}t.type===101&&N({type:204,pid:process.pid,requestId:t.requestId,routes:e.router.getRoutes()})}}),N({type:200,pid:process.pid}),se();let t,r=!1,i=n=>{r||(r=!0,e.logger.warn({message:`WorkerShuttingDown`,pid:process.pid,signal:n}),e.watcher.stop(),t||process.exit(0),setTimeout(()=>process.exit(1),1e4).unref(),t.close(t=>{t&&(e.logger.error({message:`WorkerShutdownFailed`,pid:process.pid,error:C(t)}),process.exit(1)),process.exit(0)}))};process.once(`SIGINT`,i),process.once(`SIGTERM`,i),oe(e).then(e=>{t=e,N({type:201,pid:process.pid})}).catch(t=>{e.logger.error({message:`WorkerBootstrapFailed`,pid:process.pid,error:C(t)}),e.watcher.stop(),process.exit(1)})}var Q=class{cx;timer=null;filesChanged=new Map;constructor(e){this.cx=e}async init(){let e=this.cx.options.dir;if(!i.existsSync(e))return this.cx.logger.warn(`Directory does not exist: ${e}`),this;let n=[],r=(e,a)=>{let o=i.readdirSync(e,{withFileTypes:!0});for(let i=0;i<o.length;i++){let s=o[i],c=t.join(e,s.name),l=t.join(a,s.name);if(s.isDirectory())r(c,l);else if(s.isFile()){let e=this.cx.router.register(c,l).catch(e=>{this.cx.logger.error(`Error registering file ${l}: ${e.message}`)});n.push(e)}}};return r(e,``),await Promise.all(n),this.cx.logger.info(`Initial registration complete for directory: ${e}`),this}queueUp(e,t){this.filesChanged.set(e,t),!this.timer&&(this.timer=setTimeout(async()=>{let e=[...this.filesChanged].map(([e,t])=>this.cx.router.register(e,t).catch(e=>this.cx.logger.error(`Error refreshing handlers: ${e.message}`)).finally(()=>this.filesChanged.delete(e)));await Promise.all(e),this.timer=null},this.cx.options.reloadDelay))}stopCore(){this.timer&&=(clearTimeout(this.timer),null),this.filesChanged.clear()}},le=class extends Q{watcher=null;constructor(e){super(e)}async start(){this.stop(),await this.init();let e=this.cx.options.dir;return this.watcher=c.watch(e,{persistent:!0,ignoreInitial:!0,usePolling:!1,awaitWriteFinish:{stabilityThreshold:100,pollInterval:50}}).on(`all`,(n,r)=>{r&&this.queueUp(r,t.relative(e,r))}).on(`error`,e=>{let t=e instanceof Error?e:Error(String(e));this.cx.logger.error(`Watcher error: ${t.message}`),this.cx.logger.error(`Restarting watcher...`),this.start()}).on(`ready`,()=>{this.cx.logger.info(`Watcher ready and watching directory: ${e}`)}),this.cx.logger.info(`Watcher started on directory: ${e}`),this}stop(){return this.watcher&&=(this.watcher.close(),null),this.stopCore(),this}},ue=class extends Q{watcher=null;constructor(e){super(e)}async start(){this.stop(),await this.init();let e=this.cx.options.dir;return this.watcher=i.watch(e,{recursive:!0},(n,r)=>{r&&this.queueUp(t.join(e,r),r)}).on(`error`,e=>{this.cx.logger.error(`Watcher error: ${e.message}`),this.cx.logger.error(`Restarting watcher...`),this.start()}),this.cx.logger.info(`Watcher started on directory: ${e}`),this}stop(){return this.watcher&&=(this.watcher.close(),null),this.stopCore(),this}};function de(e){}const fe=de;function $(e,t){if(typeof t!=`object`||!t)return!1;if(fe(t),typeof t.handler!=`function`)return e.logger.error(`handler must be a function`),!1;if(t.disposer!==void 0&&typeof t.disposer!=`function`)return e.logger.error(`disposer must be a function if provided`),!1;let n=t.handlerTimeoutMs;return n!==void 0&&(!Number.isSafeInteger(n)||n<100)?(e.logger.error(`handlerTimeoutMs must be an integer >= 100 if provided`),!1):t.type===0?!0:(e.logger.error(`You must use defineFluxionModule to create module`),!1)}function pe(e,t){delete u.cache[t];let n=u(t);if($(e,n.default))n=n.default;else if(!$(e,n))throw Error(`[fluxion error] Invalid handler module '${t}', make sure it satisfies defineFluxionModule(...) helper`);return n}var me=class{cx;handlers=new Map;constructor(e){this.cx=e}makeStaticResource(e){return{type:1,handler:async(n,r,a,o)=>{if(n.method!==`GET`&&n.method!==`HEAD`){o.statusCode=405,o.setHeader(`Allow`,`GET, HEAD`),o.end();return}if(!i.existsSync(e)){o.statusCode=404,o.end(`Not Found`);return}let s=i.statSync(e);if(!s.isFile()){o.statusCode=404,o.end(`Not Found`);return}let c=ee[t.extname(e).toLowerCase()]??`application/octet-stream`;if(o.statusCode=200,o.setHeader(`Content-Type`,c),o.setHeader(`Content-Length`,String(s.size)),n.method===`HEAD`){o.end();return}return new Promise((t,n)=>{let r=i.createReadStream(e),s=()=>{r.off(`error`,c),r.off(`end`,l),o.off(`close`,u),a.off(`aborted`,u)},c=e=>{s(),n(e)},l=()=>{s(),t(T)},u=()=>{s(),r.destroy(),t(T)};r.on(`error`,c),r.on(`end`,l),o.on(`close`,u),a.on(`aborted`,u),r.pipe(o)})}}}async register(e,t){let n=this.handlers.get(t)?.disposer;if(n&&await V(n),!i.existsSync(e)){this.handlers.delete(t),this.cx.logger.info({action:`Delete`,url:t});return}if(!this.cx.options.include.some(e=>l(t,e))){this.handlers.delete(t),this.cx.logger.info({action:`Skip`,url:t});return}if(this.cx.options.exclude.some(e=>l(t,e))){this.handlers.delete(t),this.cx.logger.info({action:`Exclude`,url:t});return}if(this.cx.options.apiInclude.some(e=>l(t,e))){let n=pe(this.cx,e);this.handlers.set(t,n),this.cx.logger.info({action:`RegisterApi`,url:t});return}this.handlers.set(t,this.makeStaticResource(e)),this.cx.logger.info({action:`RegisterStatic`,url:t})}getModule(e){let t=e.pathname.replace(/^[/]+/,``).replace(/[/]+$/,``);return this.handlers.get(t)}getRoutes(){return[...this.handlers.entries()].map(([e,t])=>({path:`/`+e,type:t.type===0?`api`:`static`,methods:t.methods?[...t.methods]:null})).sort((e,t)=>e.path.localeCompare(t.path))}};async function he(e){let t={options:e.normalizedFlag===w?e:j(e)};t.logger=x(t),t.router=new me(t),n.isPrimary?B(t):(t.logger=S(t.logger,process.pid),t.watcher=await new(t.options.nativeWatcher?ue:le)(t).start(),ce(t))}function ge(e){if(e.name===null){let n=e.options.find(e=>e.option===`config`)?.value??`fluxion.config.ts`;n=t.isAbsolute(n)?n:t.join(process.cwd(),n),he(u(n).default)}}function _e(){ge(p())}_e();export{};
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require("fast-json-stable-stringify");c=s(c);let l=require("node:fs");l=s(l);let u=require("node:path");u=s(u);let d=require("node:cluster");d=s(d);let f=require("node:os");f=s(f);let p=require("node:http");p=s(p);let m=require("node:https");m=s(m);let h=require("chokidar");h=s(h);let g=require("minimatch");function _(e=new Date){return`${e.getFullYear()}.${String(e.getMonth()+1).padStart(2,`0`)}.${String(e.getDate()).padStart(2,`0`)} ${String(e.getHours()).padStart(2,`0`)}:${String(e.getMinutes()).padStart(2,`0`)}:${String(e.getSeconds()).padStart(2,`0`)}.${String(e.getMilliseconds()).padStart(3,`0`)}`}const v=process.env.FLUXION_COLORS!==`0`;let y;(function(e){e.reset=v?`\x1B[0m`:``,e.bold=v?`\x1B[1m`:``,e.dim=v?`\x1B[2m`:``,e.italic=v?`\x1B[3m`:``,e.underline=v?`\x1B[4m`:``,e.blink=v?`\x1B[5m`:``,e.inverse=v?`\x1B[7m`:``,e.black=v?`\x1B[30m`:``,e.red=v?`\x1B[31m`:``,e.green=v?`\x1B[32m`:``,e.yellow=v?`\x1B[33m`:``,e.blue=v?`\x1B[34m`:``,e.magenta=v?`\x1B[35m`:``,e.cyan=v?`\x1B[36m`:``,e.white=v?`\x1B[37m`:``,e.brightBlack=v?`\x1B[90m`:``,e.brightRed=v?`\x1B[91m`:``,e.brightGreen=v?`\x1B[92m`:``,e.brightYellow=v?`\x1B[93m`:``,e.brightBlue=v?`\x1B[94m`:``,e.brightMagenta=v?`\x1B[95m`:``,e.brightCyan=v?`\x1B[96m`:``,e.brightWhite=v?`\x1B[97m`:``,e.bgBlack=v?`\x1B[40m`:``,e.bgRed=v?`\x1B[41m`:``,e.bgGreen=v?`\x1B[42m`:``,e.bgYellow=v?`\x1B[43m`:``,e.bgBlue=v?`\x1B[44m`:``,e.bgMagenta=v?`\x1B[45m`:``,e.bgCyan=v?`\x1B[46m`:``,e.bgWhite=v?`\x1B[47m`:``,e.bgBrightBlack=v?`\x1B[100m`:``,e.bgBrightRed=v?`\x1B[101m`:``,e.bgBrightGreen=v?`\x1B[102m`:``,e.bgBrightYellow=v?`\x1B[103m`:``,e.bgBrightBlue=v?`\x1B[104m`:``,e.bgBrightMagenta=v?`\x1B[105m`:``,e.bgBrightCyan=v?`\x1B[106m`:``,e.bgBrightWhite=v?`\x1B[107m`:``,e.purple=v?`\x1B[38;2;225;16;248m`:``,e.orange=v?`\x1B[38;2;248;147;16m`:``,e.darkGreen=v?`\x1B[38;2;22;101;52m`:``,e.claude=v?`\x1B[38;2;217;119;87m`:``,e.deepseek=v?`\x1B[38;2;57;100;254m`:``,e.gpt=v?`\x1B[38;2;41;60;77m`:``})(y||={});const b=e=>{try{return(0,c.default)(e)}catch{return`[unserializable]`}},x={INFO:`${y.cyan}INFO${y.reset}`,WARN:`${y.orange}WARN${y.reset}`,ERROR:`${y.red}ERROR${y.reset}`,SUCC:`${y.green}SUCC${y.reset}`,DEBUG:`${y.blue}DEBUG${y.reset}`,VERBOSE:`${y.purple}VERBOSE${y.reset}`},S=e=>{let{level:t,timestamp:n,message:r,pid:i,...a}=e,o=`${y.darkGreen}[${n}]${y.reset}`,s=x[t]??t,c=i===void 0?``:` [${i}]`,l=Object.keys(a).length>0?` ${y.dim}${b(a)}${y.reset}`:``;console.log(`${o} ${s}${c} ${r}${l}`)};function ee(e){let t=e.options.logger;return t===void 0||t===`one-line`?S:t===`json-line`?e=>console.log(b(e)):t}function te(e){let t=ee(e);return{write(e,n){let r=typeof n==`string`?{message:n,timestamp:_(),level:e}:{...n,timestamp:_(),level:e};try{t(r)}catch{}},info(e){this.write(`INFO`,e)},warn(e){this.write(`WARN`,e)},error(e){this.write(`ERROR`,e)},succ(e){this.write(`SUCC`,e)},debug(e){this.write(`DEBUG`,e)},verbose(e){this.write(`VERBOSE`,e)}}}function ne(e,t){return{write(n,r){e.write(n,typeof r==`string`?{message:r,pid:t}:{...r,pid:t})},info(e){this.write(`INFO`,e)},warn(e){this.write(`WARN`,e)},error(e){this.write(`ERROR`,e)},succ(e){this.write(`SUCC`,e)},debug(e){this.write(`DEBUG`,e)},verbose(e){this.write(`VERBOSE`,e)}}}const C=typeof Error.isError==`function`?e=>Error.isError(e)?e.message:String(e):e=>e?.message||String(e);function w(e={}){let t=e.restartWhen??{},n=t.healthzTimeout??3e4;if(n!==1/0&&(!Number.isFinite(n)||n<1e4))throw Error(`[fluxion error] workerOptions.restartWhen.healthzTimeout must be a finite number >= 10000 (ms) or Infinity`);return{maxWorkerCount:e.maxWorkerCount??4,restartWhen:{memoryUsageGreaterThan:t.memoryUsageGreaterThan??1/0,healthzTimeout:n,uptimeGreaterThan:t.uptimeGreaterThan??1/0}}}function T(e,t){if(Buffer.isBuffer(e))return e;if(typeof e==`string`){if(!e.startsWith(`-----BEGIN`)){let n=u.default.isAbsolute(e)?e:u.default.join(t,e);if(l.default.existsSync(n))return l.default.readFileSync(n)}return Buffer.from(e)}throw Error(`[fluxion error] Certificate content must be a string or Buffer`)}function re(e,t){if(!e)return;if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`[fluxion error] FluxionOptions.https must be an object`);if(typeof e.key!=`string`)throw Error(`[fluxion error] FluxionOptions.https.key must be a string`);if(typeof e.cert!=`string`)throw Error(`[fluxion error] FluxionOptions.https.cert must be a string`);let n={key:T(e.key,t),cert:T(e.cert,t)};return e.ca!==void 0&&(Array.isArray(e.ca)?n.ca=e.ca.map(e=>T(e,t)):n.ca=T(e.ca,t)),n}function ie(e){if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`[fluxion error] FluxionOptions must be an object`);let{dir:t,host:n,port:r,handlerTimeoutMs:i=5e3,middlewareTimeoutMs:a=3e3,staticResourceTimeoutMs:o=10*6e5,metaPort:s=r+1,moduleDir:c=process.cwd(),workerOptions:d={},maxRequestBytes:f=8e6,reloadDelay:p=500,include:m=[`**/*`],apiInclude:h=[`**/*.ts`],exclude:g=[`**/node_modules/**`,`**/.git/**`,`**/dist/**`,`**/build/**`,`**/.vscode/**`,`**/.idea/**`,`**/*.log`,`**/.DS_Store`,`**/coverage/**`,`**/.nyc_output/**`,`**/*.tmp`,`**/*.temp`],https:_,nativeWatcher:v=!1,metaSecret:y}=e,b=e.logger??`one-line`;if(b!==`one-line`&&b!==`json-line`&&typeof b!=`function`)throw Error(`[fluxion error] Invalid logger option, Must be 'one-line', 'json-line' or a custom logger function`);if(typeof t!=`string`)throw Error(`[fluxion error] FluxionOptions.dir must be a string`);let x=u.default.resolve(t);if(typeof c!=`string`)throw Error(`[fluxion error] FluxionOptions.moduleDir must be a string`);let S=u.default.resolve(c);if(typeof n!=`string`)throw Error(`[fluxion error] FluxionOptions.host must be a string`);if(!Number.isSafeInteger(i)||i<=100)throw Error(`[fluxion error] FluxionOptions.handlerTimeoutMs must be an integer greater than 100`);if(!Number.isSafeInteger(a)||a<=100)throw Error(`[fluxion error] FluxionOptions.middlewareTimeoutMs must be an integer greater than 100`);if(typeof p!=`number`||p<=0||!Number.isSafeInteger(p))throw Error(`[fluxion error] FluxionOptions.reloadDelay must be a positive integer`);if(p<50)throw Error(`[fluxion error] FluxionOptions.reloadDelay must be greater than or equal to 50`);if(typeof r!=`number`||!Number.isSafeInteger(r))throw Error(`[fluxion error] FluxionOptions.port must be a positive integer`);if(r<=1||r>65535)throw Error(`[fluxion error] FluxionOptions.port must be 1 ~ 65535`);if(typeof s!=`number`||!Number.isSafeInteger(s))throw Error(`[fluxion error] FluxionOptions.metaPort must be a positive integer`);if(s<=1||s>65535)throw Error(`[fluxion error] FluxionOptions.metaPort must be 1 ~ 65535`);if(s===r)throw Error(`[fluxion error] FluxionOptions.metaPort must be different from FluxionOptions.port`);if(typeof d!=`object`||!d||Array.isArray(d))throw Error(`[fluxion error] FluxionOptions.workerOptions must be an object`);if(typeof f!=`number`||f<=0||!Number.isSafeInteger(f))throw Error(`[fluxion error] FluxionOptions.maxRequestBytes must be a positive integer`);if(y!==void 0&&(typeof y!=`string`||y.length<20||/\s/.test(y)||!/[A-Za-z]/.test(y)||!/\d/.test(y)))throw Error(`[fluxion error] FluxionOptions.metaSecret must be a string with at least 20 characters, include both letters and digits, and contain no whitespace`);return l.default.existsSync(x)||l.default.mkdirSync(x,{recursive:!0}),{dir:x,host:n,port:r,handlerTimeoutMs:i,middlewareTimeoutMs:a,staticResourceTimeoutMs:o,reloadDelay:p,metaPort:s,moduleDir:S,workerOptions:w(d),maxRequestBytes:f,logger:b,include:m,apiInclude:h,exclude:g,nativeWatcher:v,metaSecret:y,https:re(_,S)}}const E=e=>[100,101].includes(e?.type),ae=e=>[202,200,201,203,204].includes(e?.type),D=e=>process.send?.(e),O=(e,t)=>e.send(t),k=Symbol.for(`fluxion.router.StaticHandled`),A=Symbol.for(`fluxion.handlerTimeout`),j=Symbol.for(`fluxion.middlewareTimeout`),M={".css":`text/css; charset=utf-8`,".html":`text/html; charset=utf-8`,".ico":`image/x-icon`,".js":`text/javascript; charset=utf-8`,".json":`application/json; charset=utf-8`,".map":`application/json; charset=utf-8`,".png":`image/png`,".jpg":`image/jpeg`,".jpeg":`image/jpeg`,".svg":`image/svg+xml`,".txt":`text/plain; charset=utf-8`,".webp":`image/webp`};let oe=function(e){return e[e.Ok=200]=`Ok`,e[e.Created=201]=`Created`,e[e.Accepted=202]=`Accepted`,e[e.NoContent=204]=`NoContent`,e[e.PartialContent=206]=`PartialContent`,e[e.MovedPermanently=301]=`MovedPermanently`,e[e.Found=302]=`Found`,e[e.NotModified=304]=`NotModified`,e[e.TemporaryRedirect=307]=`TemporaryRedirect`,e[e.PermanentRedirect=308]=`PermanentRedirect`,e[e.BadRequest=400]=`BadRequest`,e[e.Unauthorized=401]=`Unauthorized`,e[e.Forbidden=403]=`Forbidden`,e[e.NotFound=404]=`NotFound`,e[e.MethodNotAllowed=405]=`MethodNotAllowed`,e[e.NotAcceptable=406]=`NotAcceptable`,e[e.RequestTimeout=408]=`RequestTimeout`,e[e.Conflict=409]=`Conflict`,e[e.Gone=410]=`Gone`,e[e.PayloadTooLarge=413]=`PayloadTooLarge`,e[e.UnsupportedMediaType=415]=`UnsupportedMediaType`,e[e.UnprocessableEntity=422]=`UnprocessableEntity`,e[e.TooManyRequests=429]=`TooManyRequests`,e[e.InternalServerError=500]=`InternalServerError`,e[e.NotImplemented=501]=`NotImplemented`,e[e.BadGateway=502]=`BadGateway`,e[e.ServiceUnavailable=503]=`ServiceUnavailable`,e[e.GatewayTimeout=504]=`GatewayTimeout`,e}({});function N(e,t,n=200){e.statusCode=n,e.setHeader(`Content-Type`,`application/json; charset=utf-8`),e.end(JSON.stringify(t))}function P(e,t,n=200){if(!e.writableEnded){if(e.headersSent){e.end();return}N(e,t,n)}}function se(e,t,n){let r=p.default.createServer(async(r,i)=>{let a=r.method??`GET`,o;try{o=new URL(r.url??`/`,`http://fluxion.local`)}catch{N(i,{message:`Bad Request: invalid url`},400);return}if(a===`GET`&&o.pathname===`/_fluxion/healthz`){N(i,{ok:!0,role:`primary`,pid:process.pid,now:Date.now(),uptimeSeconds:Number(process.uptime().toFixed(3))});return}if(a===`GET`&&o.pathname===`/_fluxion/workers`){N(i,{ok:!0,now:Date.now(),workers:t()});return}if(a===`GET`&&o.pathname===`/_fluxion/routes`){if(!e.options.metaSecret){N(i,{message:`Not Found`},404);return}if(o.searchParams.get(`secret`)!==e.options.metaSecret){N(i,{message:`Forbidden`},403);return}let t=await n();N(i,{ok:!0,now:Date.now(),routes:t});return}N(i,{message:`Not Found`},404)});return r.on(`listening`,()=>{e.logger.info({message:`MetaApiStarted`,pid:process.pid,host:e.options.host,port:e.options.metaPort,prefix:`/_fluxion`})}),r.on(`error`,t=>{e.logger.error({message:`MetaApiError`,host:e.options.host,port:e.options.metaPort,code:t.code,error:C(t)}),process.exit(1)}),r.listen(e.options.metaPort,e.options.host),r}const F=e=>Number((e/1024/1024).toFixed(2)),I=6e4;function ce(e){if(!d.default.isPrimary)throw Error(`[fluxion error] createPrimary should only be called in primary process`);let{workerOptions:t}=e.options,n=t.restartWhen,r=Math.max(1,f.default.cpus().length),i=Math.max(1,Math.min(t.maxWorkerCount??Math.min(2,r),r));e.logger.info({message:`PrimaryStarted`,pid:process.pid,workers:i,host:e.options.host,port:e.options.port,metaPort:e.options.metaPort});let a=new Map,o=new Map,s=0,c=new Map,l=e=>{let t=Date.now(),n=(c.get(e)??[]).filter(e=>t-e<I);return c.set(e,n),n.length},u=e=>{let t=Date.now(),n=(c.get(e)??[]).filter(e=>t-e<I);n.push(t),c.set(e,n)},p=e=>l(e)>=3;se(e,()=>({primaryPid:process.pid,host:e.options.host,port:e.options.port,metaPort:e.options.metaPort,uptimeSeconds:Number(process.uptime().toFixed(3)),workers:Array.from(a.entries()).map(([e,t])=>{let{instance:n}=t,r=t.lastStats;return{workerId:e,slot:t.slot,pid:t.pid??n.process.pid??null,state:t.state,restartReason:t.restartReason??null,createdAt:t.createdAt,readyAt:t.readyAt??null,connected:n.isConnected(),dead:n.isDead(),exitedAfterDisconnect:n.exitedAfterDisconnect,lastPongAt:t.lastPongAt??null,lastRttMs:t.lastRttMs??null,stats:r===void 0?null:{at:r.at,uptimeSeconds:r.uptimeSeconds,cpu:r.cpu,memory:{...r.memory,rssMb:F(r.memory.rss),heapTotalMb:F(r.memory.heapTotal),heapUsedMb:F(r.memory.heapUsed),externalMb:F(r.memory.external),arrayBuffersMb:F(r.memory.arrayBuffers)}}}})}),()=>{let e=Array.from(a.values()).find(e=>e.state===`ready`&&e.instance.isConnected());return e?new Promise(t=>{let n=++s,r=setTimeout(()=>{o.delete(n),t([])},1e3);r.unref(),o.set(n,{resolve:t,timer:r});try{O(e.instance,{type:101,requestId:n})}catch{clearTimeout(r),o.delete(n),t([])}}):Promise.resolve([])});let m=(t,n)=>{for(let e of a.values())if(e.state===`restarting`)return;if(p(t.slot)){e.logger.warn({message:`WorkerRecycleSuppressed`,slot:t.slot,pid:t.pid,reason:n,windowMs:I,max:3});return}u(t.slot),t.state=`restarting`,t.restartReason=n,e.logger.warn({message:`WorkerRecycling`,slot:t.slot,pid:t.pid,reason:n}),t.instance.kill()},h=(e,t)=>{let r=F(t.memory.rss);if(r>n.memoryUsageGreaterThan){m(e,`memoryUsageGreaterThan: rss ${r}MB > ${n.memoryUsageGreaterThan}MB`);return}let i=t.uptimeSeconds*1e3;i>n.uptimeGreaterThan&&m(e,`uptimeGreaterThan: ${Math.round(i/1e3)}s > ${Math.round(n.uptimeGreaterThan/1e3)}s`)},g=e=>{for(let t of a.values()){if(t.state!==`ready`||t.lastPongAt===void 0)continue;let r=e-t.lastPongAt;r>n.healthzTimeout&&m(t,`healthzTimeout: no pong for ${Math.round(r/1e3)}s > ${Math.round(n.healthzTimeout/1e3)}s`)}},_=e=>{v(d.default.fork({WORKER_ID:String(e)}),e)},v=(t,n)=>{let r={state:`creating`,pid:t.process.pid,slot:n,createdAt:Date.now(),instance:t};a.set(t.id,r),t.on(`message`,i=>{if(ae(i)){if(i.type===202){let e=Date.now()-i.sentAt;r.pid=i.pid,r.lastPongAt=Date.now(),r.lastRttMs=e;return}if(i.type===201){r.state=`ready`,r.pid=i.pid,r.readyAt=Date.now(),e.logger.info({message:`WorkerReady`,workerId:t.id,slot:n,pid:i.pid});return}if(i.type===200){r.state=`created`,r.pid=i.pid,e.logger.info({message:`WorkerCreated`,workerId:t.id,slot:n,pid:i.pid});return}if(i.type===203){r.pid=i.pid,r.lastStats=i.stats,r.state===`ready`&&h(r,i.stats);return}if(i.type===204){let e=o.get(i.requestId);e&&(clearTimeout(e.timer),o.delete(i.requestId),e.resolve(i.routes))}}}),t.on(`exit`,(n,r)=>{let i=a.get(t.id);a.delete(t.id);let o=i?.slot,s=i?.state===`restarting`,c=i?.restartReason??null;if(e.logger.warn({message:`WorkerExited`,workerId:t.id,slot:o??null,pid:t.process.pid??`unknown`,code:n,signal:r??`none`,expected:s,reason:c}),o!==void 0){if(s){_(o);return}if(u(o),p(o)){e.logger.error({message:`WorkerRespawnSuppressed`,slot:o,windowMs:I,max:3});return}_(o)}})};for(let e=0;e<i;e++)_(e+1);setInterval(()=>{let e=Date.now();for(let t of a.values())if(t.instance.isConnected())try{O(t.instance,{type:100,sentAt:e})}catch{}g(Date.now())},5e3).unref()}function L(e,...t){return new Promise((n,r)=>{try{let i=e(...t);i instanceof Promise?i.then(n).catch(r):n(i)}catch(e){r(e)}})}function R(e){let t=e.headersDistinct[`x-forwarded-for`];if(t){let e=t[0]?.split(`,`)[0]?.trim();if(e&&e.length>0)return e}let n=e.headersDistinct[`x-real-ip`]?.[0].trim();return n===void 0?e.socket.remoteAddress??`unknown`:n}function z(e){if(e===void 0)return!1;let t=e.toLowerCase();return t.startsWith(`text/`)||t.includes(`json`)||t.includes(`xml`)||t.includes(`x-www-form-urlencoded`)||t.includes(`javascript`)}function B(e){if(e!==void 0)try{return new URL(e,`http://fluxion.local`)}catch{return}}function V(e){let t={};for(let[n,r]of e.entries()){let e=t[n];if(e===void 0){t[n]=r;continue}if(Array.isArray(e)){e.push(r);continue}t[n]=[e,r]}return t}var H=class extends Error{errno;code;constructor(e,t,n){super(e),this.name=`HttpException`,this.errno=t,this.code=n}},U=class extends H{constructor(e=`Bad Request`){super(e,400,`BAD_REQUEST`)}},W=class extends H{constructor(e=`Unauthorized`){super(e,401,`UNAUTHORIZED`)}},G=class extends H{constructor(e=`Forbidden`){super(e,403,`FORBIDDEN`)}},le=class extends H{constructor(e=`Not Found`){super(e,404,`NOT_FOUND`)}},ue=class extends H{constructor(e=`Method Not Allowed`){super(e,405,`METHOD_NOT_ALLOWED`)}},de=class extends H{constructor(e=`Not Acceptable`){super(e,406,`NOT_ACCEPTABLE`)}},fe=class extends H{constructor(e=`Request Timeout`){super(e,408,`REQUEST_TIMEOUT`)}},pe=class extends H{constructor(e=`Conflict`){super(e,409,`CONFLICT`)}},me=class extends H{constructor(e=`Gone`){super(e,410,`GONE`)}},K=class extends H{constructor(e=`Payload Too Large`){super(e,413,`PAYLOAD_TOO_LARGE`)}},he=class extends H{constructor(e=`Unsupported Media Type`){super(e,415,`UNSUPPORTED_MEDIA_TYPE`)}},ge=class extends H{constructor(e=`Unprocessable Entity`){super(e,422,`UNPROCESSABLE_ENTITY`)}},_e=class extends H{constructor(e=`Too Many Requests`){super(e,429,`TOO_MANY_REQUESTS`)}},ve=class extends H{constructor(e=`Internal Server Error`){super(e,500,`INTERNAL_SERVER_ERROR`)}},ye=class extends H{constructor(e=`Not Implemented`){super(e,501,`NOT_IMPLEMENTED`)}},be=class extends H{constructor(e=`Bad Gateway`){super(e,502,`BAD_GATEWAY`)}},xe=class extends H{constructor(e=`Service Unavailable`){super(e,503,`SERVICE_UNAVAILABLE`)}},Se=class extends H{constructor(e=`Gateway Timeout`){super(e,504,`GATEWAY_TIMEOUT`)}};function q(e,t){return new K(`request body too large: ${e.toString()} bytes exceeds ${t.toString()} bytes`)}function J(e){return Array.isArray(e)?e[0]:e}function Y(){return{exists:!1,bytes:0,truncated:!1}}function Ce(e,t,n,r){return t===0?Y():z(n)?{exists:!0,value:e.toString(`utf8`),bytes:t,truncated:r}:{exists:!0,value:`<binary body: ${t} bytes>`,bytes:t,truncated:r}}async function we(e,t,n,r=8192){if(t===`GET`||t===`HEAD`||e.readableEnded)return{rawBody:void 0,preview:Y()};let i=J(e.headers[`content-length`]),a=i===void 0?NaN:Number.parseInt(i,10);if(Number.isFinite(a)&&a>n)throw q(a,n);return new Promise((t,i)=>{let a=[],o=[],s=0,c=0,l=!1,u=!1,d=()=>{e.off(`data`,p),e.off(`end`,m),e.off(`error`,h),e.off(`aborted`,g)},f=e=>{u||(u=!0,e())},p=t=>{let u=Buffer.isBuffer(t)?t:Buffer.from(t);if(s+=u.byteLength,s>n){d(),e.resume(),f(()=>{i(q(s,n))});return}if(a.push(u),c<r){let e=r-c,t=u.subarray(0,e);o.push(t),c+=t.length,t.length<u.length&&(l=!0)}else l=!0},m=()=>{d(),f(()=>{let n=a.length>0?Buffer.concat(a):void 0;t({rawBody:n,preview:Ce(o.length>0?Buffer.concat(o):Buffer.alloc(0),n?.byteLength??0,J(e.headers[`content-type`]),l)})})},h=e=>{d(),f(()=>{i(e)})},g=()=>{d(),f(()=>{i(Error(`request aborted while reading body`))})};e.on(`data`,p),e.once(`end`,m),e.once(`error`,h),e.once(`aborted`,g)})}async function Te(e,t,n){let{rawBody:r,preview:i}=await we(e,t,n);if(r===void 0||r.byteLength===0)return{body:{},preview:i};let a=J(e.headers[`content-type`])?.toLowerCase()??``;if(a.includes(`json`)){let e=r.toString(`utf8`).trim();if(e.length===0)return{body:{},preview:i};try{let t=JSON.parse(e);return typeof t==`object`&&t&&!Array.isArray(t)?{body:t,preview:i}:{body:{value:t},preview:i}}catch{return{body:{raw:e},preview:i}}}return a.includes(`x-www-form-urlencoded`)?{body:V(new URLSearchParams(r.toString(`utf8`))),preview:i}:z(a)?{body:{raw:r.toString(`utf8`)},preview:i}:{body:{},preview:i}}function Ee(e){if(!e)return{};let t={},n=e.split(`;`);for(let e of n){let[n,...r]=e.split(`=`);if(!n)continue;let i=n.trim(),a=r.join(`=`).trim();t[i]=decodeURIComponent(a)}return t}const X=(e,t,n)=>Promise.race([e,new Promise(e=>setTimeout(()=>e(n),t))]);function De(e){let t=Object.freeze({logger:e.logger}),n=async(n,r)=>{let i=n.method??`GET`,a=R(n),o=B(n.url);if(o===void 0){P(r,{message:`Bad Request: req.url is undefined`},400);return}let s={method:i,ip:a,url:o,query:V(o.searchParams),body:{},headers:n.headers,cookie:Ee(n.headers.cookie),meta:{}},c={exists:!1,bytes:0,truncated:!1};e.logger.info({message:`request`,method:i,ip:a,path:o.pathname});let l=performance.now();r.once(`finish`,()=>{let t={workerId:process.env.WORKER_ID??`[primary]`,message:`response`,method:i,ip:a,path:o.pathname,status:r.statusCode,duration:(performance.now()-l).toFixed(4)};Object.keys(s.query).length>0&&(t.query=s.query),c.exists&&(t.body=c.value,t.bodyBytes=c.bytes,t.bodyTruncated=c.truncated),e.logger.info(t)});try{if(s.url.pathname.startsWith(`/_fluxion/`)){P(r,{message:`Not Found`},404);return}let i=await Te(n,s.method,e.options.maxRequestBytes);s.body=i.body,c=i.preview;let a=await e.router.getModule(o);if(!a){P(r,{message:`Not Found`},404);return}if(n.method&&a.methods&&!a.methods.includes(n.method)){P(r,{message:`Method Not Allowed`},405);return}let l=a.type===0?a.handlerTimeoutMs??e.options.handlerTimeoutMs:e.options.staticResourceTimeoutMs;if(a.middlewares)for(let i=0;i<a.middlewares.length;i++){if(await X(L(a.middlewares[i],s,t,n,r),e.options.middlewareTimeoutMs,j)===j){e.logger.warn({message:`MiddlewareTimeout`,method:s.method,ip:s.ip}),P(r,{message:`Internal Server Error`},500);return}if(r.writableEnded)return;if(r.headersSent){r.end();return}}let u=await X(L(a.handler,s,t,n,r),l,A);if(u===A){e.logger.warn({message:`HandlerTimeout`,method:s.method,ip:s.ip}),P(r,{message:`Handler timed out`},500);return}u!==k&&P(r,u)}catch(t){t instanceof H?(e.logger.error({message:`RequestFailed`,method:s.method,ip:s.ip,path:s.url.pathname,error:t.message}),P(r,{message:t.message},t.errno)):(e.logger.error({message:`RequestFailed`,method:s.method,ip:s.ip,path:s.url.pathname,error:C(t)}),P(r,{message:C(t)},t.errno??500))}},r=e.options.https?m.default.createServer({key:e.options.https.key,cert:e.options.https.cert,ca:e.options.https.ca},n):p.default.createServer(n);return new Promise((t,n)=>{let i=!1;r.on(`close`,()=>{e.logger.info({message:`ServerClosed`,host:e.options.host,port:e.options.port})}),r.once(`listening`,()=>{i=!0,e.logger.info({message:`ServerStarted`,pid:process.pid,protocol:e.options.https?`https`:`http`,host:e.options.host,port:e.options.port}),e.logger.info({message:`DynamicDirectory`,directory:e.options.dir}),t(r)}),r.on(`error`,t=>{e.logger.error({message:`ServerError`,error:C(t)}),i&&process.exit(1),n(t)}),r.listen(e.options.port,e.options.host)})}const Oe=()=>{let e=process.cpuUsage(),t=Date.now();setInterval(()=>{let n=Date.now(),r=Math.max(1,(n-t)*1e3),i=process.cpuUsage(e),a=Number(((i.user+i.system)/r*100).toFixed(2));e=process.cpuUsage(),t=n;let o=process.memoryUsage();D({type:203,pid:process.pid,stats:{at:n,pid:process.pid,uptimeSeconds:Number(process.uptime().toFixed(3)),cpu:{userMicros:i.user,systemMicros:i.system,percent:a},memory:{rss:o.rss,heapTotal:o.heapTotal,heapUsed:o.heapUsed,external:o.external,arrayBuffers:o.arrayBuffers}}})},2e3).unref()};function ke(e){if(d.default.isPrimary)throw Error(`[fluxion error] createWorker should only be called in worker process`);process.on(`message`,t=>{if(E(t)){if(t.type===100){D({type:202,pid:process.pid,sentAt:t.sentAt,receivedAt:Date.now()});return}t.type===101&&D({type:204,pid:process.pid,requestId:t.requestId,routes:e.router.getRoutes()})}}),D({type:200,pid:process.pid}),Oe();let t,n=!1,r=r=>{n||(n=!0,e.logger.warn({message:`WorkerShuttingDown`,pid:process.pid,signal:r}),e.watcher.stop(),t||process.exit(0),setTimeout(()=>process.exit(1),1e4).unref(),t.close(t=>{t&&(e.logger.error({message:`WorkerShutdownFailed`,pid:process.pid,error:C(t)}),process.exit(1)),process.exit(0)}))};process.once(`SIGINT`,r),process.once(`SIGTERM`,r),De(e).then(e=>{t=e,D({type:201,pid:process.pid})}).catch(t=>{e.logger.error({message:`WorkerBootstrapFailed`,pid:process.pid,error:C(t)}),e.watcher.stop(),process.exit(1)})}var Z=class{cx;timer=null;filesChanged=new Map;constructor(e){this.cx=e}async init(){let e=this.cx.options.dir;if(!l.default.existsSync(e))return this.cx.logger.warn(`Directory does not exist: ${e}`),this;let t=[],n=(e,r)=>{let i=l.default.readdirSync(e,{withFileTypes:!0});for(let a=0;a<i.length;a++){let o=i[a],s=u.default.join(e,o.name),c=u.default.join(r,o.name);if(o.isDirectory())n(s,c);else if(o.isFile()){let e=this.cx.router.register(s,c).catch(e=>{this.cx.logger.error(`Error registering file ${c}: ${e.message}`)});t.push(e)}}};return n(e,``),await Promise.all(t),this.cx.logger.info(`Initial registration complete for directory: ${e}`),this}queueUp(e,t){this.filesChanged.set(e,t),!this.timer&&(this.timer=setTimeout(async()=>{let e=[...this.filesChanged].map(([e,t])=>this.cx.router.register(e,t).catch(e=>this.cx.logger.error(`Error refreshing handlers: ${e.message}`)).finally(()=>this.filesChanged.delete(e)));await Promise.all(e),this.timer=null},this.cx.options.reloadDelay))}stopCore(){this.timer&&=(clearTimeout(this.timer),null),this.filesChanged.clear()}},Ae=class extends Z{watcher=null;constructor(e){super(e)}async start(){this.stop(),await this.init();let e=this.cx.options.dir;return this.watcher=h.default.watch(e,{persistent:!0,ignoreInitial:!0,usePolling:!1,awaitWriteFinish:{stabilityThreshold:100,pollInterval:50}}).on(`all`,(t,n)=>{n&&this.queueUp(n,u.default.relative(e,n))}).on(`error`,e=>{let t=e instanceof Error?e:Error(String(e));this.cx.logger.error(`Watcher error: ${t.message}`),this.cx.logger.error(`Restarting watcher...`),this.start()}).on(`ready`,()=>{this.cx.logger.info(`Watcher ready and watching directory: ${e}`)}),this.cx.logger.info(`Watcher started on directory: ${e}`),this}stop(){return this.watcher&&=(this.watcher.close(),null),this.stopCore(),this}},je=class extends Z{watcher=null;constructor(e){super(e)}async start(){this.stop(),await this.init();let e=this.cx.options.dir;return this.watcher=l.default.watch(e,{recursive:!0},(t,n)=>{n&&this.queueUp(u.default.join(e,n),n)}).on(`error`,e=>{this.cx.logger.error(`Watcher error: ${e.message}`),this.cx.logger.error(`Restarting watcher...`),this.start()}),this.cx.logger.info(`Watcher started on directory: ${e}`),this}stop(){return this.watcher&&=(this.watcher.close(),null),this.stopCore(),this}};function Me(e){}const Ne=Me;function Q(e,t){if(typeof t!=`object`||!t)return!1;if(Ne(t),typeof t.handler!=`function`)return e.logger.error(`handler must be a function`),!1;if(t.disposer!==void 0&&typeof t.disposer!=`function`)return e.logger.error(`disposer must be a function if provided`),!1;let n=t.handlerTimeoutMs;return n!==void 0&&(!Number.isSafeInteger(n)||n<100)?(e.logger.error(`handlerTimeoutMs must be an integer >= 100 if provided`),!1):t.type===0?!0:(e.logger.error(`You must use defineFluxionModule to create module`),!1)}function Pe(e,t){delete require.cache[t];let n=require(t);if(Q(e,n.default))n=n.default;else if(!Q(e,n))throw Error(`[fluxion error] Invalid handler module '${t}', make sure it satisfies defineFluxionModule(...) helper`);return n}var $=class{cx;handlers=new Map;constructor(e){this.cx=e}makeStaticResource(e){return{type:1,handler:async(t,n,r,i)=>{if(t.method!==`GET`&&t.method!==`HEAD`){i.statusCode=405,i.setHeader(`Allow`,`GET, HEAD`),i.end();return}if(!l.default.existsSync(e)){i.statusCode=404,i.end(`Not Found`);return}let a=l.default.statSync(e);if(!a.isFile()){i.statusCode=404,i.end(`Not Found`);return}let o=M[u.default.extname(e).toLowerCase()]??`application/octet-stream`;if(i.statusCode=200,i.setHeader(`Content-Type`,o),i.setHeader(`Content-Length`,String(a.size)),t.method===`HEAD`){i.end();return}return new Promise((t,n)=>{let r=l.default.createReadStream(e);r.on(`error`,n),r.on(`end`,()=>t(k)),r.pipe(i)})}}}async register(e,t){let n=this.handlers.get(t)?.disposer;if(n&&await L(n),!l.default.existsSync(e)){this.handlers.delete(t),this.cx.logger.info({action:`Delete`,url:t});return}if(!this.cx.options.include.some(e=>(0,g.minimatch)(t,e))){this.handlers.delete(t),this.cx.logger.info({action:`Skip`,url:t});return}if(this.cx.options.exclude.some(e=>(0,g.minimatch)(t,e))){this.handlers.delete(t),this.cx.logger.info({action:`Exclude`,url:t});return}if(this.cx.options.apiInclude.some(e=>(0,g.minimatch)(t,e))){let n=Pe(this.cx,e);this.handlers.set(t,n),this.cx.logger.info({action:`RegisterApi`,url:t});return}this.handlers.set(t,this.makeStaticResource(e)),this.cx.logger.info({action:`RegisterStatic`,url:t})}getModule(e){let t=e.pathname.replace(/^[/]+/,``).replace(/[/]+$/,``);return this.handlers.get(t)}getRoutes(){return[...this.handlers.entries()].map(([e,t])=>({path:`/`+e,type:t.type===0?`api`:`static`,methods:t.methods?[...t.methods]:null})).sort((e,t)=>e.path.localeCompare(t.path))}};async function Fe(e){let t={options:ie(e)};t.logger=te(t),t.router=new $(t),d.default.isPrimary?ce(t):(t.logger=ne(t.logger,process.pid),t.watcher=await new(t.options.nativeWatcher?je:Ae)(t).start(),ke(t))}function Ie(e,t){if(typeof e==`function`){if(t!==void 0&&typeof t!=`function`)throw Error(`[fluxion error] Invalid disposer, expected a function but got ${typeof t}`);return{handler:e,disposer:t,type:0}}if(typeof e!=`object`||!e)throw Error(`[fluxion error] Invalid argument, expected a FluxionModule object or a handler function, but got ${typeof e}`);if(typeof e.handler!=`function`)throw Error(`[fluxion error] Invalid FluxionModule, "handler" must be a function`);if(e.disposer!==void 0&&typeof e.disposer!=`function`)throw Error(`[fluxion error] Invalid FluxionModule, "disposer" must be a function if provided`);if(e.methods!==void 0&&(!Array.isArray(e.methods)||e.methods.some(e=>typeof e!=`string`)))throw Error(`[fluxion error] Invalid FluxionModule, "methods" must be an array of strings if provided`);if(e.middlewares!==void 0&&(!Array.isArray(e.middlewares)||e.middlewares.some(e=>typeof e!=`function`)))throw Error(`[fluxion error] Invalid FluxionModule, "middlewares" must be an array of functions if provided`);return{...e,type:0}}function Le(e){if(typeof e!=`function`)throw Error(`[fluxion error] Invalid FluxionMiddleware, expected a function but got ${typeof e}`);return e}function Re(e){if(typeof e!=`function`)throw Error(`[fluxion error] Invalid FluxionLoggerFn, expected a function but got ${typeof e}`);return e}exports.BadGatewayException=be,exports.BadRequestException=U,exports.ConflictException=pe,exports.ForbiddenException=G,exports.GatewayTimeoutException=Se,exports.GoneException=me,exports.HttpCode=oe,exports.HttpException=H,exports.InternalServerErrorException=ve,exports.MethodNotAllowedException=ue,exports.NotAcceptableException=de,exports.NotFoundException=le,exports.NotImplementedException=ye,exports.PayloadTooLargeException=K,exports.RequestTimeoutException=fe,exports.ServiceUnavailableException=xe,exports.TooManyRequestsException=_e,exports.UnauthorizedException=W,exports.UnprocessableEntityException=ge,exports.UnsupportedMediaTypeException=he,exports.defineFluxionLogger=Re,exports.defineFluxionMiddleware=Le,exports.defineFluxionModule=Ie,exports.fluxion=Fe;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require("node:cluster");c=s(c);let l=require("fast-json-stable-stringify");l=s(l);let u=require("node:fs");u=s(u);let d=require("node:path");d=s(d);let f=require("node:os");f=s(f);let p=require("node:http");p=s(p);let m=require("node:https");m=s(m);let h=require("chokidar");h=s(h);let g=require("minimatch");function _(e=new Date){return`${e.getFullYear()}.${String(e.getMonth()+1).padStart(2,`0`)}.${String(e.getDate()).padStart(2,`0`)} ${String(e.getHours()).padStart(2,`0`)}:${String(e.getMinutes()).padStart(2,`0`)}:${String(e.getSeconds()).padStart(2,`0`)}.${String(e.getMilliseconds()).padStart(3,`0`)}`}const v=process.env.FLUXION_COLORS!==`0`;let y;(function(e){e.reset=v?`\x1B[0m`:``,e.bold=v?`\x1B[1m`:``,e.dim=v?`\x1B[2m`:``,e.italic=v?`\x1B[3m`:``,e.underline=v?`\x1B[4m`:``,e.blink=v?`\x1B[5m`:``,e.inverse=v?`\x1B[7m`:``,e.black=v?`\x1B[30m`:``,e.red=v?`\x1B[31m`:``,e.green=v?`\x1B[32m`:``,e.yellow=v?`\x1B[33m`:``,e.blue=v?`\x1B[34m`:``,e.magenta=v?`\x1B[35m`:``,e.cyan=v?`\x1B[36m`:``,e.white=v?`\x1B[37m`:``,e.brightBlack=v?`\x1B[90m`:``,e.brightRed=v?`\x1B[91m`:``,e.brightGreen=v?`\x1B[92m`:``,e.brightYellow=v?`\x1B[93m`:``,e.brightBlue=v?`\x1B[94m`:``,e.brightMagenta=v?`\x1B[95m`:``,e.brightCyan=v?`\x1B[96m`:``,e.brightWhite=v?`\x1B[97m`:``,e.bgBlack=v?`\x1B[40m`:``,e.bgRed=v?`\x1B[41m`:``,e.bgGreen=v?`\x1B[42m`:``,e.bgYellow=v?`\x1B[43m`:``,e.bgBlue=v?`\x1B[44m`:``,e.bgMagenta=v?`\x1B[45m`:``,e.bgCyan=v?`\x1B[46m`:``,e.bgWhite=v?`\x1B[47m`:``,e.bgBrightBlack=v?`\x1B[100m`:``,e.bgBrightRed=v?`\x1B[101m`:``,e.bgBrightGreen=v?`\x1B[102m`:``,e.bgBrightYellow=v?`\x1B[103m`:``,e.bgBrightBlue=v?`\x1B[104m`:``,e.bgBrightMagenta=v?`\x1B[105m`:``,e.bgBrightCyan=v?`\x1B[106m`:``,e.bgBrightWhite=v?`\x1B[107m`:``,e.purple=v?`\x1B[38;2;225;16;248m`:``,e.orange=v?`\x1B[38;2;248;147;16m`:``,e.darkGreen=v?`\x1B[38;2;22;101;52m`:``,e.claude=v?`\x1B[38;2;217;119;87m`:``,e.deepseek=v?`\x1B[38;2;57;100;254m`:``,e.gpt=v?`\x1B[38;2;41;60;77m`:``})(y||={});const b=e=>{try{return(0,l.default)(e)}catch{return`[unserializable]`}},x={INFO:`${y.cyan}INFO${y.reset}`,WARN:`${y.orange}WARN${y.reset}`,ERROR:`${y.red}ERROR${y.reset}`,SUCC:`${y.green}SUCC${y.reset}`,DEBUG:`${y.blue}DEBUG${y.reset}`,VERBOSE:`${y.purple}VERBOSE${y.reset}`},S=e=>{let{level:t,timestamp:n,message:r,pid:i,...a}=e,o=`${y.darkGreen}[${n}]${y.reset}`,s=x[t]??t,c=i===void 0?``:` [${i}]`,l=Object.keys(a).length>0?` ${y.dim}${b(a)}${y.reset}`:``;console.log(`${o} ${s}${c} ${r}${l}`)};function ee(e){let t=e.options.logger;return t===void 0||t===`one-line`?S:t===`json-line`?e=>console.log(b(e)):t}function te(e){let t=ee(e);return{write(e,n){let r=typeof n==`string`?{message:n,timestamp:_(),level:e}:{...n,timestamp:_(),level:e};try{t(r)}catch{}},info(e){this.write(`INFO`,e)},warn(e){this.write(`WARN`,e)},error(e){this.write(`ERROR`,e)},succ(e){this.write(`SUCC`,e)},debug(e){this.write(`DEBUG`,e)},verbose(e){this.write(`VERBOSE`,e)}}}function ne(e,t){return{write(n,r){e.write(n,typeof r==`string`?{message:r,pid:t}:{...r,pid:t})},info(e){this.write(`INFO`,e)},warn(e){this.write(`WARN`,e)},error(e){this.write(`ERROR`,e)},succ(e){this.write(`SUCC`,e)},debug(e){this.write(`DEBUG`,e)},verbose(e){this.write(`VERBOSE`,e)}}}const C=typeof Error.isError==`function`?e=>Error.isError(e)?e.message:String(e):e=>e?.message||String(e),w=Symbol(`fluxion.router.StaticHandled`),T=Symbol(`fluxion.router.StaticHandled`),E=Symbol(`fluxion.handlerTimeout`),D=Symbol(`fluxion.middlewareTimeout`),re={".css":`text/css; charset=utf-8`,".html":`text/html; charset=utf-8`,".ico":`image/x-icon`,".js":`text/javascript; charset=utf-8`,".json":`application/json; charset=utf-8`,".map":`application/json; charset=utf-8`,".png":`image/png`,".jpg":`image/jpeg`,".jpeg":`image/jpeg`,".svg":`image/svg+xml`,".txt":`text/plain; charset=utf-8`,".webp":`image/webp`};let O=function(e){return e[e.Ok=200]=`Ok`,e[e.Created=201]=`Created`,e[e.Accepted=202]=`Accepted`,e[e.NoContent=204]=`NoContent`,e[e.PartialContent=206]=`PartialContent`,e[e.MovedPermanently=301]=`MovedPermanently`,e[e.Found=302]=`Found`,e[e.NotModified=304]=`NotModified`,e[e.TemporaryRedirect=307]=`TemporaryRedirect`,e[e.PermanentRedirect=308]=`PermanentRedirect`,e[e.BadRequest=400]=`BadRequest`,e[e.Unauthorized=401]=`Unauthorized`,e[e.Forbidden=403]=`Forbidden`,e[e.NotFound=404]=`NotFound`,e[e.MethodNotAllowed=405]=`MethodNotAllowed`,e[e.NotAcceptable=406]=`NotAcceptable`,e[e.RequestTimeout=408]=`RequestTimeout`,e[e.Conflict=409]=`Conflict`,e[e.Gone=410]=`Gone`,e[e.PayloadTooLarge=413]=`PayloadTooLarge`,e[e.UnsupportedMediaType=415]=`UnsupportedMediaType`,e[e.UnprocessableEntity=422]=`UnprocessableEntity`,e[e.TooManyRequests=429]=`TooManyRequests`,e[e.InternalServerError=500]=`InternalServerError`,e[e.NotImplemented=501]=`NotImplemented`,e[e.BadGateway=502]=`BadGateway`,e[e.ServiceUnavailable=503]=`ServiceUnavailable`,e[e.GatewayTimeout=504]=`GatewayTimeout`,e}({});function k(e={}){let t=e.restartWhen??{},n=t.healthzTimeout??3e4;if(n!==1/0&&(!Number.isFinite(n)||n<1e4))throw Error(`[fluxion error] workerOptions.restartWhen.healthzTimeout must be a finite number >= 10000 (ms) or Infinity`);return{maxWorkerCount:e.maxWorkerCount??4,restartWhen:{memoryUsageGreaterThan:t.memoryUsageGreaterThan??1/0,healthzTimeout:n,uptimeGreaterThan:t.uptimeGreaterThan??1/0}}}function A(e,t){if(Buffer.isBuffer(e))return e;if(typeof e==`string`){if(!e.startsWith(`-----BEGIN`)){let n=d.default.isAbsolute(e)?e:d.default.join(t,e);if(u.default.existsSync(n))return u.default.readFileSync(n)}return Buffer.from(e)}throw Error(`[fluxion error] Certificate content must be a string or Buffer`)}function ie(e,t){if(!e)return;if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`[fluxion error] FluxionOptions.https must be an object`);if(typeof e.key!=`string`)throw Error(`[fluxion error] FluxionOptions.https.key must be a string`);if(typeof e.cert!=`string`)throw Error(`[fluxion error] FluxionOptions.https.cert must be a string`);let n={key:A(e.key,t),cert:A(e.cert,t)};return e.ca!==void 0&&(Array.isArray(e.ca)?n.ca=e.ca.map(e=>A(e,t)):n.ca=A(e.ca,t)),n}function j(e){if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`[fluxion error] FluxionOptions must be an object`);let{dir:t,host:n,port:r,handlerTimeoutMs:i=5e3,middlewareTimeoutMs:a=3e3,staticResourceTimeoutMs:o=10*6e5,metaPort:s=r+1,moduleDir:c=process.cwd(),workerOptions:l={},maxRequestBytes:f=8e6,reloadDelay:p=500,include:m=[`**/*`],apiInclude:h=[`**/*.ts`],exclude:g=[`**/node_modules/**`,`**/.git/**`,`**/dist/**`,`**/build/**`,`**/.vscode/**`,`**/.idea/**`,`**/*.log`,`**/.DS_Store`,`**/coverage/**`,`**/.nyc_output/**`,`**/*.tmp`,`**/*.temp`],https:_,nativeWatcher:v=!1,metaSecret:y}=e,b=e.logger??`one-line`;if(b!==`one-line`&&b!==`json-line`&&typeof b!=`function`)throw Error(`[fluxion error] Invalid logger option, Must be 'one-line', 'json-line' or a custom logger function`);if(typeof t!=`string`)throw Error(`[fluxion error] FluxionOptions.dir must be a string`);let x=d.default.resolve(t);if(typeof c!=`string`)throw Error(`[fluxion error] FluxionOptions.moduleDir must be a string`);let S=d.default.resolve(c);if(typeof n!=`string`)throw Error(`[fluxion error] FluxionOptions.host must be a string`);if(!Number.isSafeInteger(i)||i<=100)throw Error(`[fluxion error] FluxionOptions.handlerTimeoutMs must be an integer greater than 100`);if(!Number.isSafeInteger(a)||a<=100)throw Error(`[fluxion error] FluxionOptions.middlewareTimeoutMs must be an integer greater than 100`);if(typeof p!=`number`||p<=0||!Number.isSafeInteger(p))throw Error(`[fluxion error] FluxionOptions.reloadDelay must be a positive integer`);if(p<50)throw Error(`[fluxion error] FluxionOptions.reloadDelay must be greater than or equal to 50`);if(typeof r!=`number`||!Number.isSafeInteger(r))throw Error(`[fluxion error] FluxionOptions.port must be a positive integer`);if(r<=1||r>65535)throw Error(`[fluxion error] FluxionOptions.port must be 1 ~ 65535`);if(typeof s!=`number`||!Number.isSafeInteger(s))throw Error(`[fluxion error] FluxionOptions.metaPort must be a positive integer`);if(s<=1||s>65535)throw Error(`[fluxion error] FluxionOptions.metaPort must be 1 ~ 65535`);if(s===r)throw Error(`[fluxion error] FluxionOptions.metaPort must be different from FluxionOptions.port`);if(typeof l!=`object`||!l||Array.isArray(l))throw Error(`[fluxion error] FluxionOptions.workerOptions must be an object`);if(typeof f!=`number`||f<=0||!Number.isSafeInteger(f))throw Error(`[fluxion error] FluxionOptions.maxRequestBytes must be a positive integer`);if(y!==void 0&&(typeof y!=`string`||y.length<20||/\s/.test(y)||!/[A-Za-z]/.test(y)||!/\d/.test(y)))throw Error(`[fluxion error] FluxionOptions.metaSecret must be a string with at least 20 characters, include both letters and digits, and contain no whitespace`);return u.default.existsSync(x)||u.default.mkdirSync(x,{recursive:!0}),{dir:x,host:n,port:r,handlerTimeoutMs:i,middlewareTimeoutMs:a,staticResourceTimeoutMs:o,reloadDelay:p,metaPort:s,moduleDir:S,workerOptions:k(l),maxRequestBytes:f,logger:b,include:m,apiInclude:h,exclude:g,nativeWatcher:v,metaSecret:y,https:ie(_,S),normalizedFlag:w}}const ae=e=>[100,101].includes(e?.type),M=e=>[202,200,201,203,204].includes(e?.type),N=e=>process.send?.(e),P=(e,t)=>e.send(t);function F(e,t,n=200){e.statusCode=n,e.setHeader(`Content-Type`,`application/json; charset=utf-8`),e.end(JSON.stringify(t))}function I(e,t,n=200){if(!e.writableEnded){if(e.headersSent){e.end();return}F(e,t,n)}}function oe(e,t,n){let r=p.default.createServer(async(r,i)=>{let a=r.method??`GET`,o;try{o=new URL(r.url??`/`,`http://fluxion.local`)}catch{F(i,{message:`Bad Request: invalid url`},400);return}if(a===`GET`&&o.pathname===`/_fluxion/healthz`){F(i,{ok:!0,role:`primary`,pid:process.pid,now:Date.now(),uptimeSeconds:Number(process.uptime().toFixed(3))});return}if(a===`GET`&&o.pathname===`/_fluxion/workers`){F(i,{ok:!0,now:Date.now(),workers:t()});return}if(a===`GET`&&o.pathname===`/_fluxion/routes`){if(!e.options.metaSecret){F(i,{message:`Not Found`},404);return}if(o.searchParams.get(`secret`)!==e.options.metaSecret){F(i,{message:`Forbidden`},403);return}let t=await n();F(i,{ok:!0,now:Date.now(),routes:t});return}F(i,{message:`Not Found`},404)});return r.on(`listening`,()=>{e.logger.info({message:`MetaApiStarted`,pid:process.pid,host:e.options.host,port:e.options.metaPort,prefix:`/_fluxion`})}),r.on(`error`,t=>{e.logger.error({message:`MetaApiError`,host:e.options.host,port:e.options.metaPort,code:t.code,error:C(t)}),process.exit(1)}),r.listen(e.options.metaPort,e.options.host),r}const L=e=>Number((e/1024/1024).toFixed(2)),R=6e4;function se(e){if(!c.default.isPrimary)throw Error(`[fluxion error] createPrimary should only be called in primary process`);let{workerOptions:t}=e.options,n=t.restartWhen,r=Math.max(1,f.default.cpus().length),i=Math.max(1,Math.min(t.maxWorkerCount??Math.min(2,r),r));e.logger.info({message:`PrimaryStarted`,pid:process.pid,workers:i,host:e.options.host,port:e.options.port,metaPort:e.options.metaPort});let a=new Map,o=new Map,s=0,l=new Map,u=e=>{let t=Date.now(),n=(l.get(e)??[]).filter(e=>t-e<R);return l.set(e,n),n.length},d=e=>{let t=Date.now(),n=(l.get(e)??[]).filter(e=>t-e<R);n.push(t),l.set(e,n)},p=e=>u(e)>=3;oe(e,()=>({primaryPid:process.pid,host:e.options.host,port:e.options.port,metaPort:e.options.metaPort,uptimeSeconds:Number(process.uptime().toFixed(3)),workers:Array.from(a.entries()).map(([e,t])=>{let{instance:n}=t,r=t.lastStats;return{workerId:e,slot:t.slot,pid:t.pid??n.process.pid??null,state:t.state,restartReason:t.restartReason??null,createdAt:t.createdAt,readyAt:t.readyAt??null,connected:n.isConnected(),dead:n.isDead(),exitedAfterDisconnect:n.exitedAfterDisconnect,lastPongAt:t.lastPongAt??null,lastRttMs:t.lastRttMs??null,stats:r===void 0?null:{at:r.at,uptimeSeconds:r.uptimeSeconds,cpu:r.cpu,memory:{...r.memory,rssMb:L(r.memory.rss),heapTotalMb:L(r.memory.heapTotal),heapUsedMb:L(r.memory.heapUsed),externalMb:L(r.memory.external),arrayBuffersMb:L(r.memory.arrayBuffers)}}}})}),()=>{let e=Array.from(a.values()).find(e=>e.state===`ready`&&e.instance.isConnected());return e?new Promise(t=>{let n=++s,r=setTimeout(()=>{o.delete(n),t([])},1e3);r.unref(),o.set(n,{resolve:t,timer:r});try{P(e.instance,{type:101,requestId:n})}catch{clearTimeout(r),o.delete(n),t([])}}):Promise.resolve([])});let m=(t,n)=>{for(let e of a.values())if(e.state===`restarting`)return;if(p(t.slot)){e.logger.warn({message:`WorkerRecycleSuppressed`,slot:t.slot,pid:t.pid,reason:n,windowMs:R,max:3});return}d(t.slot),t.state=`restarting`,t.restartReason=n,e.logger.warn({message:`WorkerRecycling`,slot:t.slot,pid:t.pid,reason:n}),t.instance.kill()},h=(e,t)=>{let r=L(t.memory.rss);if(r>n.memoryUsageGreaterThan){m(e,`memoryUsageGreaterThan: rss ${r}MB > ${n.memoryUsageGreaterThan}MB`);return}let i=t.uptimeSeconds*1e3;i>n.uptimeGreaterThan&&m(e,`uptimeGreaterThan: ${Math.round(i/1e3)}s > ${Math.round(n.uptimeGreaterThan/1e3)}s`)},g=e=>{for(let t of a.values()){if(t.state!==`ready`||t.lastPongAt===void 0)continue;let r=e-t.lastPongAt;r>n.healthzTimeout&&m(t,`healthzTimeout: no pong for ${Math.round(r/1e3)}s > ${Math.round(n.healthzTimeout/1e3)}s`)}},_=e=>{v(c.default.fork({WORKER_ID:String(e)}),e)},v=(t,n)=>{let r={state:`creating`,pid:t.process.pid,slot:n,createdAt:Date.now(),instance:t};a.set(t.id,r),t.on(`message`,i=>{if(M(i)){if(i.type===202){let e=Date.now()-i.sentAt;r.pid=i.pid,r.lastPongAt=Date.now(),r.lastRttMs=e;return}if(i.type===201){r.state=`ready`,r.pid=i.pid,r.readyAt=Date.now(),e.logger.info({message:`WorkerReady`,workerId:t.id,slot:n,pid:i.pid});return}if(i.type===200){r.state=`created`,r.pid=i.pid,e.logger.info({message:`WorkerCreated`,workerId:t.id,slot:n,pid:i.pid});return}if(i.type===203){r.pid=i.pid,r.lastStats=i.stats,r.state===`ready`&&h(r,i.stats);return}if(i.type===204){let e=o.get(i.requestId);e&&(clearTimeout(e.timer),o.delete(i.requestId),e.resolve(i.routes))}}}),t.on(`exit`,(n,r)=>{let i=a.get(t.id);a.delete(t.id);let o=i?.slot,s=i?.state===`restarting`,c=i?.restartReason??null;if(e.logger.warn({message:`WorkerExited`,workerId:t.id,slot:o??null,pid:t.process.pid??`unknown`,code:n,signal:r??`none`,expected:s,reason:c}),o!==void 0){if(s){_(o);return}if(d(o),p(o)){e.logger.error({message:`WorkerRespawnSuppressed`,slot:o,windowMs:R,max:3});return}_(o)}})};for(let e=0;e<i;e++)_(e+1);setInterval(()=>{let e=Date.now();for(let t of a.values())if(t.instance.isConnected())try{P(t.instance,{type:100,sentAt:e})}catch{}g(Date.now())},5e3).unref()}function z(e,...t){return new Promise((n,r)=>{try{let i=e(...t);i instanceof Promise?i.then(n).catch(r):n(i)}catch(e){r(e)}})}function ce(e){let t=e.headersDistinct[`x-forwarded-for`];if(t){let e=t[0]?.split(`,`)[0]?.trim();if(e&&e.length>0)return e}let n=e.headersDistinct[`x-real-ip`]?.[0].trim();return n===void 0?e.socket.remoteAddress??`unknown`:n}function B(e){if(e===void 0)return!1;let t=e.toLowerCase();return t.startsWith(`text/`)||t.includes(`json`)||t.includes(`xml`)||t.includes(`x-www-form-urlencoded`)||t.includes(`javascript`)}function V(e){if(e!==void 0)try{return new URL(e,`http://fluxion.local`)}catch{return}}function H(e){let t={};for(let[n,r]of e.entries()){let e=t[n];if(e===void 0){t[n]=r;continue}if(Array.isArray(e)){e.push(r);continue}t[n]=[e,r]}return t}var U=class extends Error{errno;code;constructor(e,t,n){super(e),this.name=`HttpException`,this.errno=t,this.code=n}},W=class extends U{constructor(e=`Bad Request`){super(e,400,`BAD_REQUEST`)}},G=class extends U{constructor(e=`Unauthorized`){super(e,401,`UNAUTHORIZED`)}},le=class extends U{constructor(e=`Forbidden`){super(e,403,`FORBIDDEN`)}},ue=class extends U{constructor(e=`Not Found`){super(e,404,`NOT_FOUND`)}},de=class extends U{constructor(e=`Method Not Allowed`){super(e,405,`METHOD_NOT_ALLOWED`)}},fe=class extends U{constructor(e=`Not Acceptable`){super(e,406,`NOT_ACCEPTABLE`)}},pe=class extends U{constructor(e=`Request Timeout`){super(e,408,`REQUEST_TIMEOUT`)}},me=class extends U{constructor(e=`Conflict`){super(e,409,`CONFLICT`)}},he=class extends U{constructor(e=`Gone`){super(e,410,`GONE`)}},K=class extends U{constructor(e=`Payload Too Large`){super(e,413,`PAYLOAD_TOO_LARGE`)}},q=class extends U{constructor(e=`Unsupported Media Type`){super(e,415,`UNSUPPORTED_MEDIA_TYPE`)}},ge=class extends U{constructor(e=`Unprocessable Entity`){super(e,422,`UNPROCESSABLE_ENTITY`)}},_e=class extends U{constructor(e=`Too Many Requests`){super(e,429,`TOO_MANY_REQUESTS`)}},ve=class extends U{constructor(e=`Internal Server Error`){super(e,500,`INTERNAL_SERVER_ERROR`)}},ye=class extends U{constructor(e=`Not Implemented`){super(e,501,`NOT_IMPLEMENTED`)}},be=class extends U{constructor(e=`Bad Gateway`){super(e,502,`BAD_GATEWAY`)}},xe=class extends U{constructor(e=`Service Unavailable`){super(e,503,`SERVICE_UNAVAILABLE`)}},Se=class extends U{constructor(e=`Gateway Timeout`){super(e,504,`GATEWAY_TIMEOUT`)}};function J(e,t){return new K(`request body too large: ${e.toString()} bytes exceeds ${t.toString()} bytes`)}function Y(e){return Array.isArray(e)?e[0]:e}function X(){return{exists:!1,bytes:0,truncated:!1}}function Ce(e,t,n,r){return t===0?X():B(n)?{exists:!0,value:e.toString(`utf8`),bytes:t,truncated:r}:{exists:!0,value:`<binary body: ${t} bytes>`,bytes:t,truncated:r}}async function we(e,t,n,r=8192){if(t===`GET`||t===`HEAD`||e.readableEnded)return{rawBody:void 0,preview:X()};let i=Y(e.headers[`content-length`]),a=i===void 0?NaN:Number.parseInt(i,10);return new Promise((t,i)=>{let o=[],s=[],c=0,l=0,u=!1,d=!1,f=()=>{e.off(`data`,m),e.off(`end`,h),e.off(`error`,g),e.off(`aborted`,_)},p=e=>{d||(d=!0,e())};if(Number.isFinite(a)&&a>n){f(),e.resume(),p(()=>i(J(a,n)));return}let m=t=>{let a=Buffer.isBuffer(t)?t:Buffer.from(t);if(c+=a.byteLength,c>n){f(),e.resume(),p(()=>i(J(c,n)));return}if(o.push(a),l<r){let e=r-l,t=a.subarray(0,e);s.push(t),l+=t.length,t.length<a.length&&(u=!0)}else u=!0},h=()=>{f(),p(()=>{let n=o.length>0?Buffer.concat(o):void 0;t({rawBody:n,preview:Ce(s.length>0?Buffer.concat(s):Buffer.alloc(0),n?.byteLength??0,Y(e.headers[`content-type`]),u)})})},g=e=>{f(),p(()=>i(e))},_=()=>{f(),p(()=>i(Error(`request aborted while reading body`)))};e.on(`data`,m),e.once(`end`,h),e.once(`error`,g),e.once(`aborted`,_)})}async function Te(e,t,n){let{rawBody:r,preview:i}=await we(e,t,n);if(r===void 0||r.byteLength===0)return{body:{},preview:i};let a=Y(e.headers[`content-type`])?.toLowerCase()??``;if(a.includes(`json`)){let e=r.toString(`utf8`).trim();if(e.length===0)return{body:{},preview:i};try{let t=JSON.parse(e);return typeof t==`object`&&t&&!Array.isArray(t)?{body:t,preview:i}:{body:{value:t},preview:i}}catch{return{body:{raw:e},preview:i}}}return a.includes(`x-www-form-urlencoded`)?{body:H(new URLSearchParams(r.toString(`utf8`))),preview:i}:B(a)?{body:{raw:r.toString(`utf8`)},preview:i}:{body:{},preview:i}}function Ee(e){if(!e)return{};let t={},n=e.split(`;`);for(let e of n){let[n,...r]=e.split(`=`);if(!n)continue;let i=n.trim(),a=r.join(`=`).trim();t[i]=decodeURIComponent(a)}return t}const Z=(e,t,n)=>Promise.race([e,new Promise(e=>setTimeout(()=>e(n),t))]);function De(e){let t=Object.freeze({logger:e.logger}),n=async(n,r)=>{let i=n.method??`GET`,a=ce(n),o=V(n.url);if(o===void 0){I(r,{message:`Bad Request: req.url is undefined`},400);return}let s={method:i,ip:a,url:o,query:H(o.searchParams),body:{},headers:n.headers,cookie:Ee(n.headers.cookie),meta:{}},c={exists:!1,bytes:0,truncated:!1};e.logger.info({message:`request`,method:i,ip:a,path:o.pathname});let l=performance.now();r.once(`finish`,()=>{let t={workerId:process.env.WORKER_ID??`[primary]`,message:`response`,method:i,ip:a,path:o.pathname,status:r.statusCode,duration:(performance.now()-l).toFixed(4)};Object.keys(s.query).length>0&&(t.query=s.query),c.exists&&(t.body=c.value,t.bodyBytes=c.bytes,t.bodyTruncated=c.truncated),e.logger.info(t)});try{if(s.url.pathname.startsWith(`/_fluxion/`)){I(r,{message:`Not Found`},404);return}let i=await Te(n,s.method,e.options.maxRequestBytes);s.body=i.body,c=i.preview;let a=await e.router.getModule(o);if(!a){I(r,{message:`Not Found`},404);return}if(n.method&&a.methods&&!a.methods.includes(n.method)){I(r,{message:`Method Not Allowed`},405);return}let l=a.type===0?a.handlerTimeoutMs??e.options.handlerTimeoutMs:e.options.staticResourceTimeoutMs;if(a.middlewares)for(let i=0;i<a.middlewares.length;i++){if(await Z(z(a.middlewares[i],s,t,n,r),e.options.middlewareTimeoutMs,D)===D){e.logger.warn({message:`MiddlewareTimeout`,method:s.method,ip:s.ip}),I(r,{message:`Internal Server Error`},500);return}if(r.writableEnded)return;if(r.headersSent){r.end();return}}let u=await Z(z(a.handler,s,t,n,r),l,E);if(u===E){e.logger.warn({message:`HandlerTimeout`,method:s.method,ip:s.ip}),I(r,{message:`Handler timed out`},500);return}u!==T&&I(r,u)}catch(t){t instanceof U?(e.logger.error({message:`RequestFailed`,method:s.method,ip:s.ip,path:s.url.pathname,error:t.message}),I(r,{message:t.message},t.errno)):(e.logger.error({message:`RequestFailed`,method:s.method,ip:s.ip,path:s.url.pathname,error:C(t)}),I(r,{message:C(t)},t.errno??500))}},r=e.options.https?m.default.createServer({key:e.options.https.key,cert:e.options.https.cert,ca:e.options.https.ca},n):p.default.createServer(n);return new Promise((t,n)=>{let i=!1;r.on(`close`,()=>{e.logger.info({message:`ServerClosed`,host:e.options.host,port:e.options.port})}),r.once(`listening`,()=>{i=!0,e.logger.info({message:`ServerStarted`,pid:process.pid,protocol:e.options.https?`https`:`http`,host:e.options.host,port:e.options.port}),e.logger.info({message:`DynamicDirectory`,directory:e.options.dir}),t(r)}),r.on(`error`,t=>{e.logger.error({message:`ServerError`,error:C(t)}),i&&process.exit(1),n(t)}),r.listen(e.options.port,e.options.host)})}const Oe=()=>{let e=process.cpuUsage(),t=Date.now();setInterval(()=>{let n=Date.now(),r=Math.max(1,(n-t)*1e3),i=process.cpuUsage(e),a=Number(((i.user+i.system)/r*100).toFixed(2));e=process.cpuUsage(),t=n;let o=process.memoryUsage();N({type:203,pid:process.pid,stats:{at:n,pid:process.pid,uptimeSeconds:Number(process.uptime().toFixed(3)),cpu:{userMicros:i.user,systemMicros:i.system,percent:a},memory:{rss:o.rss,heapTotal:o.heapTotal,heapUsed:o.heapUsed,external:o.external,arrayBuffers:o.arrayBuffers}}})},2e3).unref()};function ke(e){if(c.default.isPrimary)throw Error(`[fluxion error] createWorker should only be called in worker process`);process.on(`message`,t=>{if(ae(t)){if(t.type===100){N({type:202,pid:process.pid,sentAt:t.sentAt,receivedAt:Date.now()});return}t.type===101&&N({type:204,pid:process.pid,requestId:t.requestId,routes:e.router.getRoutes()})}}),N({type:200,pid:process.pid}),Oe();let t,n=!1,r=r=>{n||(n=!0,e.logger.warn({message:`WorkerShuttingDown`,pid:process.pid,signal:r}),e.watcher.stop(),t||process.exit(0),setTimeout(()=>process.exit(1),1e4).unref(),t.close(t=>{t&&(e.logger.error({message:`WorkerShutdownFailed`,pid:process.pid,error:C(t)}),process.exit(1)),process.exit(0)}))};process.once(`SIGINT`,r),process.once(`SIGTERM`,r),De(e).then(e=>{t=e,N({type:201,pid:process.pid})}).catch(t=>{e.logger.error({message:`WorkerBootstrapFailed`,pid:process.pid,error:C(t)}),e.watcher.stop(),process.exit(1)})}var Q=class{cx;timer=null;filesChanged=new Map;constructor(e){this.cx=e}async init(){let e=this.cx.options.dir;if(!u.default.existsSync(e))return this.cx.logger.warn(`Directory does not exist: ${e}`),this;let t=[],n=(e,r)=>{let i=u.default.readdirSync(e,{withFileTypes:!0});for(let a=0;a<i.length;a++){let o=i[a],s=d.default.join(e,o.name),c=d.default.join(r,o.name);if(o.isDirectory())n(s,c);else if(o.isFile()){let e=this.cx.router.register(s,c).catch(e=>{this.cx.logger.error(`Error registering file ${c}: ${e.message}`)});t.push(e)}}};return n(e,``),await Promise.all(t),this.cx.logger.info(`Initial registration complete for directory: ${e}`),this}queueUp(e,t){this.filesChanged.set(e,t),!this.timer&&(this.timer=setTimeout(async()=>{let e=[...this.filesChanged].map(([e,t])=>this.cx.router.register(e,t).catch(e=>this.cx.logger.error(`Error refreshing handlers: ${e.message}`)).finally(()=>this.filesChanged.delete(e)));await Promise.all(e),this.timer=null},this.cx.options.reloadDelay))}stopCore(){this.timer&&=(clearTimeout(this.timer),null),this.filesChanged.clear()}},Ae=class extends Q{watcher=null;constructor(e){super(e)}async start(){this.stop(),await this.init();let e=this.cx.options.dir;return this.watcher=h.default.watch(e,{persistent:!0,ignoreInitial:!0,usePolling:!1,awaitWriteFinish:{stabilityThreshold:100,pollInterval:50}}).on(`all`,(t,n)=>{n&&this.queueUp(n,d.default.relative(e,n))}).on(`error`,e=>{let t=e instanceof Error?e:Error(String(e));this.cx.logger.error(`Watcher error: ${t.message}`),this.cx.logger.error(`Restarting watcher...`),this.start()}).on(`ready`,()=>{this.cx.logger.info(`Watcher ready and watching directory: ${e}`)}),this.cx.logger.info(`Watcher started on directory: ${e}`),this}stop(){return this.watcher&&=(this.watcher.close(),null),this.stopCore(),this}},je=class extends Q{watcher=null;constructor(e){super(e)}async start(){this.stop(),await this.init();let e=this.cx.options.dir;return this.watcher=u.default.watch(e,{recursive:!0},(t,n)=>{n&&this.queueUp(d.default.join(e,n),n)}).on(`error`,e=>{this.cx.logger.error(`Watcher error: ${e.message}`),this.cx.logger.error(`Restarting watcher...`),this.start()}),this.cx.logger.info(`Watcher started on directory: ${e}`),this}stop(){return this.watcher&&=(this.watcher.close(),null),this.stopCore(),this}};function Me(e){}const Ne=Me;function $(e,t){if(typeof t!=`object`||!t)return!1;if(Ne(t),typeof t.handler!=`function`)return e.logger.error(`handler must be a function`),!1;if(t.disposer!==void 0&&typeof t.disposer!=`function`)return e.logger.error(`disposer must be a function if provided`),!1;let n=t.handlerTimeoutMs;return n!==void 0&&(!Number.isSafeInteger(n)||n<100)?(e.logger.error(`handlerTimeoutMs must be an integer >= 100 if provided`),!1):t.type===0?!0:(e.logger.error(`You must use defineFluxionModule to create module`),!1)}function Pe(e,t){delete require.cache[t];let n=require(t);if($(e,n.default))n=n.default;else if(!$(e,n))throw Error(`[fluxion error] Invalid handler module '${t}', make sure it satisfies defineFluxionModule(...) helper`);return n}var Fe=class{cx;handlers=new Map;constructor(e){this.cx=e}makeStaticResource(e){return{type:1,handler:async(t,n,r,i)=>{if(t.method!==`GET`&&t.method!==`HEAD`){i.statusCode=405,i.setHeader(`Allow`,`GET, HEAD`),i.end();return}if(!u.default.existsSync(e)){i.statusCode=404,i.end(`Not Found`);return}let a=u.default.statSync(e);if(!a.isFile()){i.statusCode=404,i.end(`Not Found`);return}let o=re[d.default.extname(e).toLowerCase()]??`application/octet-stream`;if(i.statusCode=200,i.setHeader(`Content-Type`,o),i.setHeader(`Content-Length`,String(a.size)),t.method===`HEAD`){i.end();return}return new Promise((t,n)=>{let a=u.default.createReadStream(e),o=()=>{a.off(`error`,s),a.off(`end`,c),i.off(`close`,l),r.off(`aborted`,l)},s=e=>{o(),n(e)},c=()=>{o(),t(T)},l=()=>{o(),a.destroy(),t(T)};a.on(`error`,s),a.on(`end`,c),i.on(`close`,l),r.on(`aborted`,l),a.pipe(i)})}}}async register(e,t){let n=this.handlers.get(t)?.disposer;if(n&&await z(n),!u.default.existsSync(e)){this.handlers.delete(t),this.cx.logger.info({action:`Delete`,url:t});return}if(!this.cx.options.include.some(e=>(0,g.minimatch)(t,e))){this.handlers.delete(t),this.cx.logger.info({action:`Skip`,url:t});return}if(this.cx.options.exclude.some(e=>(0,g.minimatch)(t,e))){this.handlers.delete(t),this.cx.logger.info({action:`Exclude`,url:t});return}if(this.cx.options.apiInclude.some(e=>(0,g.minimatch)(t,e))){let n=Pe(this.cx,e);this.handlers.set(t,n),this.cx.logger.info({action:`RegisterApi`,url:t});return}this.handlers.set(t,this.makeStaticResource(e)),this.cx.logger.info({action:`RegisterStatic`,url:t})}getModule(e){let t=e.pathname.replace(/^[/]+/,``).replace(/[/]+$/,``);return this.handlers.get(t)}getRoutes(){return[...this.handlers.entries()].map(([e,t])=>({path:`/`+e,type:t.type===0?`api`:`static`,methods:t.methods?[...t.methods]:null})).sort((e,t)=>e.path.localeCompare(t.path))}};async function Ie(e){let t={options:e.normalizedFlag===w?e:j(e)};t.logger=te(t),t.router=new Fe(t),c.default.isPrimary?se(t):(t.logger=ne(t.logger,process.pid),t.watcher=await new(t.options.nativeWatcher?je:Ae)(t).start(),ke(t))}function Le(e,t){if(typeof e==`function`){if(t!==void 0&&typeof t!=`function`)throw Error(`[fluxion error] Invalid disposer, expected a function but got ${typeof t}`);return{handler:e,disposer:t,type:0}}if(typeof e!=`object`||!e)throw Error(`[fluxion error] Invalid argument, expected a FluxionModule object or a handler function, but got ${typeof e}`);if(typeof e.handler!=`function`)throw Error(`[fluxion error] Invalid FluxionModule, "handler" must be a function`);if(e.disposer!==void 0&&typeof e.disposer!=`function`)throw Error(`[fluxion error] Invalid FluxionModule, "disposer" must be a function if provided`);if(e.methods!==void 0&&(!Array.isArray(e.methods)||e.methods.some(e=>typeof e!=`string`)))throw Error(`[fluxion error] Invalid FluxionModule, "methods" must be an array of strings if provided`);if(e.middlewares!==void 0&&(!Array.isArray(e.middlewares)||e.middlewares.some(e=>typeof e!=`function`)))throw Error(`[fluxion error] Invalid FluxionModule, "middlewares" must be an array of functions if provided`);return{...e,type:0}}function Re(e){if(typeof e!=`function`)throw Error(`[fluxion error] Invalid FluxionMiddleware, expected a function but got ${typeof e}`);return e}function ze(e){if(typeof e!=`function`)throw Error(`[fluxion error] Invalid FluxionLoggerFn, expected a function but got ${typeof e}`);return e}exports.BadGatewayException=be,exports.BadRequestException=W,exports.ConflictException=me,exports.ForbiddenException=le,exports.GatewayTimeoutException=Se,exports.GoneException=he,exports.HttpCode=O,exports.HttpException=U,exports.InternalServerErrorException=ve,exports.MethodNotAllowedException=de,exports.NotAcceptableException=fe,exports.NotFoundException=ue,exports.NotImplementedException=ye,exports.PayloadTooLargeException=K,exports.RequestTimeoutException=pe,exports.ServiceUnavailableException=xe,exports.TooManyRequestsException=_e,exports.UnauthorizedException=G,exports.UnprocessableEntityException=ge,exports.UnsupportedMediaTypeException=q,exports.defineFluxionLogger=ze,exports.defineFluxionMiddleware=Re,exports.defineFluxionModule=Le,exports.defineFluxionOptions=j,exports.fluxion=Ie;
2
2
  //# sourceMappingURL=index.cjs.map