fluxion-ts 0.13.5 → 0.14.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/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/cli.cjs +0 -3
- package/dist/cli.cjs.map +0 -1
- package/dist/cli.d.cts +0 -1
- package/dist/cli.d.mts +0 -1
- package/dist/cli.mjs +0 -3
- package/dist/cli.mjs.map +0 -1
- package/dist/fluxion--NlXBaPd.mjs +0 -2
- package/dist/fluxion--NlXBaPd.mjs.map +0 -1
- package/dist/fluxion-B4A8HXmW.cjs +0 -2
- package/dist/fluxion-B4A8HXmW.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./fluxion-B4A8HXmW.cjs");function t(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 n(e){if(typeof e!=`function`)throw Error(`[fluxion error] Invalid FluxionMiddleware, expected a function but got ${typeof e}`);return e}function r(e){if(typeof e!=`function`)throw Error(`[fluxion error] Invalid FluxionLoggerFn, expected a function but got ${typeof e}`);return e}exports.BadGatewayException=e.n,exports.BadRequestException=e.r,exports.ConflictException=e.i,exports.ForbiddenException=e.a,exports.GatewayTimeoutException=e.o,exports.GoneException=e.s,exports.HttpCode=e.C,exports.HttpException=e.c,exports.InternalServerErrorException=e.l,exports.MethodNotAllowedException=e.u,exports.NotAcceptableException=e.d,exports.NotFoundException=e.f,exports.NotImplementedException=e.p,exports.PayloadTooLargeException=e.m,exports.RequestTimeoutException=e.h,exports.ServiceUnavailableException=e.g,exports.TooManyRequestsException=e._,exports.UnauthorizedException=e.v,exports.UnprocessableEntityException=e.y,exports.UnsupportedMediaTypeException=e.b,exports.defineFluxionLogger=r,exports.defineFluxionMiddleware=n,exports.defineFluxionModule=t,exports.defineFluxionOptions=e.S,exports.fluxion=e.t;
|
|
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 C(e){let t=e.options.logger;return t===void 0||t===`one-line`?S:t===`json-line`?e=>console.log(b(e)):t}function ee(e){let t=C(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 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`),te={".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 ne=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 re(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:re(l),maxRequestBytes:f,logger:b,include:m,apiInclude:h,exclude:g,nativeWatcher:v,metaSecret:y,https:ie(_,S),normalizedFlag:E}}const ae=e=>[100,101].includes(e?.type),oe=e=>[202,200,201,203,204].includes(e?.type),M=e=>process.send?.(e),N=(e,t)=>e.send(t);function P(e,t,n=200){e.statusCode=n,e.setHeader(`Content-Type`,`application/json; charset=utf-8`),e.end(JSON.stringify(t))}function F(e,t,n=200){if(!e.writableEnded){if(e.headersSent){e.end();return}P(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{P(i,{message:`Bad Request: invalid url`},400);return}if(a===`GET`&&o.pathname===`/_fluxion/healthz`){P(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`){P(i,{ok:!0,now:Date.now(),workers:t()});return}if(a===`GET`&&o.pathname===`/_fluxion/routes`){if(!e.options.metaSecret){P(i,{message:`Not Found`},404);return}if(o.searchParams.get(`secret`)!==e.options.metaSecret){P(i,{message:`Forbidden`},403);return}let t=await n();P(i,{ok:!0,now:Date.now(),routes:t});return}P(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 I=new class e{instanceFilePath;isUnregistering=!1;static KILL_POLL_INTERVAL_MS=300;static SIGTERM_TIMEOUT_MS=1e4;static SIGKILL_TIMEOUT_MS=1e3;constructor(){let e=d.default.join(f.default.homedir(),`.fluxion`);this.instanceFilePath=d.default.join(e,`instances.json`),u.default.existsSync(e)||u.default.mkdirSync(e,{recursive:!0}),process.on(`exit`,()=>this.unregister())}isAlive(e){try{return process.kill(e,0),!0}catch{return!1}}readAlive(){let e=[];try{if(u.default.existsSync(this.instanceFilePath)){let t=u.default.readFileSync(this.instanceFilePath,`utf-8`),n=JSON.parse(t);n.instances!==void 0&&!Array.isArray(n.instances)&&(console.error(`[FluxionInstanceManager] 'instances' of ${this.instanceFilePath} is not an array. It seems that the record file is corrupted`),e=[]),e=n.instances||[]}}catch(e){console.error(`[FluxionInstanceManager] Failed to read instance.json:`,e)}return e.filter(e=>this.isAlive(e.pid))}update(e){try{let t={instances:e};u.default.writeFileSync(this.instanceFilePath,JSON.stringify(t,null,2),`utf-8`)}catch(e){console.error(`[FluxionInstanceManager] Failed to write instance.json:`,e)}}async waitForExit(t,n){let r=Math.ceil(n/e.KILL_POLL_INTERVAL_MS);for(let n=0;n<r;n++){if(!this.isAlive(t))return!0;await new Promise(t=>{setTimeout(t,e.KILL_POLL_INTERVAL_MS)})}return!this.isAlive(t)}async kill(t){try{process.kill(t,`SIGTERM`)}catch(e){return console.error(`[FluxionInstanceManager] Failed to kill process ${t}:`,e),!1}if(await this.waitForExit(t,e.SIGTERM_TIMEOUT_MS))return!0;console.warn(`[FluxionInstanceManager] Process ${t} did not exit after SIGTERM, sending SIGKILL`);try{process.kill(t,`SIGKILL`)}catch(e){return console.error(`[FluxionInstanceManager] Failed to force kill process ${t}:`,e),!1}return this.waitForExit(t,e.SIGKILL_TIMEOUT_MS)}async register(e,t,n,r){let i=process.pid,a=process.cwd(),o=this.readAlive().find(t=>t.configPath===e);if(o){if(console.warn(`[FluxionInstanceManager] Found existing instance with same config or port: PID=${o.pid}, PORT=${o.port}`),!await this.kill(o.pid))throw Error(`[FluxionInstanceManager] Failed to stop old process ${o.pid}`);console.warn(`[FluxionInstanceManager] Killed old process ${o.pid}`);let e=this.readAlive().filter(e=>e.pid!==o.pid);this.update(e)}let s=this.readAlive().filter(e=>e.pid!==i),c={startTime:Date.now(),pid:i,host:t,port:n,metaPort:r,cwd:a,configPath:e};s.push(c),this.update(s),console.info(`[FluxionInstanceManager] Registered instance: PID=${i}, PORT=${n}, PATH=${e}`)}unregister(){if(this.isUnregistering)return;this.isUnregistering=!0;let e=process.pid;try{let t=this.readAlive(),n=t.filter(t=>t.pid!==e);n.length!==t.length&&(this.update(n),console.info(`[FluxionInstanceManager] Unregistered instance: PID=${e}`))}finally{this.isUnregistering=!1}}print(){let e=this.readAlive();console.info(`[FluxionInstanceManager] Current instances:`);for(let t of e)console.info(` - PID: ${t.pid}, PORT: ${t.port}, PATH: ${t.configPath}, START: ${new Date(t.startTime).toISOString()}`)}};async function ce(e,t,n,r){await I.register(e,t,n,r)}async function le(){await I.unregister()}const L=e=>Number((e/1024/1024).toFixed(2)),R=6e4,z=1e4;var ue=class{cx;workers=new Map;routeRequests=new Map;restartLog=new Map;configPath;restartWhen;workerCount;routeRequestId=0;pingTimer;metaServer;shuttingDown=!1;shutdownPromise=null;constructor(e){this.cx=e,this.configPath=d.default.join(e.options.moduleDir||process.cwd(),`fluxion.config.ts`),this.restartWhen=e.options.workerOptions.restartWhen,this.metaServer=se(this.cx,()=>this.getWorkersSnapshot(),()=>this.getRoutesSnapshot());let t=Math.max(1,f.default.cpus().length);this.workerCount=Math.max(1,Math.min(e.options.workerOptions.maxWorkerCount??Math.min(2,t),t))}async start(){await ce(this.configPath,this.cx.options.host,this.cx.options.port,this.cx.options.metaPort),this.cx.logger.info({message:`PrimaryStarted`,pid:process.pid,workers:this.workerCount,host:this.cx.options.host,port:this.cx.options.port,metaPort:this.cx.options.metaPort}),this.registerProcessHandlers();for(let e=0;e<this.workerCount;e++)this.spawnSlot(e+1);this.startPingLoop()}registerProcessHandlers(){let e=e=>{this.beginShutdown(e)};process.once(`SIGINT`,()=>e(`SIGINT`)),process.once(`SIGTERM`,()=>e(`SIGTERM`))}restartCountInWindow(e){let t=Date.now(),n=(this.restartLog.get(e)??[]).filter(e=>t-e<R);return this.restartLog.set(e,n),n.length}recordRestart(e){let t=Date.now(),n=(this.restartLog.get(e)??[]).filter(e=>t-e<R);n.push(t),this.restartLog.set(e,n)}isStorming(e){return this.restartCountInWindow(e)>=3}getWorkersSnapshot(){return{primaryPid:process.pid,host:this.cx.options.host,port:this.cx.options.port,metaPort:this.cx.options.metaPort,uptimeSeconds:Number(process.uptime().toFixed(3)),shuttingDown:this.shuttingDown,workers:Array.from(this.workers.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)}}}})}}getRoutesSnapshot(){let e=Array.from(this.workers.values()).find(e=>e.state===`ready`&&e.instance.isConnected());return e?new Promise(t=>{let n=++this.routeRequestId,r=setTimeout(()=>{this.routeRequests.delete(n),t([])},1e3);r.unref(),this.routeRequests.set(n,{resolve:t,timer:r});try{N(e.instance,{type:101,requestId:n})}catch{clearTimeout(r),this.routeRequests.delete(n),t([])}}):Promise.resolve([])}initiateRecycle(e,t){if(!this.shuttingDown){for(let e of this.workers.values())if(e.state===`restarting`)return;if(this.isStorming(e.slot)){this.cx.logger.warn({message:`WorkerRecycleSuppressed`,slot:e.slot,pid:e.pid,reason:t,windowMs:R,max:3});return}this.recordRestart(e.slot),e.state=`restarting`,e.restartReason=t,this.cx.logger.warn({message:`WorkerRecycling`,slot:e.slot,pid:e.pid,reason:t}),e.instance.kill()}}evaluateResourceConditions(e,t){if(this.shuttingDown)return;let n=L(t.memory.rss);if(n>this.restartWhen.memoryUsageGreaterThan){this.initiateRecycle(e,`memoryUsageGreaterThan: rss ${n}MB > ${this.restartWhen.memoryUsageGreaterThan}MB`);return}let r=t.uptimeSeconds*1e3;r>this.restartWhen.uptimeGreaterThan&&this.initiateRecycle(e,`uptimeGreaterThan: ${Math.round(r/1e3)}s > ${Math.round(this.restartWhen.uptimeGreaterThan/1e3)}s`)}evaluateLiveness(e){if(!this.shuttingDown)for(let t of this.workers.values()){if(t.state!==`ready`||t.lastPongAt===void 0)continue;let n=e-t.lastPongAt;n>this.restartWhen.healthzTimeout&&this.initiateRecycle(t,`healthzTimeout: no pong for ${Math.round(n/1e3)}s > ${Math.round(this.restartWhen.healthzTimeout/1e3)}s`)}}spawnSlot(e){this.shuttingDown||this.attachWorker(c.default.fork({WORKER_ID:String(e)}),e)}attachWorker(e,t){let n={state:`creating`,pid:e.process.pid,slot:t,createdAt:Date.now(),instance:e};this.workers.set(e.id,n),e.on(`message`,r=>{if(oe(r)){if(r.type===202){let e=Date.now()-r.sentAt;n.pid=r.pid,n.lastPongAt=Date.now(),n.lastRttMs=e;return}if(r.type===201){n.state=`ready`,n.pid=r.pid,n.readyAt=Date.now(),this.cx.logger.info({message:`WorkerReady`,workerId:e.id,slot:t,pid:r.pid});return}if(r.type===200){n.state=`created`,n.pid=r.pid,this.cx.logger.info({message:`WorkerCreated`,workerId:e.id,slot:t,pid:r.pid});return}if(r.type===203){n.pid=r.pid,n.lastStats=r.stats,n.state===`ready`&&this.evaluateResourceConditions(n,r.stats);return}if(r.type===204){let e=this.routeRequests.get(r.requestId);e&&(clearTimeout(e.timer),this.routeRequests.delete(r.requestId),e.resolve(r.routes))}}}),e.on(`exit`,(t,n)=>{let r=this.workers.get(e.id);this.workers.delete(e.id);let i=r?.slot,a=r?.state===`restarting`||this.shuttingDown,o=r?.restartReason??(this.shuttingDown?`shutdown`:null);if(this.cx.logger.warn({message:`WorkerExited`,workerId:e.id,slot:i??null,pid:e.process.pid??`unknown`,code:t,signal:n??`none`,expected:a,reason:o}),!(i===void 0||this.shuttingDown)){if(r?.state===`restarting`){this.spawnSlot(i);return}if(this.recordRestart(i),this.isStorming(i)){this.cx.logger.error({message:`WorkerRespawnSuppressed`,slot:i,windowMs:R,max:3});return}this.spawnSlot(i)}})}startPingLoop(){this.pingTimer=setInterval(()=>{let e=Date.now();for(let t of this.workers.values())if(t.instance.isConnected())try{N(t.instance,{type:100,sentAt:e})}catch{}this.evaluateLiveness(Date.now())},5e3),this.pingTimer.unref()}stopTimers(){this.pingTimer&&=(clearInterval(this.pingTimer),void 0);for(let[e,t]of this.routeRequests.entries())clearTimeout(t.timer),t.resolve([]),this.routeRequests.delete(e)}getAliveWorkers(){return Array.from(this.workers.values()).filter(e=>!e.instance.isDead())}async waitForWorkersToExit(e){let t=Date.now()+e;for(;Date.now()<t;){if(this.getAliveWorkers().length===0)return[];await new Promise(e=>{setTimeout(e,200)})}return this.getAliveWorkers()}async forceKillWorkers(e){for(let t of e){let e=t.pid??t.instance.process.pid;this.cx.logger.error({message:`WorkerForceKilled`,slot:t.slot,pid:e??null});try{t.instance.process.kill(`SIGKILL`)}catch{}}await this.waitForWorkersToExit(1e3)}async shutdownWorkers(e){let t=this.getAliveWorkers();for(let n of t){let t=n.pid??n.instance.process.pid;this.cx.logger.warn({message:`WorkerShutdownRequested`,slot:n.slot,pid:t??null,signal:e});try{n.instance.kill(e)}catch{}}let n=await this.waitForWorkersToExit(z);n.length!==0&&(this.cx.logger.error({message:`PrimaryShutdownTimeout`,pid:process.pid,remainingWorkers:n.map(e=>({slot:e.slot,pid:e.pid??e.instance.process.pid??null})),timeoutMs:z}),await this.forceKillWorkers(n))}async beginShutdown(e){if(this.shutdownPromise)return this.shutdownPromise;this.shutdownPromise=(async()=>{this.shuttingDown=!0,this.cx.logger.warn({message:`PrimaryShuttingDown`,pid:process.pid,signal:e,workerCount:this.workers.size}),this.stopTimers();try{await this.shutdownWorkers(e)}finally{this.metaServer.close(),await le()}})();try{await this.shutdownPromise,process.exit(0)}catch(t){this.cx.logger.error({message:`PrimaryShutdownFailed`,pid:process.pid,signal:e,error:t instanceof Error?t.message:String(t)}),process.exit(1)}}};async function B(e){if(!c.default.isPrimary)throw Error(`[fluxion error] createPrimary should only be called in primary process`);await new ue(e).start()}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 H(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 U(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 de(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}},fe=class extends G{constructor(e=`Bad Request`){super(e,400,`BAD_REQUEST`)}},pe=class extends G{constructor(e=`Unauthorized`){super(e,401,`UNAUTHORIZED`)}},me=class extends G{constructor(e=`Forbidden`){super(e,403,`FORBIDDEN`)}},he=class extends G{constructor(e=`Not Found`){super(e,404,`NOT_FOUND`)}},ge=class extends G{constructor(e=`Method Not Allowed`){super(e,405,`METHOD_NOT_ALLOWED`)}},_e=class extends G{constructor(e=`Not Acceptable`){super(e,406,`NOT_ACCEPTABLE`)}},ve=class extends G{constructor(e=`Request Timeout`){super(e,408,`REQUEST_TIMEOUT`)}},ye=class extends G{constructor(e=`Conflict`){super(e,409,`CONFLICT`)}},be=class extends G{constructor(e=`Gone`){super(e,410,`GONE`)}},K=class extends G{constructor(e=`Payload Too Large`){super(e,413,`PAYLOAD_TOO_LARGE`)}},xe=class extends G{constructor(e=`Unsupported Media Type`){super(e,415,`UNSUPPORTED_MEDIA_TYPE`)}},Se=class extends G{constructor(e=`Unprocessable Entity`){super(e,422,`UNPROCESSABLE_ENTITY`)}},q=class extends G{constructor(e=`Too Many Requests`){super(e,429,`TOO_MANY_REQUESTS`)}},Ce=class extends G{constructor(e=`Internal Server Error`){super(e,500,`INTERNAL_SERVER_ERROR`)}},we=class extends G{constructor(e=`Not Implemented`){super(e,501,`NOT_IMPLEMENTED`)}},Te=class extends G{constructor(e=`Bad Gateway`){super(e,502,`BAD_GATEWAY`)}},Ee=class extends G{constructor(e=`Service Unavailable`){super(e,503,`SERVICE_UNAVAILABLE`)}},De=class extends G{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 Oe(e,t,n,r){return t===0?X():U(n)?{exists:!0,value:e.toString(`utf8`),bytes:t,truncated:r}:{exists:!0,value:`<binary body: ${t} bytes>`,bytes:t,truncated:r}}async function ke(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:Oe(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 Ae(e,t,n){let{rawBody:r,preview:i}=await ke(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:W(new URLSearchParams(r.toString(`utf8`))),preview:i}:U(a)?{body:{raw:r.toString(`utf8`)},preview:i}:{body:{},preview:i}}function je(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 Me(e){let t=Object.freeze({logger:e.logger}),n=async(n,r)=>{let i=n.method??`GET`,a=H(n),o=de(n.url);if(o===void 0){F(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:je(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/`)){F(r,{message:`Not Found`},404);return}let i=await Ae(n,s.method,e.options.maxRequestBytes);s.body=i.body,c=i.preview;let a=await e.router.getModule(o);if(!a){F(r,{message:`Not Found`},404);return}if(n.method&&a.methods&&!a.methods.includes(n.method)){F(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,k)===k){e.logger.warn({message:`MiddlewareTimeout`,method:s.method,ip:s.ip}),F(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,O);if(u===O){e.logger.warn({message:`HandlerTimeout`,method:s.method,ip:s.ip}),F(r,{message:`Handler timed out`},500);return}u!==D&&F(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}),F(r,{message:t.message},t.errno)):(e.logger.error({message:`RequestFailed`,method:s.method,ip:s.ip,path:s.url.pathname,error:T(t)}),F(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)})}var Ne=class{cx;server;statsTimer;exiting=!1;constructor(e){this.cx=e}start(){this.registerMessageHandler(),this.registerSignalHandlers(),M({type:200,pid:process.pid}),this.startStatsReporter(),Me(this.cx).then(e=>{this.server=e,M({type:201,pid:process.pid})}).catch(e=>{this.cx.logger.error({message:`WorkerBootstrapFailed`,pid:process.pid,error:T(e)}),this.cx.watcher.stop(),process.exit(1)})}registerMessageHandler(){process.on(`message`,e=>{if(ae(e)){if(e.type===100){M({type:202,pid:process.pid,sentAt:e.sentAt,receivedAt:Date.now()});return}e.type===101&&M({type:204,pid:process.pid,requestId:e.requestId,routes:this.cx.router.getRoutes()})}})}startStatsReporter(){let e=process.cpuUsage(),t=Date.now();this.statsTimer=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();M({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),this.statsTimer.unref()}registerSignalHandlers(){process.once(`SIGINT`,()=>{this.shutdown(`SIGINT`)}),process.once(`SIGTERM`,()=>{this.shutdown(`SIGTERM`)})}stopStatsReporter(){this.statsTimer&&=(clearInterval(this.statsTimer),void 0)}async shutdown(e){if(this.exiting)return;this.exiting=!0,this.cx.logger.warn({message:`WorkerShuttingDown`,pid:process.pid,signal:e}),this.stopStatsReporter(),this.cx.watcher.stop(),this.server||process.exit(0);let t=setTimeout(()=>{process.exit(1)},1e4);t.unref(),this.server.close(e=>{clearTimeout(t),e&&(this.cx.logger.error({message:`WorkerShutdownFailed`,pid:process.pid,error:T(e)}),process.exit(1)),process.exit(0)})}};function Pe(e){if(c.default.isPrimary)throw Error(`[fluxion error] createWorker should only be called in worker process`);new Ne(e).start()}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()}},Fe=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}},Ie=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 Le(e){}const Re=Le;function $(e,t){if(typeof t!=`object`||!t)return!1;if(Re(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 ze(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(!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=te[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(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 V(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=ze(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 Ve(e){let t={options:e.normalizedFlag===E?e:j(e)};t.logger=ee(t),t.router=new Be(t),c.default.isPrimary?await B(t):(t.logger=w(t.logger,process.pid),t.watcher=await new(t.options.nativeWatcher?Ie:Fe)(t).start(),Pe(t))}function He(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 Ue(e){if(typeof e!=`function`)throw Error(`[fluxion error] Invalid FluxionMiddleware, expected a function but got ${typeof e}`);return e}function We(e){if(typeof e!=`function`)throw Error(`[fluxion error] Invalid FluxionLoggerFn, expected a function but got ${typeof e}`);return e}exports.BadGatewayException=Te,exports.BadRequestException=fe,exports.ConflictException=ye,exports.ForbiddenException=me,exports.GatewayTimeoutException=De,exports.GoneException=be,exports.HttpCode=ne,exports.HttpException=G,exports.InternalServerErrorException=Ce,exports.MethodNotAllowedException=ge,exports.NotAcceptableException=_e,exports.NotFoundException=he,exports.NotImplementedException=we,exports.PayloadTooLargeException=K,exports.RequestTimeoutException=ve,exports.ServiceUnavailableException=Ee,exports.TooManyRequestsException=q,exports.UnauthorizedException=pe,exports.UnprocessableEntityException=Se,exports.UnsupportedMediaTypeException=xe,exports.defineFluxionLogger=We,exports.defineFluxionMiddleware=Ue,exports.defineFluxionModule=He,exports.defineFluxionOptions=j,exports.fluxion=Ve;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/defines/index.ts"],"sourcesContent":["import type {\n FluxionHandler,\n FluxionDisposer,\n FluxionModuleWithType,\n FluxionModule,\n FluxionMiddleware,\n} from '@/types.js';\nimport type { FluxionLoggerFn } from '@/common/logger.js';\nimport { FluxionModuleType } from '@/common/consts.js';\n\nexport { defineFluxionOptions } from './options.js';\n\n/**\n * Use handler function and optional disposer function to define a Fluxion module.\n * @param handler Main function that handles request and response instances\n * @param disposer Deal with resource cleanup when the server is about to close\n */\nexport function defineFluxionModule(handler: FluxionHandler, disposer?: FluxionDisposer): FluxionModuleWithType;\n/**\n * Provides type safety for defining Fluxion modules.\n */\nexport function defineFluxionModule(fluxionModule: FluxionModule): FluxionModuleWithType;\nexport function defineFluxionModule(\n a: FluxionModule | FluxionHandler,\n disposer?: FluxionDisposer,\n): FluxionModuleWithType {\n if (typeof a === 'function') {\n if (disposer !== undefined && typeof disposer !== 'function') {\n $throw(`Invalid disposer, expected a function but got ${typeof disposer}`);\n }\n return { handler: a, disposer, type: FluxionModuleType.Api };\n }\n\n if (typeof a !== 'object' || a === null) {\n $throw(`Invalid argument, expected a FluxionModule object or a handler function, but got ${typeof a}`);\n }\n\n if (typeof a.handler !== 'function') {\n $throw(`Invalid FluxionModule, \"handler\" must be a function`);\n }\n\n if (a.disposer !== undefined && typeof a.disposer !== 'function') {\n $throw(`Invalid FluxionModule, \"disposer\" must be a function if provided`);\n }\n\n if (a.methods !== undefined && (!Array.isArray(a.methods) || a.methods.some((v) => typeof v !== 'string'))) {\n $throw(`Invalid FluxionModule, \"methods\" must be an array of strings if provided`);\n }\n\n if (\n a.middlewares !== undefined &&\n (!Array.isArray(a.middlewares) || a.middlewares.some((v) => typeof v !== 'function'))\n ) {\n $throw(`Invalid FluxionModule, \"middlewares\" must be an array of functions if provided`);\n }\n\n return { ...a, type: FluxionModuleType.Api };\n}\n\nexport function defineFluxionMiddleware(middleware: FluxionMiddleware): FluxionMiddleware {\n if (typeof middleware !== 'function') {\n $throw(`Invalid FluxionMiddleware, expected a function but got ${typeof middleware}`);\n }\n return middleware;\n}\n\nexport function defineFluxionLogger(loggerFn: FluxionLoggerFn) {\n if (typeof loggerFn !== 'function') {\n $throw(`Invalid FluxionLoggerFn, expected a function but got ${typeof loggerFn}`);\n }\n return loggerFn;\n}\n"],"mappings":"6GAsBA,SAAgB,EACd,EACA,EACuB,CACvB,GAAI,OAAO,GAAM,WAAY,CAC3B,GAAI,IAAa,IAAA,IAAa,OAAO,GAAa,WAChD,MAAA,MAAA,iEAAwD,OAAO,GAAU,EAE3E,MAAO,CAAE,QAAS,EAAG,WAAU,KAAA,CAA4B,CAC7D,CAEA,GAAI,OAAO,GAAM,WAAY,EAC3B,MAAA,MAAA,oGAA2F,OAAO,GAAG,EAGvG,GAAI,OAAO,EAAE,SAAY,WACvB,MAAA,MAAA,qEAA4D,EAG9D,GAAI,EAAE,WAAa,IAAA,IAAa,OAAO,EAAE,UAAa,WACpD,MAAA,MAAA,kFAAyE,EAG3E,GAAI,EAAE,UAAY,IAAA,KAAc,CAAC,MAAM,QAAQ,EAAE,OAAO,GAAK,EAAE,QAAQ,KAAM,GAAM,OAAO,GAAM,QAAQ,GACtG,MAAA,MAAA,0FAAiF,EAGnF,GACE,EAAE,cAAgB,IAAA,KACjB,CAAC,MAAM,QAAQ,EAAE,WAAW,GAAK,EAAE,YAAY,KAAM,GAAM,OAAO,GAAM,UAAU,GAEnF,MAAA,MAAA,gGAAuF,EAGzF,MAAO,CAAE,GAAG,EAAG,KAAA,CAA4B,CAC7C,CAEA,SAAgB,EAAwB,EAAkD,CACxF,GAAI,OAAO,GAAe,WACxB,MAAA,MAAA,0EAAiE,OAAO,GAAY,EAEtF,OAAO,CACT,CAEA,SAAgB,EAAoB,EAA2B,CAC7D,GAAI,OAAO,GAAa,WACtB,MAAA,MAAA,wEAA+D,OAAO,GAAU,EAElF,OAAO,CACT"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["http","path","os","fs","https","http","fs","path","path","fs","path","fs","path","cluster"],"sources":["../src/common/dtm.ts","../src/common/color.ts","../src/common/logger.ts","../src/common/consts.ts","../src/defines/options.ts","../src/cluster/consts.ts","../src/cluster/communicate.ts","../src/http/respond.ts","../src/cluster/meta-api.ts","../src/cluster/launcher.ts","../src/cluster/primary.ts","../src/common/promise-try.ts","../src/http/headers.ts","../src/http/request.ts","../src/http/query.ts","../src/http/exceptions.ts","../src/http/body.ts","../src/http/cookie.ts","../src/cluster/server.ts","../src/cluster/worker.ts","../src/watcher/base.ts","../src/watcher/chokidar.ts","../src/watcher/native.ts","../node_modules/.pnpm/type-narrow@0.2.2/node_modules/type-narrow/dist/index.mjs","../src/common/injector.ts","../src/router/index.ts","../src/fluxion.ts","../src/defines/index.ts"],"sourcesContent":["export function dtm(dt = new Date()) {\n const y = dt.getFullYear();\n const m = String(dt.getMonth() + 1).padStart(2, '0');\n const d = String(dt.getDate()).padStart(2, '0');\n const hh = String(dt.getHours()).padStart(2, '0');\n const mm = String(dt.getMinutes()).padStart(2, '0');\n const ss = String(dt.getSeconds()).padStart(2, '0');\n const ms = String(dt.getMilliseconds()).padStart(3, '0');\n return `${y}.${m}.${d} ${hh}:${mm}:${ss}.${ms}`;\n}\n","const useColor = process.env.FLUXION_COLORS !== '0';\n\n/**\n * Color Control Characters for Terminal (cctl)\n */\nexport namespace cctl {\n export const reset = useColor ? '\\x1b[0m' : '';\n export const bold = useColor ? '\\x1b[1m' : '';\n export const dim = useColor ? '\\x1b[2m' : '';\n export const italic = useColor ? '\\x1b[3m' : '';\n export const underline = useColor ? '\\x1b[4m' : '';\n export const blink = useColor ? '\\x1b[5m' : '';\n export const inverse = useColor ? '\\x1b[7m' : '';\n\n export const black = useColor ? '\\x1b[30m' : '';\n export const red = useColor ? '\\x1b[31m' : '';\n export const green = useColor ? '\\x1b[32m' : '';\n export const yellow = useColor ? '\\x1b[33m' : '';\n export const blue = useColor ? '\\x1b[34m' : '';\n export const magenta = useColor ? '\\x1b[35m' : '';\n export const cyan = useColor ? '\\x1b[36m' : '';\n export const white = useColor ? '\\x1b[37m' : '';\n\n export const brightBlack = useColor ? '\\x1b[90m' : '';\n export const brightRed = useColor ? '\\x1b[91m' : '';\n export const brightGreen = useColor ? '\\x1b[92m' : '';\n export const brightYellow = useColor ? '\\x1b[93m' : '';\n export const brightBlue = useColor ? '\\x1b[94m' : '';\n export const brightMagenta = useColor ? '\\x1b[95m' : '';\n export const brightCyan = useColor ? '\\x1b[96m' : '';\n export const brightWhite = useColor ? '\\x1b[97m' : '';\n\n export const bgBlack = useColor ? '\\x1b[40m' : '';\n export const bgRed = useColor ? '\\x1b[41m' : '';\n export const bgGreen = useColor ? '\\x1b[42m' : '';\n export const bgYellow = useColor ? '\\x1b[43m' : '';\n export const bgBlue = useColor ? '\\x1b[44m' : '';\n export const bgMagenta = useColor ? '\\x1b[45m' : '';\n export const bgCyan = useColor ? '\\x1b[46m' : '';\n export const bgWhite = useColor ? '\\x1b[47m' : '';\n\n export const bgBrightBlack = useColor ? '\\x1b[100m' : '';\n export const bgBrightRed = useColor ? '\\x1b[101m' : '';\n export const bgBrightGreen = useColor ? '\\x1b[102m' : '';\n export const bgBrightYellow = useColor ? '\\x1b[103m' : '';\n export const bgBrightBlue = useColor ? '\\x1b[104m' : '';\n export const bgBrightMagenta = useColor ? '\\x1b[105m' : '';\n export const bgBrightCyan = useColor ? '\\x1b[106m' : '';\n export const bgBrightWhite = useColor ? '\\x1b[107m' : '';\n\n // 'rgb(225, 16, 248)';\n export const purple = useColor ? '\\x1b[38;2;225;16;248m' : '';\n // 'rgb(248, 147, 16)';\n export const orange = useColor ? '\\x1b[38;2;248;147;16m' : '';\n export const darkGreen = useColor ? '\\x1b[38;2;22;101;52m' : '';\n export const claude = useColor ? '\\x1b[38;2;217;119;87m' : '';\n export const deepseek = useColor ? '\\x1b[38;2;57;100;254m' : '';\n export const gpt = useColor ? '\\x1b[38;2;41;60;77m' : '';\n}\n","import type { FluxionContext } from '@/types.js';\nimport type { otherstring } from '@/global.js';\nimport stringify from 'fast-json-stable-stringify';\n\nimport { dtm } from './dtm.js';\nimport { cctl } from './color.js';\n\ntype LogLevel = 'INFO' | 'WARN' | 'ERROR' | 'SUCC' | 'DEBUG' | 'VERBOSE' | otherstring;\n\ninterface LogEntry {\n timestamp: string;\n level: LogLevel;\n [key: string]: unknown;\n}\n\nexport type LoggerOption = 'one-line' | 'json-line' | FluxionLoggerFn;\n\nexport type FluxionLoggerFn = (entry: LogEntry) => void;\n\nexport interface MessageObject {\n [key: string]: unknown;\n message?: string;\n}\n\nexport interface FluxionLogger {\n /**\n * [WARN] We assert that `fields` is an object or undefined.\n */\n write(level: LogLevel, messageOrObject: string | MessageObject): void;\n info(messageOrObject: string | MessageObject): void;\n warn(messageOrObject: string | MessageObject): void;\n error(messageOrObject: string | MessageObject): void;\n succ(messageOrObject: string | MessageObject): void;\n debug(messageOrObject: string | MessageObject): void;\n verbose(messageOrObject: string | MessageObject): void;\n}\n\nconst safeStringify = (value: unknown): string => {\n try {\n return stringify(value);\n } catch {\n return '[unserializable]';\n }\n};\n\nconst ColoredLevels: Record<LogLevel, string> = {\n INFO: `${cctl.cyan}INFO${cctl.reset}`,\n WARN: `${cctl.orange}WARN${cctl.reset}`,\n ERROR: `${cctl.red}ERROR${cctl.reset}`,\n SUCC: `${cctl.green}SUCC${cctl.reset}`,\n DEBUG: `${cctl.blue}DEBUG${cctl.reset}`,\n VERBOSE: `${cctl.purple}VERBOSE${cctl.reset}`,\n};\n\nexport const oneLineLogger: FluxionLoggerFn = (entry: LogEntry) => {\n const { level: rawLevel, timestamp: rawTimestamp, message: rawMessage, pid, ...fields } = entry;\n\n const timestamp = `${cctl.darkGreen}[${rawTimestamp}]${cctl.reset}`;\n const level = ColoredLevels[rawLevel] ?? rawLevel;\n const pidText = pid === undefined ? '' : ` [${pid}]`;\n const fieldsText = Object.keys(fields).length > 0 ? ` ${cctl.dim}${safeStringify(fields)}${cctl.reset}` : '';\n\n // eslint-disable-next-line @typescript-eslint/no-console\n console.log(`${timestamp} ${level}${pidText} ${rawMessage}${fieldsText}`);\n};\n\n/**\n * & Logger Options here is checked by normalizeOptions function.\n */\nfunction resolveLoggerSink(cx: Pick<FluxionContext, 'options'>): FluxionLoggerFn {\n const loggerOption = cx.options.logger;\n if (loggerOption === undefined || loggerOption === 'one-line') {\n return oneLineLogger;\n }\n\n if (loggerOption === 'json-line') {\n // eslint-disable-next-line @typescript-eslint/no-console\n return (entry: LogEntry) => console.log(safeStringify(entry));\n }\n\n return loggerOption;\n}\n\nexport function createLogger(cx: Pick<FluxionContext, 'options'>): FluxionLogger {\n const sink = resolveLoggerSink(cx);\n\n const logger: FluxionLogger = {\n write(level: LogLevel, o: string | object): void {\n const entry: LogEntry =\n typeof o === 'string'\n ? {\n message: o,\n timestamp: dtm(),\n level,\n }\n : {\n ...o,\n timestamp: dtm(),\n level,\n };\n\n try {\n sink(entry);\n } catch {\n // Ignore logger sink failures to avoid breaking request handling.\n }\n },\n info(messageOrObject: string | MessageObject): void {\n this.write('INFO', messageOrObject);\n },\n warn(messageOrObject: string | MessageObject): void {\n this.write('WARN', messageOrObject);\n },\n error(messageOrObject: string | MessageObject): void {\n this.write('ERROR', messageOrObject);\n },\n succ(messageOrObject: string | MessageObject): void {\n this.write('SUCC', messageOrObject);\n },\n debug(messageOrObject: string | MessageObject): void {\n this.write('DEBUG', messageOrObject);\n },\n verbose(messageOrObject: string | MessageObject): void {\n this.write('VERBOSE', messageOrObject);\n },\n };\n\n return logger;\n}\n\n/**\n * Create a worker logger that prefixes all log messages with the worker PID.\n */\nexport function createWorkerLogger(baseLogger: FluxionLogger, pid: number): FluxionLogger {\n return {\n write(level: LogLevel, messageOrObject: string | MessageObject): void {\n baseLogger.write(\n level,\n typeof messageOrObject === 'string' ? { message: messageOrObject, pid } : { ...messageOrObject, pid },\n );\n },\n info(messageOrObject: string | MessageObject): void {\n this.write('INFO', messageOrObject);\n },\n warn(messageOrObject: string | MessageObject): void {\n this.write('WARN', messageOrObject);\n },\n error(messageOrObject: string | MessageObject): void {\n this.write('ERROR', messageOrObject);\n },\n succ(messageOrObject: string | MessageObject): void {\n this.write('SUCC', messageOrObject);\n },\n debug(messageOrObject: string | MessageObject): void {\n this.write('DEBUG', messageOrObject);\n },\n verbose(messageOrObject: string | MessageObject): void {\n this.write('VERBOSE', messageOrObject);\n },\n };\n}\n\n/**\n * ! Error.isError needs Node.js 24\n */\nexport const getErrorMessage =\n typeof Error.isError === 'function'\n ? (e: unknown): string => (Error.isError(e) ? e.message : String(e))\n : (e: unknown): string => (e as any)?.message || String(e);\n","export const DUMMY_BASE_URL = 'http://fluxion.local';\nexport const META_PREFIX = '/_fluxion';\n\nexport const OPTIONS_NORMALIZED_FLAG = Symbol('fluxion.router.StaticHandled');\nexport const STATIC_HANDLED_FLAG = Symbol('fluxion.router.StaticHandled');\nexport const HANDLER_TIMEOUT_FLAG = Symbol('fluxion.handlerTimeout');\nexport const MIDDLEWARE_TIMEOUT_FLAG = Symbol('fluxion.middlewareTimeout');\n\nexport const STATIC_CONTENT_TYPES: Record<string, string> = {\n '.css': 'text/css; charset=utf-8',\n '.html': 'text/html; charset=utf-8',\n '.ico': 'image/x-icon',\n '.js': 'text/javascript; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.map': 'application/json; charset=utf-8',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.svg': 'image/svg+xml',\n '.txt': 'text/plain; charset=utf-8',\n '.webp': 'image/webp',\n};\n\nexport enum HttpCode {\n // 2xx Success\n Ok = 200,\n Created = 201,\n Accepted = 202,\n NoContent = 204,\n PartialContent = 206,\n\n // 3xx Redirection\n MovedPermanently = 301,\n Found = 302,\n NotModified = 304,\n TemporaryRedirect = 307,\n PermanentRedirect = 308,\n\n // 4xx Client Error\n BadRequest = 400,\n Unauthorized = 401,\n Forbidden = 403,\n NotFound = 404,\n MethodNotAllowed = 405,\n NotAcceptable = 406,\n RequestTimeout = 408,\n Conflict = 409,\n Gone = 410,\n PayloadTooLarge = 413,\n UnsupportedMediaType = 415,\n UnprocessableEntity = 422,\n TooManyRequests = 429,\n\n // 5xx Server Error\n InternalServerError = 500,\n NotImplemented = 501,\n BadGateway = 502,\n ServiceUnavailable = 503,\n GatewayTimeout = 504,\n}\n\nexport const enum HandlerResult {\n NotFound,\n Handled,\n}\n\nexport const enum FluxionModuleType {\n Api,\n StaticResource,\n}\n\nexport const noop = () => {};\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { WorkerOptions, NormalizedWorkerOptions, FluxionOptions, NormalizedFluxionOptions } from '../types.js';\nimport { OPTIONS_NORMALIZED_FLAG } from '@/common/consts.js';\n\n/**\n * Resolves worker options with framework defaults. All thresholds become\n * concrete numbers (`Infinity` disables a check) so the primary can evaluate\n * them without null-handling.\n */\nfunction resolveWorkerOptions(options: WorkerOptions = {}): NormalizedWorkerOptions {\n const rw = options.restartWhen ?? {};\n const healthzTimeout = rw.healthzTimeout ?? 30_000;\n // Ping runs every 5s; a threshold below 2x that would recycle healthy workers\n // (a ready worker's lastPongAt is normally ~5s old). Infinity disables.\n if (healthzTimeout !== Infinity && (!Number.isFinite(healthzTimeout) || healthzTimeout < 10_000)) {\n $throw('workerOptions.restartWhen.healthzTimeout must be a finite number >= 10000 (ms) or Infinity');\n }\n return {\n maxWorkerCount: options.maxWorkerCount ?? 4,\n restartWhen: {\n memoryUsageGreaterThan: rw.memoryUsageGreaterThan ?? Infinity,\n healthzTimeout,\n uptimeGreaterThan: rw.uptimeGreaterThan ?? Infinity,\n },\n };\n}\n\n/**\n * Read certificate content from a file path or return the content directly.\n */\nfunction readCertificateContent(content: string | Buffer, moduleDir: string): Buffer {\n if (Buffer.isBuffer(content)) {\n return content;\n }\n if (typeof content === 'string') {\n // Check if it looks like a file path (not a PEM certificate)\n // PEM certificates start with \"-----BEGIN\"\n if (!content.startsWith('-----BEGIN')) {\n const filePath = path.isAbsolute(content) ? content : path.join(moduleDir, content);\n if (fs.existsSync(filePath)) {\n return fs.readFileSync(filePath);\n }\n }\n return Buffer.from(content);\n }\n $throw('Certificate content must be a string or Buffer');\n}\n\n/**\n * Normalize HTTPS options.\n */\nfunction normalizeHttpsOptions(\n https: FluxionOptions['https'],\n moduleDir: string,\n): NormalizedFluxionOptions['https'] | undefined {\n if (!https) {\n return undefined;\n }\n\n if (typeof https !== 'object' || https === null || Array.isArray(https)) {\n $throw('FluxionOptions.https must be an object');\n }\n if (typeof https.key !== 'string') {\n $throw('FluxionOptions.https.key must be a string');\n }\n if (typeof https.cert !== 'string') {\n $throw('FluxionOptions.https.cert must be a string');\n }\n\n const result: NormalizedFluxionOptions['https'] = {\n key: readCertificateContent(https.key, moduleDir),\n cert: readCertificateContent(https.cert, moduleDir),\n };\n\n if (https.ca !== undefined) {\n if (Array.isArray(https.ca)) {\n result.ca = https.ca.map((item) => readCertificateContent(item, moduleDir));\n } else {\n result.ca = readCertificateContent(https.ca, moduleDir);\n }\n }\n\n return result;\n}\n\n/**\n * Normalize options and create necessary resources like the dynamic directory and logger.\n */\nexport function defineFluxionOptions(o: FluxionOptions): NormalizedFluxionOptions {\n if (typeof o !== 'object' || o === null || Array.isArray(o)) {\n $throw('FluxionOptions must be an object');\n }\n\n const {\n dir: rawDir,\n host,\n port,\n handlerTimeoutMs = 5000,\n middlewareTimeoutMs = 3000,\n staticResourceTimeoutMs = 10 * 600000,\n metaPort = port + 1,\n moduleDir: rawModuleDir = process.cwd(),\n workerOptions = {},\n maxRequestBytes = 8_000_000,\n reloadDelay = 500,\n include = ['**/*'],\n apiInclude = ['**/*.ts'],\n exclude = [\n '**/node_modules/**',\n '**/.git/**',\n '**/dist/**',\n '**/build/**',\n '**/.vscode/**',\n '**/.idea/**',\n '**/*.log',\n '**/.DS_Store',\n '**/coverage/**',\n '**/.nyc_output/**',\n '**/*.tmp',\n '**/*.temp',\n ],\n https,\n nativeWatcher = false,\n metaSecret,\n } = o as FluxionOptions;\n\n const logger = o.logger ?? 'one-line';\n if (logger !== 'one-line' && logger !== 'json-line' && typeof logger !== 'function') {\n $throw(`Invalid logger option, Must be 'one-line', 'json-line' or a custom logger function`);\n }\n\n if (typeof rawDir !== 'string') {\n $throw('FluxionOptions.dir must be a string');\n }\n const dir = path.resolve(rawDir);\n\n if (typeof rawModuleDir !== 'string') {\n $throw('FluxionOptions.moduleDir must be a string');\n }\n const moduleDir = path.resolve(rawModuleDir);\n\n if (typeof host !== 'string') {\n $throw('FluxionOptions.host must be a string');\n }\n\n if (!Number.isSafeInteger(handlerTimeoutMs) || handlerTimeoutMs <= 100) {\n $throw('FluxionOptions.handlerTimeoutMs must be an integer greater than 100');\n }\n\n if (!Number.isSafeInteger(middlewareTimeoutMs) || middlewareTimeoutMs <= 100) {\n $throw('FluxionOptions.middlewareTimeoutMs must be an integer greater than 100');\n }\n\n if (typeof reloadDelay !== 'number' || reloadDelay <= 0 || !Number.isSafeInteger(reloadDelay)) {\n $throw('FluxionOptions.reloadDelay must be a positive integer');\n }\n\n if (reloadDelay < 50) {\n $throw('FluxionOptions.reloadDelay must be greater than or equal to 50');\n }\n\n if (typeof port !== 'number' || !Number.isSafeInteger(port)) {\n $throw('FluxionOptions.port must be a positive integer');\n }\n\n if (port <= 1 || port > 65535) {\n $throw('FluxionOptions.port must be 1 ~ 65535');\n }\n\n if (typeof metaPort !== 'number' || !Number.isSafeInteger(metaPort)) {\n $throw('FluxionOptions.metaPort must be a positive integer');\n }\n\n if (metaPort <= 1 || metaPort > 65535) {\n $throw('FluxionOptions.metaPort must be 1 ~ 65535');\n }\n\n if (metaPort === port) {\n $throw('FluxionOptions.metaPort must be different from FluxionOptions.port');\n }\n\n if (typeof workerOptions !== 'object' || workerOptions === null || Array.isArray(workerOptions)) {\n $throw('FluxionOptions.workerOptions must be an object');\n }\n\n if (typeof maxRequestBytes !== 'number' || maxRequestBytes <= 0 || !Number.isSafeInteger(maxRequestBytes)) {\n $throw('FluxionOptions.maxRequestBytes must be a positive integer');\n }\n\n if (\n metaSecret !== undefined &&\n (typeof metaSecret !== 'string' ||\n metaSecret.length < 20 ||\n /\\s/.test(metaSecret) ||\n !/[A-Za-z]/.test(metaSecret) ||\n !/\\d/.test(metaSecret))\n ) {\n $throw(\n 'FluxionOptions.metaSecret must be a string with at least 20 characters, include both letters and digits, and contain no whitespace',\n );\n }\n\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n return {\n dir,\n host,\n port,\n handlerTimeoutMs,\n middlewareTimeoutMs,\n staticResourceTimeoutMs,\n reloadDelay,\n metaPort,\n moduleDir,\n workerOptions: resolveWorkerOptions(workerOptions),\n maxRequestBytes,\n logger,\n include,\n apiInclude,\n exclude,\n nativeWatcher,\n metaSecret,\n https: normalizeHttpsOptions(https, moduleDir),\n // !\n normalizedFlag: OPTIONS_NORMALIZED_FLAG,\n };\n}\n","import type { PrimaryMessage, WorkerMessage } from './types.js';\n\nexport const enum PrimaryAction {\n /**\n * Health check message, the worker should respond with Pong and the latency information\n */\n Ping = 100,\n\n /**\n * Ask a worker for its current router snapshot.\n */\n Routes,\n}\n\nexport const enum WorkerAction {\n /**\n * Just created\n */\n Created = 200,\n\n /**\n * Ready for tasks\n * - fluxion options are injected\n */\n Ready,\n\n /**\n * Response to Ping, used for health check and latency measurement\n */\n Pong,\n\n /**\n * Runtime telemetry snapshot from worker process.\n */\n Stats,\n\n /**\n * Current router snapshot from worker process.\n */\n Routes,\n}\n\nexport const isPrimaryMessage = (v: PrimaryMessage): v is PrimaryMessage =>\n [PrimaryAction.Ping, PrimaryAction.Routes].includes(v?.type);\n\nexport const isWorkerMessage = (v: WorkerMessage): v is WorkerMessage =>\n [WorkerAction.Pong, WorkerAction.Created, WorkerAction.Ready, WorkerAction.Stats, WorkerAction.Routes].includes(\n v?.type,\n );\n","import type cluster from 'node:cluster';\nimport type { PrimaryMessage, WorkerMessage } from './types.js';\n\nexport const sendToPrimary = (message: WorkerMessage) => process.send?.(message);\n\nexport const sendToWorker = (worker: cluster.Worker, message: PrimaryMessage) => worker.send(message);\n","import type { ServerResponse } from 'node:http';\nimport { HttpCode } from '@/common/consts.js';\n\nexport function sendJson(res: ServerResponse, payload: unknown, statusCode: HttpCode = HttpCode.Ok): void {\n res.statusCode = statusCode;\n res.setHeader('Content-Type', 'application/json; charset=utf-8');\n res.end(JSON.stringify(payload));\n}\n\nexport function safeSendJson(res: ServerResponse, payload: unknown, statusCode: HttpCode = HttpCode.Ok): void {\n if (res.writableEnded) {\n return;\n }\n\n if (res.headersSent) {\n res.end();\n return;\n }\n\n sendJson(res, payload, statusCode);\n}\n","import type { FluxionContext, FluxionRouteMeta } from '../types.js';\nimport http from 'node:http';\n\nimport { getErrorMessage } from '@/common/logger.js';\nimport { HttpCode, META_PREFIX } from '@/common/consts.js';\nimport { sendJson } from '../http/respond.js';\n\nexport function createPrimaryMetaApiServer(\n cx: Pick<FluxionContext, 'logger' | 'options' | 'router'>,\n getWorkersSnapshot: () => unknown,\n getRoutesSnapshot: () => Promise<FluxionRouteMeta[]>,\n): http.Server {\n const server = http.createServer(async (req, res) => {\n const method = req.method ?? 'GET';\n\n let url: URL;\n try {\n url = new URL(req.url ?? '/', 'http://fluxion.local');\n } catch {\n sendJson(res, { message: 'Bad Request: invalid url' }, HttpCode.BadRequest);\n return;\n }\n\n if (method === 'GET' && url.pathname === META_PREFIX + '/healthz') {\n sendJson(res, {\n ok: true,\n role: 'primary',\n pid: process.pid,\n now: Date.now(),\n uptimeSeconds: Number(process.uptime().toFixed(3)),\n });\n return;\n }\n\n if (method === 'GET' && url.pathname === META_PREFIX + '/workers') {\n sendJson(res, {\n ok: true,\n now: Date.now(),\n workers: getWorkersSnapshot(),\n });\n return;\n }\n\n if (method === 'GET' && url.pathname === META_PREFIX + '/routes') {\n if (!cx.options.metaSecret) {\n sendJson(res, { message: 'Not Found' }, HttpCode.NotFound);\n return;\n }\n\n if (url.searchParams.get('secret') !== cx.options.metaSecret) {\n sendJson(res, { message: 'Forbidden' }, HttpCode.Forbidden);\n return;\n }\n\n const routes = await getRoutesSnapshot();\n sendJson(res, { ok: true, now: Date.now(), routes });\n return;\n }\n\n sendJson(res, { message: 'Not Found' }, HttpCode.NotFound);\n });\n\n server.on('listening', () => {\n cx.logger.info({\n message: 'MetaApiStarted',\n pid: process.pid,\n host: cx.options.host,\n port: cx.options.metaPort,\n prefix: META_PREFIX,\n });\n });\n\n server.on('error', (error: NodeJS.ErrnoException) => {\n cx.logger.error({\n message: 'MetaApiError',\n host: cx.options.host,\n port: cx.options.metaPort,\n code: error.code,\n error: getErrorMessage(error),\n });\n process.exit(1);\n });\n\n server.listen(cx.options.metaPort, cx.options.host);\n return server;\n}\n","import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\ninterface FluxionInstanceRecord {\n startTime: number;\n pid: number;\n host: string;\n port: number;\n metaPort: number;\n cwd: string;\n\n configPath: string; // This will be used as an identifier\n}\n\ninterface InstanceJson {\n instances: FluxionInstanceRecord[];\n}\n\n/**\n * Aim to avoid creating duplicated instances\n * and make it smoother for pm2's process management\n */\nexport class FluxionInstanceManager {\n private readonly instanceFilePath: string;\n private isUnregistering = false;\n private static readonly KILL_POLL_INTERVAL_MS = 300;\n private static readonly SIGTERM_TIMEOUT_MS = 10_000;\n private static readonly SIGKILL_TIMEOUT_MS = 1_000;\n\n constructor() {\n const dir = path.join(os.homedir(), '.fluxion');\n this.instanceFilePath = path.join(dir, 'instances.json');\n\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n process.on('exit', () => this.unregister());\n }\n\n private isAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Read the living processes\n */\n readAlive(): FluxionInstanceRecord[] {\n let result: FluxionInstanceRecord[] = [];\n try {\n if (fs.existsSync(this.instanceFilePath)) {\n const content = fs.readFileSync(this.instanceFilePath, 'utf-8');\n const data: InstanceJson = JSON.parse(content);\n if (data.instances !== undefined && !Array.isArray(data.instances)) {\n console.error(\n `[FluxionInstanceManager] 'instances' of ${this.instanceFilePath} is not an array. It seems that the record file is corrupted`,\n );\n result = [];\n }\n result = data.instances || [];\n }\n } catch (e) {\n console.error(`[FluxionInstanceManager] Failed to read instance.json:`, e);\n }\n\n return result.filter((instance) => this.isAlive(instance.pid));\n }\n\n /**\n * 写入实例记录\n * @param instances 实例记录数组\n */\n private update(instances: FluxionInstanceRecord[]): void {\n try {\n const data: InstanceJson = { instances };\n fs.writeFileSync(this.instanceFilePath, JSON.stringify(data, null, 2), 'utf-8');\n } catch (error) {\n console.error('[FluxionInstanceManager] Failed to write instance.json:', error);\n }\n }\n\n private async waitForExit(pid: number, timeoutMs: number): Promise<boolean> {\n const maxAttempts = Math.ceil(timeoutMs / FluxionInstanceManager.KILL_POLL_INTERVAL_MS);\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n if (!this.isAlive(pid)) {\n return true;\n }\n\n await new Promise((resolve) => {\n setTimeout(resolve, FluxionInstanceManager.KILL_POLL_INTERVAL_MS);\n });\n }\n\n return !this.isAlive(pid);\n }\n\n private async kill(pid: number): Promise<boolean> {\n try {\n process.kill(pid, 'SIGTERM');\n } catch (error) {\n console.error(`[FluxionInstanceManager] Failed to kill process ${pid}:`, error);\n return false;\n }\n\n if (await this.waitForExit(pid, FluxionInstanceManager.SIGTERM_TIMEOUT_MS)) {\n return true;\n }\n\n console.warn(`[FluxionInstanceManager] Process ${pid} did not exit after SIGTERM, sending SIGKILL`);\n\n try {\n process.kill(pid, 'SIGKILL');\n } catch (error) {\n console.error(`[FluxionInstanceManager] Failed to force kill process ${pid}:`, error);\n return false;\n }\n\n return this.waitForExit(pid, FluxionInstanceManager.SIGKILL_TIMEOUT_MS);\n }\n\n async register(configPath: string, host: string, port: number, metaPort: number): Promise<void> {\n const currentPid = process.pid;\n const cwd = process.cwd();\n\n const duplicate = this.readAlive().find((instance) => instance.configPath === configPath);\n if (duplicate) {\n console.warn(\n `[FluxionInstanceManager] Found existing instance with same config or port: PID=${duplicate.pid}, PORT=${duplicate.port}`,\n );\n\n if (!(await this.kill(duplicate.pid))) {\n throw new Error(`[FluxionInstanceManager] Failed to stop old process ${duplicate.pid}`);\n }\n\n console.warn(`[FluxionInstanceManager] Killed old process ${duplicate.pid}`);\n\n const instances = this.readAlive();\n const filtered = instances.filter((instance) => instance.pid !== duplicate.pid);\n this.update(filtered);\n }\n\n const instances = this.readAlive().filter((instance) => instance.pid !== currentPid);\n\n const newRecord: FluxionInstanceRecord = {\n startTime: Date.now(),\n pid: currentPid,\n host,\n port,\n metaPort,\n cwd,\n configPath,\n };\n instances.push(newRecord);\n\n this.update(instances);\n\n console.info(`[FluxionInstanceManager] Registered instance: PID=${currentPid}, PORT=${port}, PATH=${configPath}`);\n }\n\n unregister(): void {\n if (this.isUnregistering) {\n return;\n }\n this.isUnregistering = true;\n\n const currentPid = process.pid;\n try {\n const instances = this.readAlive();\n const filtered = instances.filter((instance) => instance.pid !== currentPid);\n\n if (filtered.length !== instances.length) {\n this.update(filtered);\n console.info(`[FluxionInstanceManager] Unregistered instance: PID=${currentPid}`);\n }\n } finally {\n this.isUnregistering = false;\n }\n }\n\n print(): void {\n const instances = this.readAlive();\n console.info('[FluxionInstanceManager] Current instances:');\n for (const instance of instances) {\n console.info(\n ` - PID: ${instance.pid}, PORT: ${instance.port}, PATH: ${instance.configPath}, START: ${new Date(instance.startTime).toISOString()}`,\n );\n }\n }\n}\n\nexport const instanceManager: FluxionInstanceManager = new FluxionInstanceManager();\n\nexport async function launchFluxionInstance(configPath: string, host: string, port: number, metaPort: number) {\n await instanceManager.register(configPath, host, port, metaPort);\n}\n\nexport async function cleanupFluxionInstance() {\n await instanceManager.unregister();\n}\n","import type { Server } from 'node:http';\nimport type { WorkerMessage, WorkerState, WorkerRuntimeStats } from './types.js';\nimport type { FluxionContext, FluxionRouteMeta } from '../types.js';\nimport os from 'node:os';\nimport cluster from 'node:cluster';\nimport path from 'node:path';\n\nimport { isWorkerMessage, WorkerAction, PrimaryAction } from './consts.js';\nimport { sendToWorker } from './communicate.js';\nimport { createPrimaryMetaApiServer } from './meta-api.js';\nimport { cleanupFluxionInstance, launchFluxionInstance } from './launcher.js';\n\nconst bytesToMb = (bytes: number) => Number((bytes / 1024 / 1024).toFixed(2));\n\nconst RESTART_WINDOW_MS = 60_000;\nconst MAX_RESTARTS_PER_WINDOW = 3;\nconst PING_INTERVAL_MS = 5000;\nconst ROUTES_TIMEOUT_MS = 1000;\nconst PRIMARY_SHUTDOWN_TIMEOUT_MS = 10_000;\nconst PRIMARY_SHUTDOWN_POLL_INTERVAL_MS = 200;\n\nclass FluxionPrimaryController {\n private readonly workers = new Map<number, WorkerState>();\n private readonly routeRequests = new Map<\n number,\n { resolve: (routes: FluxionRouteMeta[]) => void; timer: NodeJS.Timeout }\n >();\n private readonly restartLog = new Map<number, number[]>();\n private readonly configPath: string;\n private readonly restartWhen;\n private readonly workerCount: number;\n\n private routeRequestId = 0;\n private pingTimer?: NodeJS.Timeout;\n private metaServer: Server;\n private shuttingDown = false;\n private shutdownPromise: Promise<void> | null = null;\n\n constructor(private readonly cx: Pick<FluxionContext, 'logger' | 'options' | 'router'>) {\n this.configPath = path.join(cx.options.moduleDir || process.cwd(), 'fluxion.config.ts');\n this.restartWhen = cx.options.workerOptions.restartWhen;\n\n this.metaServer = createPrimaryMetaApiServer(\n this.cx,\n () => this.getWorkersSnapshot(),\n () => this.getRoutesSnapshot(),\n );\n\n const cpuCount = Math.max(1, os.cpus().length);\n this.workerCount = Math.max(\n 1,\n Math.min(cx.options.workerOptions.maxWorkerCount ?? Math.min(2, cpuCount), cpuCount),\n );\n }\n\n async start(): Promise<void> {\n await launchFluxionInstance(this.configPath, this.cx.options.host, this.cx.options.port, this.cx.options.metaPort);\n\n this.cx.logger.info({\n message: 'PrimaryStarted',\n pid: process.pid,\n workers: this.workerCount,\n host: this.cx.options.host,\n port: this.cx.options.port,\n metaPort: this.cx.options.metaPort,\n });\n\n this.registerProcessHandlers();\n\n for (let i = 0; i < this.workerCount; i++) {\n this.spawnSlot(i + 1);\n }\n\n this.startPingLoop();\n }\n\n private registerProcessHandlers(): void {\n const handleShutdownSignal = (signal: NodeJS.Signals) => {\n void this.beginShutdown(signal);\n };\n\n process.once('SIGINT', () => handleShutdownSignal('SIGINT'));\n process.once('SIGTERM', () => handleShutdownSignal('SIGTERM'));\n }\n\n private restartCountInWindow(slot: number): number {\n const now = Date.now();\n const log = (this.restartLog.get(slot) ?? []).filter((t) => now - t < RESTART_WINDOW_MS);\n this.restartLog.set(slot, log);\n return log.length;\n }\n\n private recordRestart(slot: number): void {\n const now = Date.now();\n const log = (this.restartLog.get(slot) ?? []).filter((t) => now - t < RESTART_WINDOW_MS);\n log.push(now);\n this.restartLog.set(slot, log);\n }\n\n private isStorming(slot: number): boolean {\n return this.restartCountInWindow(slot) >= MAX_RESTARTS_PER_WINDOW;\n }\n\n private getWorkersSnapshot() {\n return {\n primaryPid: process.pid,\n host: this.cx.options.host,\n port: this.cx.options.port,\n metaPort: this.cx.options.metaPort,\n uptimeSeconds: Number(process.uptime().toFixed(3)),\n shuttingDown: this.shuttingDown,\n workers: Array.from(this.workers.entries()).map(([workerId, info]) => {\n const { instance } = info;\n const stats = info.lastStats;\n return {\n workerId,\n slot: info.slot,\n pid: info.pid ?? instance.process.pid ?? null,\n state: info.state,\n restartReason: info.restartReason ?? null,\n createdAt: info.createdAt,\n readyAt: info.readyAt ?? null,\n connected: instance.isConnected(),\n dead: instance.isDead(),\n exitedAfterDisconnect: instance.exitedAfterDisconnect,\n lastPongAt: info.lastPongAt ?? null,\n lastRttMs: info.lastRttMs ?? null,\n stats:\n stats === undefined\n ? null\n : {\n at: stats.at,\n uptimeSeconds: stats.uptimeSeconds,\n cpu: stats.cpu,\n memory: {\n ...stats.memory,\n rssMb: bytesToMb(stats.memory.rss),\n heapTotalMb: bytesToMb(stats.memory.heapTotal),\n heapUsedMb: bytesToMb(stats.memory.heapUsed),\n externalMb: bytesToMb(stats.memory.external),\n arrayBuffersMb: bytesToMb(stats.memory.arrayBuffers),\n },\n },\n };\n }),\n };\n }\n\n private getRoutesSnapshot(): Promise<FluxionRouteMeta[]> {\n const worker = Array.from(this.workers.values()).find(\n (info) => info.state === 'ready' && info.instance.isConnected(),\n );\n if (!worker) {\n return Promise.resolve([]);\n }\n\n return new Promise((resolve) => {\n const requestId = ++this.routeRequestId;\n const timer = setTimeout(() => {\n this.routeRequests.delete(requestId);\n resolve([]);\n }, ROUTES_TIMEOUT_MS);\n timer.unref();\n this.routeRequests.set(requestId, { resolve, timer });\n try {\n sendToWorker(worker.instance, { type: PrimaryAction.Routes, requestId });\n } catch {\n clearTimeout(timer);\n this.routeRequests.delete(requestId);\n resolve([]);\n }\n });\n }\n\n private initiateRecycle(info: WorkerState, reason: string): void {\n if (this.shuttingDown) {\n return;\n }\n\n for (const workerInfo of this.workers.values()) {\n if (workerInfo.state === 'restarting') return;\n }\n\n if (this.isStorming(info.slot)) {\n this.cx.logger.warn({\n message: 'WorkerRecycleSuppressed',\n slot: info.slot,\n pid: info.pid,\n reason,\n windowMs: RESTART_WINDOW_MS,\n max: MAX_RESTARTS_PER_WINDOW,\n });\n return;\n }\n\n this.recordRestart(info.slot);\n info.state = 'restarting';\n info.restartReason = reason;\n this.cx.logger.warn({\n message: 'WorkerRecycling',\n slot: info.slot,\n pid: info.pid,\n reason,\n });\n info.instance.kill();\n }\n\n private evaluateResourceConditions(info: WorkerState, stats: WorkerRuntimeStats): void {\n if (this.shuttingDown) {\n return;\n }\n\n const rssMb = bytesToMb(stats.memory.rss);\n if (rssMb > this.restartWhen.memoryUsageGreaterThan) {\n this.initiateRecycle(\n info,\n `memoryUsageGreaterThan: rss ${rssMb}MB > ${this.restartWhen.memoryUsageGreaterThan}MB`,\n );\n return;\n }\n\n const uptimeMs = stats.uptimeSeconds * 1000;\n if (uptimeMs > this.restartWhen.uptimeGreaterThan) {\n this.initiateRecycle(\n info,\n `uptimeGreaterThan: ${Math.round(uptimeMs / 1000)}s > ${Math.round(this.restartWhen.uptimeGreaterThan / 1000)}s`,\n );\n }\n }\n\n private evaluateLiveness(now: number): void {\n if (this.shuttingDown) {\n return;\n }\n\n for (const info of this.workers.values()) {\n if (info.state !== 'ready' || info.lastPongAt === undefined) continue;\n const staleMs = now - info.lastPongAt;\n if (staleMs > this.restartWhen.healthzTimeout) {\n this.initiateRecycle(\n info,\n `healthzTimeout: no pong for ${Math.round(staleMs / 1000)}s > ${Math.round(this.restartWhen.healthzTimeout / 1000)}s`,\n );\n }\n }\n }\n\n private spawnSlot(slot: number): void {\n if (this.shuttingDown) {\n return;\n }\n\n this.attachWorker(cluster.fork({ WORKER_ID: String(slot) }), slot);\n }\n\n private attachWorker(worker: cluster.Worker, slot: number): void {\n const workerInfo: WorkerState = {\n state: 'creating',\n pid: worker.process.pid,\n slot,\n createdAt: Date.now(),\n instance: worker,\n };\n this.workers.set(worker.id, workerInfo);\n\n worker.on('message', (raw: WorkerMessage) => {\n if (!isWorkerMessage(raw)) {\n return;\n }\n\n if (raw.type === WorkerAction.Pong) {\n const rtt = Date.now() - raw.sentAt;\n workerInfo.pid = raw.pid;\n workerInfo.lastPongAt = Date.now();\n workerInfo.lastRttMs = rtt;\n return;\n }\n\n if (raw.type === WorkerAction.Ready) {\n workerInfo.state = 'ready';\n workerInfo.pid = raw.pid;\n workerInfo.readyAt = Date.now();\n this.cx.logger.info({\n message: 'WorkerReady',\n workerId: worker.id,\n slot,\n pid: raw.pid,\n });\n return;\n }\n\n if (raw.type === WorkerAction.Created) {\n workerInfo.state = 'created';\n workerInfo.pid = raw.pid;\n this.cx.logger.info({\n message: 'WorkerCreated',\n workerId: worker.id,\n slot,\n pid: raw.pid,\n });\n return;\n }\n\n if (raw.type === WorkerAction.Stats) {\n workerInfo.pid = raw.pid;\n workerInfo.lastStats = raw.stats;\n if (workerInfo.state === 'ready') {\n this.evaluateResourceConditions(workerInfo, raw.stats);\n }\n return;\n }\n\n if (raw.type === WorkerAction.Routes) {\n const request = this.routeRequests.get(raw.requestId);\n if (request) {\n clearTimeout(request.timer);\n this.routeRequests.delete(raw.requestId);\n request.resolve(raw.routes);\n }\n }\n });\n\n worker.on('exit', (code, signal) => {\n const info = this.workers.get(worker.id);\n this.workers.delete(worker.id);\n const exitedSlot = info?.slot;\n const expected = info?.state === 'restarting' || this.shuttingDown;\n const reason = info?.restartReason ?? (this.shuttingDown ? 'shutdown' : null);\n\n this.cx.logger.warn({\n message: 'WorkerExited',\n workerId: worker.id,\n slot: exitedSlot ?? null,\n pid: worker.process.pid ?? 'unknown',\n code,\n signal: signal ?? 'none',\n expected,\n reason,\n });\n\n if (exitedSlot === undefined || this.shuttingDown) return;\n\n if (info?.state === 'restarting') {\n this.spawnSlot(exitedSlot);\n return;\n }\n\n this.recordRestart(exitedSlot);\n if (this.isStorming(exitedSlot)) {\n this.cx.logger.error({\n message: 'WorkerRespawnSuppressed',\n slot: exitedSlot,\n windowMs: RESTART_WINDOW_MS,\n max: MAX_RESTARTS_PER_WINDOW,\n });\n return;\n }\n this.spawnSlot(exitedSlot);\n });\n }\n\n private startPingLoop(): void {\n this.pingTimer = setInterval(() => {\n const sentAt = Date.now();\n for (const info of this.workers.values()) {\n if (!info.instance.isConnected()) {\n continue;\n }\n try {\n sendToWorker(info.instance, { type: PrimaryAction.Ping, sentAt });\n } catch {\n // Ignore transient IPC errors; worker lifecycle events will reconcile state.\n }\n }\n this.evaluateLiveness(Date.now());\n }, PING_INTERVAL_MS);\n this.pingTimer.unref();\n }\n\n private stopTimers(): void {\n if (this.pingTimer) {\n clearInterval(this.pingTimer);\n this.pingTimer = undefined;\n }\n\n for (const [requestId, request] of this.routeRequests.entries()) {\n clearTimeout(request.timer);\n request.resolve([]);\n this.routeRequests.delete(requestId);\n }\n }\n\n private getAliveWorkers(): WorkerState[] {\n return Array.from(this.workers.values()).filter((info) => !info.instance.isDead());\n }\n\n private async waitForWorkersToExit(timeoutMs: number): Promise<WorkerState[]> {\n const deadline = Date.now() + timeoutMs;\n\n while (Date.now() < deadline) {\n const alive = this.getAliveWorkers();\n if (alive.length === 0) {\n return [];\n }\n\n await new Promise((resolve) => {\n setTimeout(resolve, PRIMARY_SHUTDOWN_POLL_INTERVAL_MS);\n });\n }\n\n return this.getAliveWorkers();\n }\n\n private async forceKillWorkers(workers: WorkerState[]): Promise<void> {\n for (const info of workers) {\n const pid = info.pid ?? info.instance.process.pid;\n this.cx.logger.error({\n message: 'WorkerForceKilled',\n slot: info.slot,\n pid: pid ?? null,\n });\n\n try {\n info.instance.process.kill('SIGKILL');\n } catch {\n // Ignore races where the worker exits between timeout and force kill.\n }\n }\n\n await this.waitForWorkersToExit(1000);\n }\n\n private async shutdownWorkers(signal: NodeJS.Signals): Promise<void> {\n const workers = this.getAliveWorkers();\n for (const info of workers) {\n const pid = info.pid ?? info.instance.process.pid;\n this.cx.logger.warn({\n message: 'WorkerShutdownRequested',\n slot: info.slot,\n pid: pid ?? null,\n signal,\n });\n\n try {\n info.instance.kill(signal);\n } catch {\n // Ignore races; exit listener will reconcile state.\n }\n }\n\n const remaining = await this.waitForWorkersToExit(PRIMARY_SHUTDOWN_TIMEOUT_MS);\n if (remaining.length === 0) {\n return;\n }\n\n this.cx.logger.error({\n message: 'PrimaryShutdownTimeout',\n pid: process.pid,\n remainingWorkers: remaining.map((info) => ({\n slot: info.slot,\n pid: info.pid ?? info.instance.process.pid ?? null,\n })),\n timeoutMs: PRIMARY_SHUTDOWN_TIMEOUT_MS,\n });\n\n await this.forceKillWorkers(remaining);\n }\n\n private async beginShutdown(signal: NodeJS.Signals): Promise<void> {\n if (this.shutdownPromise) {\n return this.shutdownPromise;\n }\n\n this.shutdownPromise = (async () => {\n this.shuttingDown = true;\n this.cx.logger.warn({\n message: 'PrimaryShuttingDown',\n pid: process.pid,\n signal,\n workerCount: this.workers.size,\n });\n\n this.stopTimers();\n\n try {\n await this.shutdownWorkers(signal);\n } finally {\n this.metaServer.close();\n await cleanupFluxionInstance();\n }\n })();\n\n try {\n await this.shutdownPromise;\n process.exit(0);\n } catch (error) {\n this.cx.logger.error({\n message: 'PrimaryShutdownFailed',\n pid: process.pid,\n signal,\n error: error instanceof Error ? error.message : String(error),\n });\n process.exit(1);\n }\n }\n}\n\nexport async function initPrimary(cx: Pick<FluxionContext, 'logger' | 'options' | 'router'>) {\n if (!cluster.isPrimary) {\n $throw('createPrimary should only be called in primary process');\n }\n\n const controller = new FluxionPrimaryController(cx);\n await controller.start();\n}\n","/**\n * For low version of Node.js that does not support `Promise.try`, we can implement it ourselves.\n *\n * Only for async functions.\n */\nexport function PromiseTry<T extends (...args: any[]) => any>(fn: T, ...args: Parameters<T>) {\n return new Promise<ReturnType<T>>((resolve, reject) => {\n // in case `fn` throws synchronously, we catch it and reject the promise\n try {\n const r = fn(...args);\n if (r instanceof Promise) {\n r.then(resolve).catch(reject);\n } else {\n resolve(r);\n }\n } catch (error) {\n reject(error);\n }\n });\n}\n","import type { IncomingMessage } from 'node:http';\n\nexport function getRealIp(req: IncomingMessage): string {\n const forwardedFor = req.headersDistinct['x-forwarded-for'];\n if (forwardedFor) {\n const firstForwarded = forwardedFor[0]?.split(',')[0]?.trim();\n if (firstForwarded && firstForwarded.length > 0) {\n return firstForwarded;\n }\n }\n\n const realIp = req.headersDistinct['x-real-ip']?.[0].trim();\n if (realIp !== undefined) {\n return realIp;\n }\n\n return req.socket.remoteAddress ?? 'unknown';\n}\n\nexport function isTextualContentType(contentType: string | undefined): boolean {\n if (contentType === undefined) {\n return false;\n }\n\n const normalized = contentType.toLowerCase();\n\n return (\n normalized.startsWith('text/') ||\n normalized.includes('json') ||\n normalized.includes('xml') ||\n normalized.includes('x-www-form-urlencoded') ||\n normalized.includes('javascript')\n );\n}\n","import { DUMMY_BASE_URL } from '@/common/consts.js';\n\nexport function toURL(rawUrl: string | undefined): URL | undefined {\n if (rawUrl === undefined) {\n return undefined;\n }\n\n try {\n return new URL(rawUrl, DUMMY_BASE_URL);\n } catch {\n return undefined;\n }\n}\n","export function parseQuery(searchParams: URLSearchParams): Record<string, string | string[]> {\n const query: Record<string, string | string[]> = {};\n\n for (const [key, value] of searchParams.entries()) {\n const existing = query[key];\n\n if (existing === undefined) {\n query[key] = value;\n continue;\n }\n\n if (Array.isArray(existing)) {\n existing.push(value);\n continue;\n }\n\n query[key] = [existing, value];\n }\n\n return query;\n}\n","import { HttpCode } from '@/common/consts.js';\n\n/**\n * Base class for all HTTP exceptions\n */\nexport abstract class HttpException extends Error implements NodeJS.ErrnoException {\n errno?: number | undefined;\n code?: string | undefined;\n\n constructor(message: string, statusCode: HttpCode, code: string) {\n super(message);\n this.name = 'HttpException';\n this.errno = statusCode;\n this.code = code;\n }\n}\n\n// 4xx Client Error Exceptions\n\n/**\n * 400 Bad Request - Malformed or invalid request\n */\nexport class BadRequestException extends HttpException {\n constructor(message: string = 'Bad Request') {\n super(message, HttpCode.BadRequest, 'BAD_REQUEST');\n }\n}\n\n/**\n * 401 Unauthorized - Authentication required or failed\n */\nexport class UnauthorizedException extends HttpException {\n constructor(message: string = 'Unauthorized') {\n super(message, HttpCode.Unauthorized, 'UNAUTHORIZED');\n }\n}\n\n/**\n * 403 Forbidden - Valid request but refused authorization\n */\nexport class ForbiddenException extends HttpException {\n constructor(message: string = 'Forbidden') {\n super(message, HttpCode.Forbidden, 'FORBIDDEN');\n }\n}\n\n/**\n * 404 Not Found - Resource does not exist\n */\nexport class NotFoundException extends HttpException {\n constructor(message: string = 'Not Found') {\n super(message, HttpCode.NotFound, 'NOT_FOUND');\n }\n}\n\n/**\n * 405 Method Not Allowed - HTTP method not supported for resource\n */\nexport class MethodNotAllowedException extends HttpException {\n constructor(message: string = 'Method Not Allowed') {\n super(message, HttpCode.MethodNotAllowed, 'METHOD_NOT_ALLOWED');\n }\n}\n\n/**\n * 406 Not Acceptable - Cannot generate acceptable response\n */\nexport class NotAcceptableException extends HttpException {\n constructor(message: string = 'Not Acceptable') {\n super(message, HttpCode.NotAcceptable, 'NOT_ACCEPTABLE');\n }\n}\n\n/**\n * 408 Request Timeout - Client did not produce request within time\n */\nexport class RequestTimeoutException extends HttpException {\n constructor(message: string = 'Request Timeout') {\n super(message, HttpCode.RequestTimeout, 'REQUEST_TIMEOUT');\n }\n}\n\n/**\n * 409 Conflict - Request conflicts with current state\n */\nexport class ConflictException extends HttpException {\n constructor(message: string = 'Conflict') {\n super(message, HttpCode.Conflict, 'CONFLICT');\n }\n}\n\n/**\n * 410 Gone - Resource no longer available\n */\nexport class GoneException extends HttpException {\n constructor(message: string = 'Gone') {\n super(message, HttpCode.Gone, 'GONE');\n }\n}\n\n/**\n * 413 Payload Too Large - Request entity larger than limits\n */\nexport class PayloadTooLargeException extends HttpException {\n constructor(message: string = 'Payload Too Large') {\n super(message, HttpCode.PayloadTooLarge, 'PAYLOAD_TOO_LARGE');\n }\n}\n\n/**\n * 415 Unsupported Media Type - Requested format not supported\n */\nexport class UnsupportedMediaTypeException extends HttpException {\n constructor(message: string = 'Unsupported Media Type') {\n super(message, HttpCode.UnsupportedMediaType, 'UNSUPPORTED_MEDIA_TYPE');\n }\n}\n\n/**\n * 422 Unprocessable Entity - Syntactically correct but semantically erroneous\n */\nexport class UnprocessableEntityException extends HttpException {\n constructor(message: string = 'Unprocessable Entity') {\n super(message, HttpCode.UnprocessableEntity, 'UNPROCESSABLE_ENTITY');\n }\n}\n\n/**\n * 429 Too Many Requests - Rate limit exceeded\n */\nexport class TooManyRequestsException extends HttpException {\n constructor(message: string = 'Too Many Requests') {\n super(message, HttpCode.TooManyRequests, 'TOO_MANY_REQUESTS');\n }\n}\n\n// 5xx Server Error Exceptions\n\n/**\n * 500 Internal Server Error - Unexpected server condition\n */\nexport class InternalServerErrorException extends HttpException {\n constructor(message: string = 'Internal Server Error') {\n super(message, HttpCode.InternalServerError, 'INTERNAL_SERVER_ERROR');\n }\n}\n\n/**\n * 501 Not Implemented - Server does not support functionality\n */\nexport class NotImplementedException extends HttpException {\n constructor(message: string = 'Not Implemented') {\n super(message, HttpCode.NotImplemented, 'NOT_IMPLEMENTED');\n }\n}\n\n/**\n * 502 Bad Gateway - Invalid response from upstream server\n */\nexport class BadGatewayException extends HttpException {\n constructor(message: string = 'Bad Gateway') {\n super(message, HttpCode.BadGateway, 'BAD_GATEWAY');\n }\n}\n\n/**\n * 503 Service Unavailable - Server temporarily unavailable\n */\nexport class ServiceUnavailableException extends HttpException {\n constructor(message: string = 'Service Unavailable') {\n super(message, HttpCode.ServiceUnavailable, 'SERVICE_UNAVAILABLE');\n }\n}\n\n/**\n * 504 Gateway Timeout - Upstream server timeout\n */\nexport class GatewayTimeoutException extends HttpException {\n constructor(message: string = 'Gateway Timeout') {\n super(message, HttpCode.GatewayTimeout, 'GATEWAY_TIMEOUT');\n }\n}\n","import type http from 'node:http';\n\nimport { isTextualContentType } from './headers.js';\nimport { parseQuery } from './query.js';\nimport { PayloadTooLargeException } from './exceptions.js';\n\nexport interface BodyPreview {\n exists: boolean;\n value?: string;\n bytes: number;\n truncated: boolean;\n}\n\nfunction createPayloadTooLargeException(receivedBytes: number, maxBytes: number): PayloadTooLargeException {\n return new PayloadTooLargeException(\n `request body too large: ${receivedBytes.toString()} bytes exceeds ${maxBytes.toString()} bytes`,\n );\n}\n\nfunction getHeaderValue(headerValue: string | string[] | undefined): string | undefined {\n return Array.isArray(headerValue) ? headerValue[0] : headerValue;\n}\n\nfunction createEmptyPreview(): BodyPreview {\n return {\n exists: false,\n bytes: 0,\n truncated: false,\n };\n}\n\nfunction createPreview(\n previewBuffer: Buffer,\n totalBytes: number,\n contentType: string | undefined,\n truncated: boolean,\n): BodyPreview {\n if (totalBytes === 0) {\n return createEmptyPreview();\n }\n\n if (isTextualContentType(contentType)) {\n return {\n exists: true,\n value: previewBuffer.toString('utf8'),\n bytes: totalBytes,\n truncated,\n };\n }\n\n return {\n exists: true,\n value: `<binary body: ${totalBytes} bytes>`,\n bytes: totalBytes,\n truncated,\n };\n}\n\nasync function readRequestBodyWithPreview(\n req: http.IncomingMessage,\n method: string,\n maxBytes: number,\n previewMaxBytes = 8192,\n): Promise<{ rawBody: Buffer | undefined; preview: BodyPreview }> {\n if (method === 'GET' || method === 'HEAD') {\n return {\n rawBody: undefined,\n preview: createEmptyPreview(),\n };\n }\n\n if (req.readableEnded) {\n return {\n rawBody: undefined,\n preview: createEmptyPreview(),\n };\n }\n\n const contentLengthRaw = getHeaderValue(req.headers['content-length']);\n const declaredBytes = contentLengthRaw !== undefined ? Number.parseInt(contentLengthRaw, 10) : NaN;\n\n return new Promise((resolve, reject) => {\n const rawBodyChunks: Buffer[] = [];\n const previewChunks: Buffer[] = [];\n let totalBytes = 0;\n let previewBytes = 0;\n let previewTruncated = false;\n let settled = false;\n\n const cleanup = (): void => {\n req.off('data', onData);\n req.off('end', onEnd);\n req.off('error', onError);\n req.off('aborted', onAborted);\n };\n\n const settle = (action: () => void): void => {\n if (settled) {\n return;\n }\n\n settled = true;\n action();\n };\n\n // Check content-length upfront, but still drain the request\n if (Number.isFinite(declaredBytes) && declaredBytes > maxBytes) {\n cleanup();\n req.resume();\n settle(() => reject(createPayloadTooLargeException(declaredBytes, maxBytes)));\n return;\n }\n\n const onData = (chunk: Buffer | string | Uint8Array): void => {\n const bufferChunk = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n totalBytes += bufferChunk.byteLength;\n\n if (totalBytes > maxBytes) {\n cleanup();\n req.resume();\n settle(() => reject(createPayloadTooLargeException(totalBytes, maxBytes)));\n return;\n }\n\n rawBodyChunks.push(bufferChunk);\n\n if (previewBytes < previewMaxBytes) {\n const remaining = previewMaxBytes - previewBytes;\n const nextSlice = bufferChunk.subarray(0, remaining);\n previewChunks.push(nextSlice);\n previewBytes += nextSlice.length;\n\n if (nextSlice.length < bufferChunk.length) {\n previewTruncated = true;\n }\n } else {\n previewTruncated = true;\n }\n };\n\n const onEnd = (): void => {\n cleanup();\n settle(() => {\n const rawBody = rawBodyChunks.length > 0 ? Buffer.concat(rawBodyChunks) : undefined;\n const previewBuffer = previewChunks.length > 0 ? Buffer.concat(previewChunks) : Buffer.alloc(0);\n\n resolve({\n rawBody,\n preview: createPreview(\n previewBuffer,\n rawBody?.byteLength ?? 0,\n getHeaderValue(req.headers['content-type']),\n previewTruncated,\n ),\n });\n });\n };\n\n const onError = (error: Error): void => {\n cleanup();\n settle(() => reject(error));\n };\n\n const onAborted = (): void => {\n cleanup();\n settle(() => reject(new Error('request aborted while reading body')));\n };\n\n req.on('data', onData);\n req.once('end', onEnd);\n req.once('error', onError);\n req.once('aborted', onAborted);\n });\n}\n\nexport async function parseBody(\n req: http.IncomingMessage,\n method: string,\n maxBytes: number,\n): Promise<{ body: Record<string, any>; preview: BodyPreview }> {\n const { rawBody, preview } = await readRequestBodyWithPreview(req, method, maxBytes);\n\n if (rawBody === undefined || rawBody.byteLength === 0) {\n return {\n body: {},\n preview,\n };\n }\n\n const contentType = getHeaderValue(req.headers['content-type'])?.toLowerCase() ?? '';\n\n if (contentType.includes('json')) {\n const textBody = rawBody.toString('utf8').trim();\n\n if (textBody.length === 0) {\n return {\n body: {},\n preview,\n };\n }\n\n try {\n const parsed = JSON.parse(textBody) as unknown;\n\n if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return {\n body: parsed as Record<string, any>,\n preview,\n };\n }\n\n return {\n body: { value: parsed },\n preview,\n };\n } catch {\n return {\n body: { raw: textBody },\n preview,\n };\n }\n }\n\n if (contentType.includes('x-www-form-urlencoded')) {\n return {\n body: parseQuery(new URLSearchParams(rawBody.toString('utf8'))),\n preview,\n };\n }\n\n if (isTextualContentType(contentType)) {\n return {\n body: { raw: rawBody.toString('utf8') },\n preview,\n };\n }\n\n return {\n body: {},\n preview,\n };\n}\n","/**\n * Parse Cookie header string into an object\n */\nexport function parseCookie(cookieHeader: string | undefined): Record<string, string> {\n if (!cookieHeader) {\n return {};\n }\n\n const cookies: Record<string, string> = {};\n const pairs = cookieHeader.split(';');\n\n for (const pair of pairs) {\n const [key, ...valueParts] = pair.split('=');\n if (!key) continue;\n\n const trimmedKey = key.trim();\n const value = valueParts.join('=').trim();\n cookies[trimmedKey] = decodeURIComponent(value);\n }\n\n return cookies;\n}\n\n/**\n * Serialize an object into a Cookie header string\n */\nexport function serializeCookie(name: string, value: string, options?: {\n maxAge?: number;\n expires?: Date;\n domain?: string;\n path?: string;\n secure?: boolean;\n httpOnly?: boolean;\n sameSite?: 'strict' | 'lax' | 'none';\n}): string {\n let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;\n\n if (options) {\n if (options.maxAge !== undefined) {\n cookie += `; Max-Age=${options.maxAge}`;\n }\n if (options.expires) {\n cookie += `; Expires=${options.expires.toUTCString()}`;\n }\n if (options.domain) {\n cookie += `; Domain=${options.domain}`;\n }\n if (options.path) {\n cookie += `; Path=${options.path}`;\n }\n if (options.secure) {\n cookie += '; Secure';\n }\n if (options.httpOnly) {\n cookie += '; HttpOnly';\n }\n if (options.sameSite) {\n cookie += `; SameSite=${options.sameSite}`;\n }\n }\n\n return cookie;\n}\n","import http from 'node:http';\nimport https from 'node:https';\n\nimport type { FluxionContext, FluxionModuleContext, NormalizedRequest } from '../types.js';\nimport {\n HttpCode,\n HANDLER_TIMEOUT_FLAG,\n META_PREFIX,\n STATIC_HANDLED_FLAG,\n FluxionModuleType,\n MIDDLEWARE_TIMEOUT_FLAG,\n} from '@/common/consts.js';\nimport { PromiseTry } from '@/common/promise-try.js';\nimport { getErrorMessage } from '@/common/logger.js';\n\nimport { getRealIp } from '../http/headers.js';\nimport { toURL } from '../http/request.js';\nimport { safeSendJson } from '../http/respond.js';\nimport { parseBody, type BodyPreview } from '../http/body.js';\nimport { parseQuery } from '../http/query.js';\nimport { parseCookie } from '../http/cookie.js';\nimport { HttpException } from '@/http/exceptions.js';\n\nconst waiter = (mainPromise: Promise<any>, timeoutMs: number, flag: symbol) =>\n Promise.race([mainPromise, new Promise((r) => setTimeout(() => r(flag), timeoutMs))]);\n\nexport function createWorkerServer(cx: FluxionContext): Promise<http.Server | https.Server> {\n const moduleCx: FluxionModuleContext = Object.freeze({ logger: cx.logger });\n\n const requestHandler = async (req: http.IncomingMessage, res: http.ServerResponse) => {\n const method = req.method ?? 'GET';\n const ip = getRealIp(req);\n const url = toURL(req.url);\n if (url === undefined) {\n safeSendJson(res, { message: 'Bad Request: req.url is undefined' }, HttpCode.BadRequest);\n return;\n }\n\n const normalized: NormalizedRequest = {\n method,\n ip,\n url,\n query: parseQuery(url.searchParams),\n body: {},\n headers: req.headers,\n cookie: parseCookie(req.headers.cookie as string | undefined),\n meta: {},\n };\n\n let bodyPreview: BodyPreview = {\n exists: false,\n bytes: 0,\n truncated: false,\n };\n\n cx.logger.info({ message: 'request', method, ip, path: url.pathname });\n\n const start = performance.now();\n res.once('finish', () => {\n const o: Record<string, unknown> = {\n workerId: process.env.WORKER_ID ?? '[primary]',\n message: 'response',\n method,\n ip,\n path: url.pathname,\n status: res.statusCode,\n duration: (performance.now() - start).toFixed(4),\n };\n\n if (Object.keys(normalized.query).length > 0) {\n o.query = normalized.query;\n }\n\n if (bodyPreview.exists) {\n o.body = bodyPreview.value;\n o.bodyBytes = bodyPreview.bytes;\n o.bodyTruncated = bodyPreview.truncated;\n }\n\n cx.logger.info(o);\n });\n\n // * Start request handling\n try {\n if (normalized.url.pathname.startsWith(META_PREFIX + '/')) {\n safeSendJson(res, { message: `Not Found` }, HttpCode.NotFound);\n return;\n }\n\n const parsed = await parseBody(req, normalized.method, cx.options.maxRequestBytes);\n normalized.body = parsed.body;\n bodyPreview = parsed.preview;\n\n const m = await cx.router.getModule(url);\n if (!m) {\n safeSendJson(res, { message: 'Not Found' }, HttpCode.NotFound);\n return;\n }\n\n if (req.method && m.methods && !m.methods.includes(req.method)) {\n safeSendJson(res, { message: 'Method Not Allowed' }, HttpCode.MethodNotAllowed);\n return;\n }\n\n const timeoutMs =\n m.type === FluxionModuleType.Api\n ? (m.handlerTimeoutMs ?? cx.options.handlerTimeoutMs)\n : cx.options.staticResourceTimeoutMs;\n\n // Middleware execution\n if (m.middlewares) {\n for (let i = 0; i < m.middlewares.length; i++) {\n const result = await waiter(\n PromiseTry(m.middlewares[i], normalized, moduleCx, req, res),\n cx.options.middlewareTimeoutMs,\n MIDDLEWARE_TIMEOUT_FLAG,\n );\n\n if (result === MIDDLEWARE_TIMEOUT_FLAG) {\n cx.logger.warn({\n message: 'MiddlewareTimeout',\n method: normalized.method,\n ip: normalized.ip,\n });\n safeSendJson(res, { message: 'Internal Server Error' }, HttpCode.InternalServerError);\n return;\n }\n if (res.writableEnded) {\n return;\n }\n if (res.headersSent) {\n res.end();\n return;\n }\n }\n }\n\n const result = await waiter(\n PromiseTry(m.handler, normalized, moduleCx, req, res),\n timeoutMs,\n HANDLER_TIMEOUT_FLAG,\n );\n\n if (result === HANDLER_TIMEOUT_FLAG) {\n cx.logger.warn({ message: 'HandlerTimeout', method: normalized.method, ip: normalized.ip });\n safeSendJson(res, { message: 'Handler timed out' }, HttpCode.InternalServerError);\n return;\n }\n\n if (result !== STATIC_HANDLED_FLAG) {\n safeSendJson(res, result);\n }\n } catch (e) {\n if (e instanceof HttpException) {\n cx.logger.error({\n message: 'RequestFailed',\n method: normalized.method,\n ip: normalized.ip,\n path: normalized.url.pathname,\n error: e.message,\n });\n safeSendJson(res, { message: e.message }, e.errno);\n } else {\n cx.logger.error({\n message: 'RequestFailed',\n method: normalized.method,\n ip: normalized.ip,\n path: normalized.url.pathname,\n error: getErrorMessage(e),\n });\n safeSendJson(\n res,\n { message: getErrorMessage(e) },\n (e as NodeJS.ErrnoException).errno ?? HttpCode.InternalServerError,\n );\n }\n }\n };\n\n const server = cx.options.https\n ? https.createServer(\n {\n key: cx.options.https.key,\n cert: cx.options.https.cert,\n ca: cx.options.https.ca,\n },\n requestHandler,\n )\n : http.createServer(requestHandler);\n\n return new Promise((resolve, reject) => {\n let listening = false;\n\n server.on('close', () => {\n cx.logger.info({\n message: 'ServerClosed',\n host: cx.options.host,\n port: cx.options.port,\n });\n });\n\n server.once('listening', () => {\n listening = true;\n cx.logger.info({\n message: 'ServerStarted',\n pid: process.pid,\n protocol: cx.options.https ? 'https' : 'http',\n host: cx.options.host,\n port: cx.options.port,\n });\n cx.logger.info({\n message: 'DynamicDirectory',\n directory: cx.options.dir,\n });\n resolve(server);\n });\n\n server.on('error', (error) => {\n cx.logger.error({\n message: 'ServerError',\n error: getErrorMessage(error),\n });\n if (listening) {\n process.exit(1);\n }\n reject(error);\n });\n\n server.listen(cx.options.port, cx.options.host);\n });\n}\n","import type { PrimaryMessage } from './types.js';\nimport type { FluxionContext } from '../types.js';\nimport type http from 'node:http';\nimport type https from 'node:https';\nimport cluster from 'node:cluster';\n\nimport { getErrorMessage } from '@/common/logger.js';\nimport { WorkerAction, PrimaryAction, isPrimaryMessage } from './consts.js';\nimport { sendToPrimary } from './communicate.js';\nimport { createWorkerServer } from './server.js';\n\nconst WORKER_SHUTDOWN_TIMEOUT_MS = 10_000;\nconst STATS_INTERVAL_MS = 2000;\n\nclass FluxionWorkerRuntime {\n private server?: http.Server | https.Server;\n private statsTimer?: NodeJS.Timeout;\n private exiting = false;\n\n constructor(private readonly cx: FluxionContext) {}\n\n start(): void {\n this.registerMessageHandler();\n this.registerSignalHandlers();\n\n sendToPrimary({ type: WorkerAction.Created, pid: process.pid });\n this.startStatsReporter();\n\n createWorkerServer(this.cx)\n .then((server) => {\n this.server = server;\n sendToPrimary({ type: WorkerAction.Ready, pid: process.pid });\n })\n .catch((error) => {\n this.cx.logger.error({\n message: 'WorkerBootstrapFailed',\n pid: process.pid,\n error: getErrorMessage(error),\n });\n this.cx.watcher.stop();\n process.exit(1);\n });\n }\n\n private registerMessageHandler(): void {\n process.on('message', (raw: PrimaryMessage) => {\n if (!isPrimaryMessage(raw)) {\n return;\n }\n\n if (raw.type === PrimaryAction.Ping) {\n sendToPrimary({ type: WorkerAction.Pong, pid: process.pid, sentAt: raw.sentAt, receivedAt: Date.now() });\n return;\n }\n\n if (raw.type === PrimaryAction.Routes) {\n sendToPrimary({\n type: WorkerAction.Routes,\n pid: process.pid,\n requestId: raw.requestId,\n routes: this.cx.router.getRoutes(),\n });\n }\n });\n }\n\n private startStatsReporter(): void {\n let previousCpuUsage = process.cpuUsage();\n let previousAt = Date.now();\n\n this.statsTimer = setInterval(() => {\n const now = Date.now();\n const elapsedMicros = Math.max(1, (now - previousAt) * 1000);\n const cpuDelta = process.cpuUsage(previousCpuUsage);\n const cpuPercent = Number((((cpuDelta.user + cpuDelta.system) / elapsedMicros) * 100).toFixed(2));\n\n previousCpuUsage = process.cpuUsage();\n previousAt = now;\n\n const memoryUsage = process.memoryUsage();\n sendToPrimary({\n type: WorkerAction.Stats,\n pid: process.pid,\n stats: {\n at: now,\n pid: process.pid,\n uptimeSeconds: Number(process.uptime().toFixed(3)),\n cpu: {\n userMicros: cpuDelta.user,\n systemMicros: cpuDelta.system,\n percent: cpuPercent,\n },\n memory: {\n rss: memoryUsage.rss,\n heapTotal: memoryUsage.heapTotal,\n heapUsed: memoryUsage.heapUsed,\n external: memoryUsage.external,\n arrayBuffers: memoryUsage.arrayBuffers,\n },\n },\n });\n }, STATS_INTERVAL_MS);\n\n this.statsTimer.unref();\n }\n\n private registerSignalHandlers(): void {\n process.once('SIGINT', () => {\n void this.shutdown('SIGINT');\n });\n process.once('SIGTERM', () => {\n void this.shutdown('SIGTERM');\n });\n }\n\n private stopStatsReporter(): void {\n if (!this.statsTimer) {\n return;\n }\n\n clearInterval(this.statsTimer);\n this.statsTimer = undefined;\n }\n\n private async shutdown(signal: NodeJS.Signals): Promise<void> {\n if (this.exiting) {\n return;\n }\n this.exiting = true;\n\n this.cx.logger.warn({ message: 'WorkerShuttingDown', pid: process.pid, signal });\n this.stopStatsReporter();\n this.cx.watcher.stop();\n\n if (!this.server) {\n process.exit(0);\n }\n\n const timer = setTimeout(() => {\n process.exit(1);\n }, WORKER_SHUTDOWN_TIMEOUT_MS);\n timer.unref();\n\n this.server.close((error) => {\n clearTimeout(timer);\n if (error) {\n this.cx.logger.error({ message: 'WorkerShutdownFailed', pid: process.pid, error: getErrorMessage(error) });\n process.exit(1);\n }\n\n process.exit(0);\n });\n }\n}\n\nexport function initWorker(cx: FluxionContext) {\n if (cluster.isPrimary) {\n $throw('createWorker should only be called in worker process');\n }\n\n new FluxionWorkerRuntime(cx).start();\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { FluxionContext } from '../types.js';\n\nexport type WatcherContext = Pick<FluxionContext, 'options' | 'logger' | 'router'>;\n\nexport abstract class FluxionWatcherBase {\n protected readonly cx: WatcherContext;\n\n private timer: NodeJS.Timeout | null = null;\n private readonly filesChanged = new Map<string, string>();\n\n constructor(cx: WatcherContext) {\n this.cx = cx;\n }\n\n /**\n * Recursively register all files in the options directory.\n */\n protected async init(): Promise<this> {\n const dir = this.cx.options.dir;\n if (!fs.existsSync(dir)) {\n this.cx.logger.warn(`Directory does not exist: ${dir}`);\n return this;\n }\n\n const registerList: Array<Promise<void>> = [];\n\n const registerRecursive = (absoluteDir: string, relativeDir: string) => {\n const entries = fs.readdirSync(absoluteDir, { withFileTypes: true });\n\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n const absolutePath = path.join(absoluteDir, entry.name);\n const relativePath = path.join(relativeDir, entry.name);\n\n if (entry.isDirectory()) {\n registerRecursive(absolutePath, relativePath);\n } else if (entry.isFile()) {\n const p = this.cx.router.register(absolutePath, relativePath).catch((e) => {\n this.cx.logger.error(`Error registering file ${relativePath}: ${(e as Error).message}`);\n });\n registerList.push(p);\n }\n }\n };\n\n registerRecursive(dir, '');\n await Promise.all(registerList);\n\n this.cx.logger.info(`Initial registration complete for directory: ${dir}`);\n return this;\n }\n\n protected queueUp(absolutePath: string, relativePath: string): void {\n this.filesChanged.set(absolutePath, relativePath);\n if (this.timer) {\n return;\n }\n\n this.timer = setTimeout(async () => {\n const promises = [...this.filesChanged].map(([absolutePath, relativePath]) =>\n this.cx.router\n .register(absolutePath, relativePath)\n .catch((err) => this.cx.logger.error(`Error refreshing handlers: ${(err as Error).message}`))\n .finally(() => this.filesChanged.delete(absolutePath)),\n );\n await Promise.all(promises);\n this.timer = null;\n }, this.cx.options.reloadDelay);\n }\n\n protected stopCore(): void {\n if (this.timer) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n\n this.filesChanged.clear();\n }\n\n abstract start(): Promise<this>;\n abstract stop(): this;\n}\n","import path from 'node:path';\nimport type { FSWatcher } from 'chokidar';\nimport chokidar from 'chokidar';\n\nimport { FluxionWatcherBase, type WatcherContext } from './base.js';\n\nexport class FluxionChokidarWatcher extends FluxionWatcherBase {\n private watcher: FSWatcher | null = null;\n\n constructor(cx: WatcherContext) {\n super(cx);\n }\n\n /**\n * Start watching files with chokidar.\n *\n * Using chokidar provides:\n * - Cross-platform recursive watch support (including Linux/CentOS)\n * - Better event handling and stability\n * - Automatic resource management\n */\n async start(): Promise<this> {\n this.stop();\n await this.init();\n\n const dir = this.cx.options.dir;\n this.watcher = chokidar\n .watch(dir, {\n persistent: true, // Keep the process running\n ignoreInitial: true, // Don't emit 'add' events for initial scan\n usePolling: false, // Use polling as fallback (helps with some network drives)\n awaitWriteFinish: {\n stabilityThreshold: 100,\n pollInterval: 50,\n }, // Atomic writes handling\n })\n .on('all', (_event, absolutePath) => {\n if (!absolutePath) {\n return;\n }\n\n // & `filename` is absolute(Maybe because of watching an absolute path `dir`)\n this.queueUp(absolutePath, path.relative(dir, absolutePath));\n })\n .on('error', (err: unknown) => {\n const error = err instanceof Error ? err : new Error(String(err));\n this.cx.logger.error(`Watcher error: ${error.message}`);\n this.cx.logger.error(`Restarting watcher...`);\n this.start();\n })\n .on('ready', () => {\n this.cx.logger.info(`Watcher ready and watching directory: ${dir}`);\n });\n\n this.cx.logger.info(`Watcher started on directory: ${dir}`);\n return this;\n }\n\n stop(): this {\n if (this.watcher) {\n void this.watcher.close();\n this.watcher = null;\n }\n\n this.stopCore();\n return this;\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { FluxionWatcherBase, type WatcherContext } from './base.js';\n\nexport class FluxionNativeWatcher extends FluxionWatcherBase {\n private watcher: fs.FSWatcher | null = null;\n\n constructor(cx: WatcherContext) {\n super(cx);\n }\n\n /**\n * Since all actions are mapped to `rename` and `change` (WatchEventType).\n *\n * We could only record every file and reload them all.\n */\n async start(): Promise<this> {\n this.stop();\n await this.init();\n\n const dir = this.cx.options.dir;\n this.watcher = fs\n .watch(dir, { recursive: true }, (_eventType, relativePath) => {\n if (!relativePath) {\n return;\n }\n\n // & Unlike chokidar, `filename` here is relativePath\n this.queueUp(path.join(dir, relativePath), relativePath);\n })\n .on('error', (err) => {\n this.cx.logger.error(`Watcher error: ${err.message}`);\n this.cx.logger.error(`Restarting watcher...`);\n this.start();\n });\n\n this.cx.logger.info(`Watcher started on directory: ${dir}`);\n return this;\n }\n\n stop(): this {\n if (this.watcher) {\n this.watcher.close();\n this.watcher = null;\n }\n\n this.stopCore();\n return this;\n }\n}\n","function n(n) {}\n\nconst t = n;\n\nfunction o() {\n return n => {};\n}\n\nexport { o as createNarrower, n as narrow, t as static_cast };\n","import type { FluxionContext, FluxionModuleWithType } from '@/types.js';\nimport { static_cast } from 'type-narrow';\nimport { FluxionModuleType } from './consts';\n\nfunction isFluxionModule(cx: Pick<FluxionContext, 'options' | 'logger'>, o: unknown): o is FluxionModuleWithType {\n if (typeof o !== 'object' || o === null) {\n return false;\n }\n\n static_cast<FluxionModuleWithType>(o);\n\n if (typeof o.handler !== 'function') {\n cx.logger.error(`handler must be a function`);\n return false;\n }\n\n if (o.disposer !== undefined && typeof o.disposer !== 'function') {\n cx.logger.error(`disposer must be a function if provided`);\n return false;\n }\n\n const ms = o.handlerTimeoutMs;\n if (ms !== undefined && (!Number.isSafeInteger(ms) || ms < 100)) {\n cx.logger.error(`handlerTimeoutMs must be an integer >= 100 if provided`);\n return false;\n }\n\n if (o.type !== FluxionModuleType.Api) {\n cx.logger.error(`You must use defineFluxionModule to create module`);\n return false;\n }\n\n return true;\n}\n\nexport function loadFluxionModule(\n cx: Pick<FluxionContext, 'options' | 'logger'>,\n fullpath: string,\n): FluxionModuleWithType {\n delete require.cache[fullpath];\n let m = require(fullpath);\n if (isFluxionModule(cx, m.default)) {\n m = m.default;\n } else if (isFluxionModule(cx, m)) {\n } else {\n $throw(`Invalid handler module '${fullpath}', make sure it satisfies defineFluxionModule(...) helper`);\n }\n\n return m;\n}\n","import type { FluxionContext, FluxionModuleWithType, FluxionRouteMeta } from '../types.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { minimatch } from 'minimatch';\nimport { FluxionModuleType, STATIC_CONTENT_TYPES, STATIC_HANDLED_FLAG } from '@/common/consts.js';\nimport { loadFluxionModule } from '@/common/injector.js';\nimport { PromiseTry } from '@/common/promise-try.js';\n\nexport class FluxionRouter {\n private readonly cx: Pick<FluxionContext, 'options' | 'logger'>;\n private readonly handlers: Map<string, FluxionModuleWithType> = new Map();\n\n constructor(cx: Pick<FluxionContext, 'options' | 'logger'>) {\n this.cx = cx;\n }\n\n makeStaticResource(filepath: string): FluxionModuleWithType {\n return {\n type: FluxionModuleType.StaticResource,\n handler: async (normalized, _cx, req, res) => {\n if (normalized.method !== 'GET' && normalized.method !== 'HEAD') {\n res.statusCode = 405;\n res.setHeader('Allow', 'GET, HEAD');\n res.end();\n return;\n }\n\n if (!fs.existsSync(filepath)) {\n res.statusCode = 404;\n res.end('Not Found');\n return;\n }\n\n const stat = fs.statSync(filepath);\n if (!stat.isFile()) {\n res.statusCode = 404;\n res.end('Not Found');\n return;\n }\n\n const extension = path.extname(filepath).toLowerCase();\n const contentType = STATIC_CONTENT_TYPES[extension] ?? 'application/octet-stream';\n\n res.statusCode = 200;\n res.setHeader('Content-Type', contentType);\n res.setHeader('Content-Length', String(stat.size));\n\n if (normalized.method === 'HEAD') {\n res.end();\n return;\n }\n\n return new Promise<symbol>((resolve, reject) => {\n const stream = fs.createReadStream(filepath);\n\n const cleanup = () => {\n stream.off('error', onError);\n stream.off('end', onEnd);\n res.off('close', onClientClose);\n req.off('aborted', onClientClose);\n };\n\n const onError = (error: Error) => {\n cleanup();\n reject(error);\n };\n\n const onEnd = () => {\n cleanup();\n resolve(STATIC_HANDLED_FLAG);\n };\n\n const onClientClose = () => {\n cleanup();\n stream.destroy();\n resolve(STATIC_HANDLED_FLAG);\n };\n\n stream.on('error', onError);\n stream.on('end', onEnd);\n res.on('close', onClientClose);\n req.on('aborted', onClientClose);\n\n stream.pipe(res);\n });\n },\n };\n }\n\n /**\n * File registration logic with fast-glob pattern matching:\n * 1. Check if the path exists, if not, delete the handler;\n * 2. If file doesn't match include patterns, skip registration;\n * 3. If file matches exclude patterns, skip registration;\n * 4. If file matches apiInclude patterns, register as API handler;\n * 5. Otherwise, register as static resource.\n */\n async register(absolutePath: string, relativePath: string) {\n // Get the disposer and delete\n const disposer = this.handlers.get(relativePath)?.disposer;\n if (disposer) {\n await PromiseTry(disposer);\n }\n\n // # Delete\n if (!fs.existsSync(absolutePath)) {\n this.handlers.delete(relativePath);\n this.cx.logger.info({ action: 'Delete', url: relativePath });\n return;\n }\n\n // Step 2: Check if file matches include patterns (default: all files)\n // If not matching, skip registration\n const matchesInclude = this.cx.options.include.some((pattern) => minimatch(relativePath, pattern));\n if (!matchesInclude) {\n this.handlers.delete(relativePath);\n this.cx.logger.info({ action: 'Skip', url: relativePath });\n return;\n }\n\n // Step 3: Check if file matches exclude patterns\n // If matching, skip registration\n const matchesExclude = this.cx.options.exclude.some((pattern) => minimatch(relativePath, pattern));\n if (matchesExclude) {\n this.handlers.delete(relativePath);\n this.cx.logger.info({ action: 'Exclude', url: relativePath });\n return;\n }\n\n // Step 4 & 5: Check if file matches apiInclude patterns\n // If matching, register as API handler; otherwise as static resource\n const matchesApiInclude = this.cx.options.apiInclude.some((pattern) => minimatch(relativePath, pattern));\n if (matchesApiInclude) {\n const m = loadFluxionModule(this.cx, absolutePath);\n this.handlers.set(relativePath, m);\n this.cx.logger.info({ action: 'RegisterApi', url: relativePath });\n return;\n }\n\n // register as static resource\n this.handlers.set(relativePath, this.makeStaticResource(absolutePath));\n this.cx.logger.info({ action: 'RegisterStatic', url: relativePath });\n }\n\n getModule(url: URL): FluxionModuleWithType | undefined {\n const relativePath = url.pathname.replace(/^[/]+/, '').replace(/[/]+$/, '');\n return this.handlers.get(relativePath);\n }\n\n getRoutes(): FluxionRouteMeta[] {\n return [...this.handlers.entries()]\n .map(\n ([relativePath, m]): FluxionRouteMeta => ({\n path: '/' + relativePath,\n type: m.type === FluxionModuleType.Api ? 'api' : 'static',\n methods: m.methods ? [...m.methods] : null,\n }),\n )\n .sort((a, b) => a.path.localeCompare(b.path));\n }\n}\n","import type { FluxionContext, FluxionOptions, NormalizedFluxionOptions } from './types.js';\nimport cluster from 'node:cluster';\n\nimport { createLogger, createWorkerLogger } from './common/logger.js';\nimport { OPTIONS_NORMALIZED_FLAG } from './common/consts.js';\nimport { defineFluxionOptions } from './defines/options.js';\nimport { initPrimary } from './cluster/primary.js';\nimport { initWorker } from './cluster/worker.js';\nimport { FluxionChokidarWatcher } from './watcher/chokidar.js';\nimport { FluxionNativeWatcher } from './watcher/native.js';\nimport { FluxionRouter } from './router/index.js';\n\nexport async function fluxion(options: FluxionOptions | NormalizedFluxionOptions) {\n const alreadyNormalized = (options as NormalizedFluxionOptions).normalizedFlag === OPTIONS_NORMALIZED_FLAG;\n const context = { options: alreadyNormalized ? options : defineFluxionOptions(options) } as FluxionContext;\n\n context.logger = createLogger(context as Pick<FluxionContext, 'options'>);\n context.router = new FluxionRouter(context as Pick<FluxionContext, 'options' | 'logger'>);\n\n if (cluster.isPrimary) {\n await initPrimary(context);\n } else {\n // Replace logger with worker logger that prefixes PID\n context.logger = createWorkerLogger(context.logger, process.pid);\n // Only worker creates the watcher\n const Watcher = context.options.nativeWatcher ? FluxionNativeWatcher : FluxionChokidarWatcher;\n context.watcher = await new Watcher(context as Pick<FluxionContext, 'options' | 'logger' | 'router'>).start();\n initWorker(context);\n }\n}\n","import type {\n FluxionHandler,\n FluxionDisposer,\n FluxionModuleWithType,\n FluxionModule,\n FluxionMiddleware,\n} from '@/types.js';\nimport type { FluxionLoggerFn } from '@/common/logger.js';\nimport { FluxionModuleType } from '@/common/consts.js';\n\nexport { defineFluxionOptions } from './options.js';\n\n/**\n * Use handler function and optional disposer function to define a Fluxion module.\n * @param handler Main function that handles request and response instances\n * @param disposer Deal with resource cleanup when the server is about to close\n */\nexport function defineFluxionModule(handler: FluxionHandler, disposer?: FluxionDisposer): FluxionModuleWithType;\n/**\n * Provides type safety for defining Fluxion modules.\n */\nexport function defineFluxionModule(fluxionModule: FluxionModule): FluxionModuleWithType;\nexport function defineFluxionModule(\n a: FluxionModule | FluxionHandler,\n disposer?: FluxionDisposer,\n): FluxionModuleWithType {\n if (typeof a === 'function') {\n if (disposer !== undefined && typeof disposer !== 'function') {\n $throw(`Invalid disposer, expected a function but got ${typeof disposer}`);\n }\n return { handler: a, disposer, type: FluxionModuleType.Api };\n }\n\n if (typeof a !== 'object' || a === null) {\n $throw(`Invalid argument, expected a FluxionModule object or a handler function, but got ${typeof a}`);\n }\n\n if (typeof a.handler !== 'function') {\n $throw(`Invalid FluxionModule, \"handler\" must be a function`);\n }\n\n if (a.disposer !== undefined && typeof a.disposer !== 'function') {\n $throw(`Invalid FluxionModule, \"disposer\" must be a function if provided`);\n }\n\n if (a.methods !== undefined && (!Array.isArray(a.methods) || a.methods.some((v) => typeof v !== 'string'))) {\n $throw(`Invalid FluxionModule, \"methods\" must be an array of strings if provided`);\n }\n\n if (\n a.middlewares !== undefined &&\n (!Array.isArray(a.middlewares) || a.middlewares.some((v) => typeof v !== 'function'))\n ) {\n $throw(`Invalid FluxionModule, \"middlewares\" must be an array of functions if provided`);\n }\n\n return { ...a, type: FluxionModuleType.Api };\n}\n\nexport function defineFluxionMiddleware(middleware: FluxionMiddleware): FluxionMiddleware {\n if (typeof middleware !== 'function') {\n $throw(`Invalid FluxionMiddleware, expected a function but got ${typeof middleware}`);\n }\n return middleware;\n}\n\nexport function defineFluxionLogger(loggerFn: FluxionLoggerFn) {\n if (typeof loggerFn !== 'function') {\n $throw(`Invalid FluxionLoggerFn, expected a function but got ${typeof loggerFn}`);\n }\n return loggerFn;\n}\n"],"x_google_ignoreList":[23],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{C as e,S as t,_ as n,a as r,b as i,c as a,d as o,f as s,g as c,h as l,i as u,l as d,m as f,n as p,o as m,p as h,r as g,s as _,t as v,u as y,v as b,y as x}from"./fluxion--NlXBaPd.mjs";function S(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 C(e){if(typeof e!=`function`)throw Error(`[fluxion error] Invalid FluxionMiddleware, expected a function but got ${typeof e}`);return e}function w(e){if(typeof e!=`function`)throw Error(`[fluxion error] Invalid FluxionLoggerFn, expected a function but got ${typeof e}`);return e}export{p as BadGatewayException,g as BadRequestException,u as ConflictException,r as ForbiddenException,m as GatewayTimeoutException,_ as GoneException,e as HttpCode,a as HttpException,d as InternalServerErrorException,y as MethodNotAllowedException,o as NotAcceptableException,s as NotFoundException,h as NotImplementedException,f as PayloadTooLargeException,l as RequestTimeoutException,c as ServiceUnavailableException,n as TooManyRequestsException,b as UnauthorizedException,x as UnprocessableEntityException,i as UnsupportedMediaTypeException,w as defineFluxionLogger,C as defineFluxionMiddleware,S as defineFluxionModule,t as defineFluxionOptions,v as fluxion};
|
|
1
|
+
import{createRequire as e}from"node:module";import t from"node:cluster";import n from"fast-json-stable-stringify";import r from"node:fs";import i from"node:path";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=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 f=process.env.FLUXION_COLORS!==`0`;let p;(function(e){e.reset=f?`\x1B[0m`:``,e.bold=f?`\x1B[1m`:``,e.dim=f?`\x1B[2m`:``,e.italic=f?`\x1B[3m`:``,e.underline=f?`\x1B[4m`:``,e.blink=f?`\x1B[5m`:``,e.inverse=f?`\x1B[7m`:``,e.black=f?`\x1B[30m`:``,e.red=f?`\x1B[31m`:``,e.green=f?`\x1B[32m`:``,e.yellow=f?`\x1B[33m`:``,e.blue=f?`\x1B[34m`:``,e.magenta=f?`\x1B[35m`:``,e.cyan=f?`\x1B[36m`:``,e.white=f?`\x1B[37m`:``,e.brightBlack=f?`\x1B[90m`:``,e.brightRed=f?`\x1B[91m`:``,e.brightGreen=f?`\x1B[92m`:``,e.brightYellow=f?`\x1B[93m`:``,e.brightBlue=f?`\x1B[94m`:``,e.brightMagenta=f?`\x1B[95m`:``,e.brightCyan=f?`\x1B[96m`:``,e.brightWhite=f?`\x1B[97m`:``,e.bgBlack=f?`\x1B[40m`:``,e.bgRed=f?`\x1B[41m`:``,e.bgGreen=f?`\x1B[42m`:``,e.bgYellow=f?`\x1B[43m`:``,e.bgBlue=f?`\x1B[44m`:``,e.bgMagenta=f?`\x1B[45m`:``,e.bgCyan=f?`\x1B[46m`:``,e.bgWhite=f?`\x1B[47m`:``,e.bgBrightBlack=f?`\x1B[100m`:``,e.bgBrightRed=f?`\x1B[101m`:``,e.bgBrightGreen=f?`\x1B[102m`:``,e.bgBrightYellow=f?`\x1B[103m`:``,e.bgBrightBlue=f?`\x1B[104m`:``,e.bgBrightMagenta=f?`\x1B[105m`:``,e.bgBrightCyan=f?`\x1B[106m`:``,e.bgBrightWhite=f?`\x1B[107m`:``,e.purple=f?`\x1B[38;2;225;16;248m`:``,e.orange=f?`\x1B[38;2;248;147;16m`:``,e.darkGreen=f?`\x1B[38;2;22;101;52m`:``,e.claude=f?`\x1B[38;2;217;119;87m`:``,e.deepseek=f?`\x1B[38;2;57;100;254m`:``,e.gpt=f?`\x1B[38;2;41;60;77m`:``})(p||={});const m=e=>{try{return n(e)}catch{return`[unserializable]`}},h={INFO:`${p.cyan}INFO${p.reset}`,WARN:`${p.orange}WARN${p.reset}`,ERROR:`${p.red}ERROR${p.reset}`,SUCC:`${p.green}SUCC${p.reset}`,DEBUG:`${p.blue}DEBUG${p.reset}`,VERBOSE:`${p.purple}VERBOSE${p.reset}`},g=e=>{let{level:t,timestamp:n,message:r,pid:i,...a}=e,o=`${p.darkGreen}[${n}]${p.reset}`,s=h[t]??t,c=i===void 0?``:` [${i}]`,l=Object.keys(a).length>0?` ${p.dim}${m(a)}${p.reset}`:``;console.log(`${o} ${s}${c} ${r}${l}`)};function _(e){let t=e.options.logger;return t===void 0||t===`one-line`?g:t===`json-line`?e=>console.log(m(e)):t}function v(e){let t=_(e);return{write(e,n){let r=typeof n==`string`?{message:n,timestamp:d(),level:e}:{...n,timestamp:d(),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 y(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 b=typeof Error.isError==`function`?e=>Error.isError(e)?e.message:String(e):e=>e?.message||String(e),x=Symbol(`fluxion.router.StaticHandled`),S=Symbol(`fluxion.router.StaticHandled`),C=Symbol(`fluxion.handlerTimeout`),w=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`};let te=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 ne(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=i.isAbsolute(e)?e:i.join(t,e);if(r.existsSync(n))return r.readFileSync(n)}return Buffer.from(e)}throw Error(`[fluxion error] Certificate content must be a string or Buffer`)}function E(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 D(e){if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`[fluxion error] FluxionOptions must be an object`);let{dir:t,host:n,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 t!=`string`)throw Error(`[fluxion error] FluxionOptions.dir must be a string`);let S=i.resolve(t);if(typeof u!=`string`)throw Error(`[fluxion error] FluxionOptions.moduleDir must be a string`);let C=i.resolve(u);if(typeof n!=`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 r.existsSync(S)||r.mkdirSync(S,{recursive:!0}),{dir:S,host:n,port:a,handlerTimeoutMs:o,middlewareTimeoutMs:s,staticResourceTimeoutMs:c,reloadDelay:p,metaPort:l,moduleDir:C,workerOptions:ne(d),maxRequestBytes:f,logger:b,include:m,apiInclude:h,exclude:g,nativeWatcher:v,metaSecret:y,https:E(_,C),normalizedFlag:x}}const re=e=>[100,101].includes(e?.type),ie=e=>[202,200,201,203,204].includes(e?.type),O=e=>process.send?.(e),k=(e,t)=>e.send(t);function A(e,t,n=200){e.statusCode=n,e.setHeader(`Content-Type`,`application/json; charset=utf-8`),e.end(JSON.stringify(t))}function j(e,t,n=200){if(!e.writableEnded){if(e.headersSent){e.end();return}A(e,t,n)}}function ae(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{A(i,{message:`Bad Request: invalid url`},400);return}if(a===`GET`&&o.pathname===`/_fluxion/healthz`){A(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`){A(i,{ok:!0,now:Date.now(),workers:t()});return}if(a===`GET`&&o.pathname===`/_fluxion/routes`){if(!e.options.metaSecret){A(i,{message:`Not Found`},404);return}if(o.searchParams.get(`secret`)!==e.options.metaSecret){A(i,{message:`Forbidden`},403);return}let t=await n();A(i,{ok:!0,now:Date.now(),routes:t});return}A(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:b(t)}),process.exit(1)}),r.listen(e.options.metaPort,e.options.host),r}const M=new class e{instanceFilePath;isUnregistering=!1;static KILL_POLL_INTERVAL_MS=300;static SIGTERM_TIMEOUT_MS=1e4;static SIGKILL_TIMEOUT_MS=1e3;constructor(){let e=i.join(a.homedir(),`.fluxion`);this.instanceFilePath=i.join(e,`instances.json`),r.existsSync(e)||r.mkdirSync(e,{recursive:!0}),process.on(`exit`,()=>this.unregister())}isAlive(e){try{return process.kill(e,0),!0}catch{return!1}}readAlive(){let e=[];try{if(r.existsSync(this.instanceFilePath)){let t=r.readFileSync(this.instanceFilePath,`utf-8`),n=JSON.parse(t);n.instances!==void 0&&!Array.isArray(n.instances)&&(console.error(`[FluxionInstanceManager] 'instances' of ${this.instanceFilePath} is not an array. It seems that the record file is corrupted`),e=[]),e=n.instances||[]}}catch(e){console.error(`[FluxionInstanceManager] Failed to read instance.json:`,e)}return e.filter(e=>this.isAlive(e.pid))}update(e){try{let t={instances:e};r.writeFileSync(this.instanceFilePath,JSON.stringify(t,null,2),`utf-8`)}catch(e){console.error(`[FluxionInstanceManager] Failed to write instance.json:`,e)}}async waitForExit(t,n){let r=Math.ceil(n/e.KILL_POLL_INTERVAL_MS);for(let n=0;n<r;n++){if(!this.isAlive(t))return!0;await new Promise(t=>{setTimeout(t,e.KILL_POLL_INTERVAL_MS)})}return!this.isAlive(t)}async kill(t){try{process.kill(t,`SIGTERM`)}catch(e){return console.error(`[FluxionInstanceManager] Failed to kill process ${t}:`,e),!1}if(await this.waitForExit(t,e.SIGTERM_TIMEOUT_MS))return!0;console.warn(`[FluxionInstanceManager] Process ${t} did not exit after SIGTERM, sending SIGKILL`);try{process.kill(t,`SIGKILL`)}catch(e){return console.error(`[FluxionInstanceManager] Failed to force kill process ${t}:`,e),!1}return this.waitForExit(t,e.SIGKILL_TIMEOUT_MS)}async register(e,t,n,r){let i=process.pid,a=process.cwd(),o=this.readAlive().find(t=>t.configPath===e);if(o){if(console.warn(`[FluxionInstanceManager] Found existing instance with same config or port: PID=${o.pid}, PORT=${o.port}`),!await this.kill(o.pid))throw Error(`[FluxionInstanceManager] Failed to stop old process ${o.pid}`);console.warn(`[FluxionInstanceManager] Killed old process ${o.pid}`);let e=this.readAlive().filter(e=>e.pid!==o.pid);this.update(e)}let s=this.readAlive().filter(e=>e.pid!==i),c={startTime:Date.now(),pid:i,host:t,port:n,metaPort:r,cwd:a,configPath:e};s.push(c),this.update(s),console.info(`[FluxionInstanceManager] Registered instance: PID=${i}, PORT=${n}, PATH=${e}`)}unregister(){if(this.isUnregistering)return;this.isUnregistering=!0;let e=process.pid;try{let t=this.readAlive(),n=t.filter(t=>t.pid!==e);n.length!==t.length&&(this.update(n),console.info(`[FluxionInstanceManager] Unregistered instance: PID=${e}`))}finally{this.isUnregistering=!1}}print(){let e=this.readAlive();console.info(`[FluxionInstanceManager] Current instances:`);for(let t of e)console.info(` - PID: ${t.pid}, PORT: ${t.port}, PATH: ${t.configPath}, START: ${new Date(t.startTime).toISOString()}`)}};async function N(e,t,n,r){await M.register(e,t,n,r)}async function P(){await M.unregister()}const F=e=>Number((e/1024/1024).toFixed(2)),I=6e4,L=1e4;var oe=class{cx;workers=new Map;routeRequests=new Map;restartLog=new Map;configPath;restartWhen;workerCount;routeRequestId=0;pingTimer;metaServer;shuttingDown=!1;shutdownPromise=null;constructor(e){this.cx=e,this.configPath=i.join(e.options.moduleDir||process.cwd(),`fluxion.config.ts`),this.restartWhen=e.options.workerOptions.restartWhen,this.metaServer=ae(this.cx,()=>this.getWorkersSnapshot(),()=>this.getRoutesSnapshot());let t=Math.max(1,a.cpus().length);this.workerCount=Math.max(1,Math.min(e.options.workerOptions.maxWorkerCount??Math.min(2,t),t))}async start(){await N(this.configPath,this.cx.options.host,this.cx.options.port,this.cx.options.metaPort),this.cx.logger.info({message:`PrimaryStarted`,pid:process.pid,workers:this.workerCount,host:this.cx.options.host,port:this.cx.options.port,metaPort:this.cx.options.metaPort}),this.registerProcessHandlers();for(let e=0;e<this.workerCount;e++)this.spawnSlot(e+1);this.startPingLoop()}registerProcessHandlers(){let e=e=>{this.beginShutdown(e)};process.once(`SIGINT`,()=>e(`SIGINT`)),process.once(`SIGTERM`,()=>e(`SIGTERM`))}restartCountInWindow(e){let t=Date.now(),n=(this.restartLog.get(e)??[]).filter(e=>t-e<I);return this.restartLog.set(e,n),n.length}recordRestart(e){let t=Date.now(),n=(this.restartLog.get(e)??[]).filter(e=>t-e<I);n.push(t),this.restartLog.set(e,n)}isStorming(e){return this.restartCountInWindow(e)>=3}getWorkersSnapshot(){return{primaryPid:process.pid,host:this.cx.options.host,port:this.cx.options.port,metaPort:this.cx.options.metaPort,uptimeSeconds:Number(process.uptime().toFixed(3)),shuttingDown:this.shuttingDown,workers:Array.from(this.workers.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)}}}})}}getRoutesSnapshot(){let e=Array.from(this.workers.values()).find(e=>e.state===`ready`&&e.instance.isConnected());return e?new Promise(t=>{let n=++this.routeRequestId,r=setTimeout(()=>{this.routeRequests.delete(n),t([])},1e3);r.unref(),this.routeRequests.set(n,{resolve:t,timer:r});try{k(e.instance,{type:101,requestId:n})}catch{clearTimeout(r),this.routeRequests.delete(n),t([])}}):Promise.resolve([])}initiateRecycle(e,t){if(!this.shuttingDown){for(let e of this.workers.values())if(e.state===`restarting`)return;if(this.isStorming(e.slot)){this.cx.logger.warn({message:`WorkerRecycleSuppressed`,slot:e.slot,pid:e.pid,reason:t,windowMs:I,max:3});return}this.recordRestart(e.slot),e.state=`restarting`,e.restartReason=t,this.cx.logger.warn({message:`WorkerRecycling`,slot:e.slot,pid:e.pid,reason:t}),e.instance.kill()}}evaluateResourceConditions(e,t){if(this.shuttingDown)return;let n=F(t.memory.rss);if(n>this.restartWhen.memoryUsageGreaterThan){this.initiateRecycle(e,`memoryUsageGreaterThan: rss ${n}MB > ${this.restartWhen.memoryUsageGreaterThan}MB`);return}let r=t.uptimeSeconds*1e3;r>this.restartWhen.uptimeGreaterThan&&this.initiateRecycle(e,`uptimeGreaterThan: ${Math.round(r/1e3)}s > ${Math.round(this.restartWhen.uptimeGreaterThan/1e3)}s`)}evaluateLiveness(e){if(!this.shuttingDown)for(let t of this.workers.values()){if(t.state!==`ready`||t.lastPongAt===void 0)continue;let n=e-t.lastPongAt;n>this.restartWhen.healthzTimeout&&this.initiateRecycle(t,`healthzTimeout: no pong for ${Math.round(n/1e3)}s > ${Math.round(this.restartWhen.healthzTimeout/1e3)}s`)}}spawnSlot(e){this.shuttingDown||this.attachWorker(t.fork({WORKER_ID:String(e)}),e)}attachWorker(e,t){let n={state:`creating`,pid:e.process.pid,slot:t,createdAt:Date.now(),instance:e};this.workers.set(e.id,n),e.on(`message`,r=>{if(ie(r)){if(r.type===202){let e=Date.now()-r.sentAt;n.pid=r.pid,n.lastPongAt=Date.now(),n.lastRttMs=e;return}if(r.type===201){n.state=`ready`,n.pid=r.pid,n.readyAt=Date.now(),this.cx.logger.info({message:`WorkerReady`,workerId:e.id,slot:t,pid:r.pid});return}if(r.type===200){n.state=`created`,n.pid=r.pid,this.cx.logger.info({message:`WorkerCreated`,workerId:e.id,slot:t,pid:r.pid});return}if(r.type===203){n.pid=r.pid,n.lastStats=r.stats,n.state===`ready`&&this.evaluateResourceConditions(n,r.stats);return}if(r.type===204){let e=this.routeRequests.get(r.requestId);e&&(clearTimeout(e.timer),this.routeRequests.delete(r.requestId),e.resolve(r.routes))}}}),e.on(`exit`,(t,n)=>{let r=this.workers.get(e.id);this.workers.delete(e.id);let i=r?.slot,a=r?.state===`restarting`||this.shuttingDown,o=r?.restartReason??(this.shuttingDown?`shutdown`:null);if(this.cx.logger.warn({message:`WorkerExited`,workerId:e.id,slot:i??null,pid:e.process.pid??`unknown`,code:t,signal:n??`none`,expected:a,reason:o}),!(i===void 0||this.shuttingDown)){if(r?.state===`restarting`){this.spawnSlot(i);return}if(this.recordRestart(i),this.isStorming(i)){this.cx.logger.error({message:`WorkerRespawnSuppressed`,slot:i,windowMs:I,max:3});return}this.spawnSlot(i)}})}startPingLoop(){this.pingTimer=setInterval(()=>{let e=Date.now();for(let t of this.workers.values())if(t.instance.isConnected())try{k(t.instance,{type:100,sentAt:e})}catch{}this.evaluateLiveness(Date.now())},5e3),this.pingTimer.unref()}stopTimers(){this.pingTimer&&=(clearInterval(this.pingTimer),void 0);for(let[e,t]of this.routeRequests.entries())clearTimeout(t.timer),t.resolve([]),this.routeRequests.delete(e)}getAliveWorkers(){return Array.from(this.workers.values()).filter(e=>!e.instance.isDead())}async waitForWorkersToExit(e){let t=Date.now()+e;for(;Date.now()<t;){if(this.getAliveWorkers().length===0)return[];await new Promise(e=>{setTimeout(e,200)})}return this.getAliveWorkers()}async forceKillWorkers(e){for(let t of e){let e=t.pid??t.instance.process.pid;this.cx.logger.error({message:`WorkerForceKilled`,slot:t.slot,pid:e??null});try{t.instance.process.kill(`SIGKILL`)}catch{}}await this.waitForWorkersToExit(1e3)}async shutdownWorkers(e){let t=this.getAliveWorkers();for(let n of t){let t=n.pid??n.instance.process.pid;this.cx.logger.warn({message:`WorkerShutdownRequested`,slot:n.slot,pid:t??null,signal:e});try{n.instance.kill(e)}catch{}}let n=await this.waitForWorkersToExit(L);n.length!==0&&(this.cx.logger.error({message:`PrimaryShutdownTimeout`,pid:process.pid,remainingWorkers:n.map(e=>({slot:e.slot,pid:e.pid??e.instance.process.pid??null})),timeoutMs:L}),await this.forceKillWorkers(n))}async beginShutdown(e){if(this.shutdownPromise)return this.shutdownPromise;this.shutdownPromise=(async()=>{this.shuttingDown=!0,this.cx.logger.warn({message:`PrimaryShuttingDown`,pid:process.pid,signal:e,workerCount:this.workers.size}),this.stopTimers();try{await this.shutdownWorkers(e)}finally{this.metaServer.close(),await P()}})();try{await this.shutdownPromise,process.exit(0)}catch(t){this.cx.logger.error({message:`PrimaryShutdownFailed`,pid:process.pid,signal:e,error:t instanceof Error?t.message:String(t)}),process.exit(1)}}};async function se(e){if(!t.isPrimary)throw Error(`[fluxion error] createPrimary should only be called in primary process`);await new oe(e).start()}function R(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 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`)}},K=class extends H{constructor(e=`Gone`){super(e,410,`GONE`)}},q=class extends H{constructor(e=`Payload Too Large`){super(e,413,`PAYLOAD_TOO_LARGE`)}},me=class extends H{constructor(e=`Unsupported Media Type`){super(e,415,`UNSUPPORTED_MEDIA_TYPE`)}},he=class extends H{constructor(e=`Unprocessable Entity`){super(e,422,`UNPROCESSABLE_ENTITY`)}},ge=class extends H{constructor(e=`Too Many Requests`){super(e,429,`TOO_MANY_REQUESTS`)}},_e=class extends H{constructor(e=`Internal Server Error`){super(e,500,`INTERNAL_SERVER_ERROR`)}},ve=class extends H{constructor(e=`Not Implemented`){super(e,501,`NOT_IMPLEMENTED`)}},ye=class extends H{constructor(e=`Bad Gateway`){super(e,502,`BAD_GATEWAY`)}},be=class extends H{constructor(e=`Service Unavailable`){super(e,503,`SERVICE_UNAVAILABLE`)}},xe=class extends H{constructor(e=`Gateway Timeout`){super(e,504,`GATEWAY_TIMEOUT`)}};function J(e,t){return new q(`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 Se(e,t,n,r){return t===0?X():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 Ce(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:Se(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 we(e,t,n){let{rawBody:r,preview:i}=await Ce(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:V(new URLSearchParams(r.toString(`utf8`))),preview:i}:z(a)?{body:{raw:r.toString(`utf8`)},preview:i}:{body:{},preview:i}}function Te(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 Ee(e){let t=Object.freeze({logger:e.logger}),n=async(n,r)=>{let i=n.method??`GET`,a=ce(n),o=B(n.url);if(o===void 0){j(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:Te(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/`)){j(r,{message:`Not Found`},404);return}let i=await we(n,s.method,e.options.maxRequestBytes);s.body=i.body,c=i.preview;let a=await e.router.getModule(o);if(!a){j(r,{message:`Not Found`},404);return}if(n.method&&a.methods&&!a.methods.includes(n.method)){j(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(R(a.middlewares[i],s,t,n,r),e.options.middlewareTimeoutMs,w)===w){e.logger.warn({message:`MiddlewareTimeout`,method:s.method,ip:s.ip}),j(r,{message:`Internal Server Error`},500);return}if(r.writableEnded)return;if(r.headersSent){r.end();return}}let u=await Z(R(a.handler,s,t,n,r),l,C);if(u===C){e.logger.warn({message:`HandlerTimeout`,method:s.method,ip:s.ip}),j(r,{message:`Handler timed out`},500);return}u!==S&&j(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}),j(r,{message:t.message},t.errno)):(e.logger.error({message:`RequestFailed`,method:s.method,ip:s.ip,path:s.url.pathname,error:b(t)}),j(r,{message:b(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:b(t)}),i&&process.exit(1),n(t)}),r.listen(e.options.port,e.options.host)})}var De=class{cx;server;statsTimer;exiting=!1;constructor(e){this.cx=e}start(){this.registerMessageHandler(),this.registerSignalHandlers(),O({type:200,pid:process.pid}),this.startStatsReporter(),Ee(this.cx).then(e=>{this.server=e,O({type:201,pid:process.pid})}).catch(e=>{this.cx.logger.error({message:`WorkerBootstrapFailed`,pid:process.pid,error:b(e)}),this.cx.watcher.stop(),process.exit(1)})}registerMessageHandler(){process.on(`message`,e=>{if(re(e)){if(e.type===100){O({type:202,pid:process.pid,sentAt:e.sentAt,receivedAt:Date.now()});return}e.type===101&&O({type:204,pid:process.pid,requestId:e.requestId,routes:this.cx.router.getRoutes()})}})}startStatsReporter(){let e=process.cpuUsage(),t=Date.now();this.statsTimer=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();O({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),this.statsTimer.unref()}registerSignalHandlers(){process.once(`SIGINT`,()=>{this.shutdown(`SIGINT`)}),process.once(`SIGTERM`,()=>{this.shutdown(`SIGTERM`)})}stopStatsReporter(){this.statsTimer&&=(clearInterval(this.statsTimer),void 0)}async shutdown(e){if(this.exiting)return;this.exiting=!0,this.cx.logger.warn({message:`WorkerShuttingDown`,pid:process.pid,signal:e}),this.stopStatsReporter(),this.cx.watcher.stop(),this.server||process.exit(0);let t=setTimeout(()=>{process.exit(1)},1e4);t.unref(),this.server.close(e=>{clearTimeout(t),e&&(this.cx.logger.error({message:`WorkerShutdownFailed`,pid:process.pid,error:b(e)}),process.exit(1)),process.exit(0)})}};function Oe(e){if(t.isPrimary)throw Error(`[fluxion error] createWorker should only be called in worker process`);new De(e).start()}var Q=class{cx;timer=null;filesChanged=new Map;constructor(e){this.cx=e}async init(){let e=this.cx.options.dir;if(!r.existsSync(e))return this.cx.logger.warn(`Directory does not exist: ${e}`),this;let t=[],n=(e,a)=>{let o=r.readdirSync(e,{withFileTypes:!0});for(let r=0;r<o.length;r++){let s=o[r],c=i.join(e,s.name),l=i.join(a,s.name);if(s.isDirectory())n(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}`)});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()}},ke=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`,(t,n)=>{n&&this.queueUp(n,i.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}},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=r.watch(e,{recursive:!0},(t,n)=>{n&&this.queueUp(i.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 je(e){}const Me=je;function $(e,t){if(typeof t!=`object`||!t)return!1;if(Me(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 Ne(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 Pe=class{cx;handlers=new Map;constructor(e){this.cx=e}makeStaticResource(e){return{type:1,handler:async(t,n,a,o)=>{if(t.method!==`GET`&&t.method!==`HEAD`){o.statusCode=405,o.setHeader(`Allow`,`GET, HEAD`),o.end();return}if(!r.existsSync(e)){o.statusCode=404,o.end(`Not Found`);return}let s=r.statSync(e);if(!s.isFile()){o.statusCode=404,o.end(`Not Found`);return}let c=ee[i.extname(e).toLowerCase()]??`application/octet-stream`;if(o.statusCode=200,o.setHeader(`Content-Type`,c),o.setHeader(`Content-Length`,String(s.size)),t.method===`HEAD`){o.end();return}return new Promise((t,n)=>{let i=r.createReadStream(e),s=()=>{i.off(`error`,c),i.off(`end`,l),o.off(`close`,u),a.off(`aborted`,u)},c=e=>{s(),n(e)},l=()=>{s(),t(S)},u=()=>{s(),i.destroy(),t(S)};i.on(`error`,c),i.on(`end`,l),o.on(`close`,u),a.on(`aborted`,u),i.pipe(o)})}}}async register(e,t){let n=this.handlers.get(t)?.disposer;if(n&&await R(n),!r.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=Ne(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 n={options:e.normalizedFlag===x?e:D(e)};n.logger=v(n),n.router=new Pe(n),t.isPrimary?await se(n):(n.logger=y(n.logger,process.pid),n.watcher=await new(n.options.nativeWatcher?Ae:ke)(n).start(),Oe(n))}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}export{ye as BadGatewayException,U as BadRequestException,pe as ConflictException,G as ForbiddenException,xe as GatewayTimeoutException,K as GoneException,te as HttpCode,H as HttpException,_e as InternalServerErrorException,ue as MethodNotAllowedException,de as NotAcceptableException,le as NotFoundException,ve as NotImplementedException,q as PayloadTooLargeException,fe as RequestTimeoutException,be as ServiceUnavailableException,ge as TooManyRequestsException,W as UnauthorizedException,he as UnprocessableEntityException,me as UnsupportedMediaTypeException,Re as defineFluxionLogger,Le as defineFluxionMiddleware,Ie as defineFluxionModule,D as defineFluxionOptions,Fe as fluxion};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|