fluxion-ts 0.10.1 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -120
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +132 -6
- package/dist/index.d.mts +132 -6
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -453,140 +453,48 @@ fluxion({
|
|
|
453
453
|
|
|
454
454
|
Relative paths are resolved relative to `moduleDir`. PEM content can be passed directly as strings.
|
|
455
455
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
Dynamic directory root. Created automatically if missing.
|
|
459
|
-
|
|
460
|
-
### `host`
|
|
461
|
-
|
|
462
|
-
Host passed to `server.listen`.
|
|
463
|
-
|
|
464
|
-
### `port`
|
|
465
|
-
|
|
466
|
-
Business server port.
|
|
467
|
-
|
|
468
|
-
### `metaPort`
|
|
469
|
-
|
|
470
|
-
Primary meta API port. Defaults to `port + 1` and must be different from `port`.
|
|
471
|
-
|
|
472
|
-
### `reloadDelay`
|
|
473
|
-
|
|
474
|
-
Debounce delay for file re-registration. Defaults to `300` and must be at least `50`.
|
|
475
|
-
|
|
476
|
-
### `nativeWatcher`
|
|
477
|
-
|
|
478
|
-
Use native file watcher (`fs.watch`) instead of chokidar. Defaults to `false`.
|
|
479
|
-
|
|
480
|
-
When set to `true`, Fluxion uses Node.js built-in `fs.watch()` for file watching. When `false` (default), it uses `chokidar` for better cross-platform compatibility.
|
|
481
|
-
|
|
482
|
-
**Trade-offs:**
|
|
483
|
-
|
|
484
|
-
- `chokidar` (default): Better cross-platform support, more stable, handles edge cases
|
|
485
|
-
- `fs.watch`: Native implementation, lighter weight, but may have platform-specific quirks
|
|
486
|
-
|
|
487
|
-
Example:
|
|
488
|
-
|
|
489
|
-
```ts
|
|
490
|
-
fluxion({
|
|
491
|
-
dir: './dynamicDirectory',
|
|
492
|
-
host: '127.0.0.1',
|
|
493
|
-
port: 3000,
|
|
494
|
-
nativeWatcher: true, // use native fs.watch instead of chokidar
|
|
495
|
-
});
|
|
496
|
-
```
|
|
497
|
-
|
|
498
|
-
### `apiExts`
|
|
499
|
-
|
|
500
|
-
Extensions registered as API handlers. Defaults to:
|
|
501
|
-
|
|
502
|
-
```ts
|
|
503
|
-
['.ts']
|
|
504
|
-
```
|
|
505
|
-
|
|
506
|
-
Example:
|
|
507
|
-
|
|
508
|
-
```ts
|
|
509
|
-
fluxion({
|
|
510
|
-
dir: './dynamicDirectory',
|
|
511
|
-
host: '127.0.0.1',
|
|
512
|
-
port: 3000,
|
|
513
|
-
apiExts: ['.ts', '.mjs'],
|
|
514
|
-
});
|
|
515
|
-
```
|
|
456
|
+
## Recent Updates
|
|
516
457
|
|
|
517
|
-
###
|
|
518
|
-
|
|
519
|
-
Extensions excluded from both API and static registration.
|
|
520
|
-
|
|
521
|
-
Example:
|
|
458
|
+
### v0.11.x
|
|
522
459
|
|
|
523
|
-
|
|
524
|
-
routerExclude: ['.map']
|
|
525
|
-
```
|
|
460
|
+
**Middleware & Module System**
|
|
526
461
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
Built-in modes:
|
|
462
|
+
- ✨ Added `defineMiddleware()` and `defineFluxionModule()` functions for enhanced type safety
|
|
463
|
+
- ✨ Middleware execution now supports timeout configuration via `MIDDLEWARE_TIMEOUT_FLAG`
|
|
464
|
+
- ✨ Module context now includes logger support
|
|
465
|
+
- ✨ Enhanced module type validation with more precise function checking
|
|
466
|
+
- ✨ Added `meta` field for extended metadata support
|
|
534
467
|
|
|
535
|
-
|
|
536
|
-
- `json-line`
|
|
468
|
+
**Logging Improvements**
|
|
537
469
|
|
|
538
|
-
|
|
470
|
+
- 🔄 Unified logging interface: merged `event` and `message` fields into single `message` field
|
|
471
|
+
- ✨ Simplified logger API across all methods
|
|
539
472
|
|
|
540
|
-
|
|
473
|
+
**Handler Parameters**
|
|
541
474
|
|
|
542
|
-
|
|
475
|
+
- 🔄 Adjusted handler parameter order for better ergonomics
|
|
543
476
|
|
|
544
|
-
|
|
545
|
-
globalThis[Symbol.for('fluxion.injection')]
|
|
546
|
-
```
|
|
477
|
+
### v0.10.x
|
|
547
478
|
|
|
548
|
-
|
|
479
|
+
**HTTP Exception Handling**
|
|
549
480
|
|
|
550
|
-
|
|
481
|
+
- 🔄 Refactored HTTP exception classes: renamed error types to exception types
|
|
482
|
+
- ✨ Expanded `HttpCode` enum with additional HTTP status codes
|
|
483
|
+
- ✨ Added `BadRequestError` and other HTTP exception classes
|
|
484
|
+
- 📦 Exported exception classes for user applications
|
|
485
|
+
- ✨ Handler catch blocks now directly send response ending
|
|
551
486
|
|
|
552
|
-
|
|
553
|
-
interface WorkerOptions {
|
|
554
|
-
maxWorkerCount?: number;
|
|
555
|
-
restartWhen?: Partial<WorkerRestartWhen>;
|
|
556
|
-
}
|
|
487
|
+
**Worker Management**
|
|
557
488
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
memoryUsageGreaterThan: number;
|
|
561
|
-
/** Recycle when no Ping answer within this many ms. Default 30000. */
|
|
562
|
-
healthzTimeout: number;
|
|
563
|
-
/** Recycle after this many ms of uptime (scheduled rotation). Infinity (default) = disabled. */
|
|
564
|
-
uptimeGreaterThan: number;
|
|
565
|
-
}
|
|
566
|
-
```
|
|
489
|
+
- ✨ Added proactive worker recycling conditions (memory usage, health timeout, uptime)
|
|
490
|
+
- ✨ Enhanced worker pool tuning with `restartWhen` options
|
|
567
491
|
|
|
568
|
-
|
|
569
|
-
- `restartWhen` lets the primary proactively recycle an unhealthy worker. The worker is hard-killed and immediately respawned when **any** configured condition is met (OR semantics):
|
|
570
|
-
- `memoryUsageGreaterThan` — RSS growth / native leak, caught before the OS OOM-killer. Disabled by default.
|
|
571
|
-
- `healthzTimeout` — a wedged event loop (worker stopped answering Ping: infinite loop, deadlock, GC storm). **Defaults to `30000`ms.**
|
|
572
|
-
- `uptimeGreaterThan` — scheduled rotation to reclaim slow growth / fragmentation. Disabled by default.
|
|
573
|
-
- Conditions are evaluated by the primary against the telemetry it already collects (RSS from stats every ~2s, liveness from Ping every 5s, uptime).
|
|
574
|
-
- A shared **anti-storm guard** bounds recycling: a given slot is restarted at most 3 times per rolling 60s, after which further restarts are suppressed and alerted instead of fork-bombing.
|
|
575
|
-
- Independently of `restartWhen`, **any worker exit — crash, OOM, or proactive recycle — triggers a respawn**, so the pool stays at `maxWorkerCount`.
|
|
492
|
+
### v0.9.x
|
|
576
493
|
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
maxWorkerCount: 4,
|
|
582
|
-
restartWhen: {
|
|
583
|
-
memoryUsageGreaterThan: 256, // MB; recycle a leaking worker at 256MB RSS
|
|
584
|
-
// healthzTimeout defaults to 30000 — recycle wedged workers after 30s
|
|
585
|
-
// uptimeGreaterThan: 6 * 3600_000, // optionally rotate every 6h
|
|
586
|
-
},
|
|
587
|
-
},
|
|
588
|
-
});
|
|
589
|
-
```
|
|
494
|
+
- ✨ Added initial middleware support
|
|
495
|
+
- ✨ Added `defineMiddleware()` for middleware type safety
|
|
496
|
+
- ✨ Enhanced worker restart conditions for better memory management
|
|
497
|
+
- ✨ Restructured build and publish flow with build scripts
|
|
590
498
|
|
|
591
499
|
## Build and Test
|
|
592
500
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require("node:fs");c=s(c);let l=require("node:path");l=s(l);let u=require("node:cluster");u=s(u);let d=require("node:os");d=s(d);let f=require("node:http");f=s(f);let p=require("node:https");p=s(p);let m=require("chokidar");m=s(m);let h=require("minimatch"),g=require("type-narrow");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=JSON.stringify,y=Object.keys,b=process.env.FLUXION_COLORS!==`0`;let x;(function(e){e.reset=b?`\x1B[0m`:``,e.bold=b?`\x1B[1m`:``,e.dim=b?`\x1B[2m`:``,e.italic=b?`\x1B[3m`:``,e.underline=b?`\x1B[4m`:``,e.blink=b?`\x1B[5m`:``,e.inverse=b?`\x1B[7m`:``,e.black=b?`\x1B[30m`:``,e.red=b?`\x1B[31m`:``,e.green=b?`\x1B[32m`:``,e.yellow=b?`\x1B[33m`:``,e.blue=b?`\x1B[34m`:``,e.magenta=b?`\x1B[35m`:``,e.cyan=b?`\x1B[36m`:``,e.white=b?`\x1B[37m`:``,e.brightBlack=b?`\x1B[90m`:``,e.brightRed=b?`\x1B[91m`:``,e.brightGreen=b?`\x1B[92m`:``,e.brightYellow=b?`\x1B[93m`:``,e.brightBlue=b?`\x1B[94m`:``,e.brightMagenta=b?`\x1B[95m`:``,e.brightCyan=b?`\x1B[96m`:``,e.brightWhite=b?`\x1B[97m`:``,e.bgBlack=b?`\x1B[40m`:``,e.bgRed=b?`\x1B[41m`:``,e.bgGreen=b?`\x1B[42m`:``,e.bgYellow=b?`\x1B[43m`:``,e.bgBlue=b?`\x1B[44m`:``,e.bgMagenta=b?`\x1B[45m`:``,e.bgCyan=b?`\x1B[46m`:``,e.bgWhite=b?`\x1B[47m`:``,e.bgBrightBlack=b?`\x1B[100m`:``,e.bgBrightRed=b?`\x1B[101m`:``,e.bgBrightGreen=b?`\x1B[102m`:``,e.bgBrightYellow=b?`\x1B[103m`:``,e.bgBrightBlue=b?`\x1B[104m`:``,e.bgBrightMagenta=b?`\x1B[105m`:``,e.bgBrightCyan=b?`\x1B[106m`:``,e.bgBrightWhite=b?`\x1B[107m`:``,e.purple=b?`\x1B[38;2;225;16;248m`:``,e.orange=b?`\x1B[38;2;248;147;16m`:``,e.darkGreen=b?`\x1B[38;2;22;101;52m`:``,e.claude=b?`\x1B[38;2;217;119;87m`:``,e.deepseek=b?`\x1B[38;2;57;100;254m`:``,e.gpt=b?`\x1B[38;2;41;60;77m`:``})(x||={});const S=e=>{try{return v(e)}catch{return`[unserializable]`}},ee={INFO:`${x.cyan}INFO${x.reset}`,WARN:`${x.orange}WARN${x.reset}`,ERROR:`${x.red}ERROR${x.reset}`,SUCC:`${x.green}SUCC${x.reset}`,DEBUG:`${x.blue}DEBUG${x.reset}`,VERBOSE:`${x.purple}VERBOSE${x.reset}`},te=e=>{let{level:t,timestamp:n,event:r,message:i,...a}=e,o=`${x.darkGreen}[${n}]${x.reset}`,s=ee[t]??t,c=i??r,l=y(a).length>0?`${x.dim}${S(a)}${x.reset}`:``;console.log(`${o} ${s} ${c}${l}`)};function C(e){let t=e.options.logger;return t===void 0||t===`one-line`?te:t===`json-line`?e=>console.log(S(e)):t}function w(e){let t=C(e);return{write(e,n,r={}){let i={...r,timestamp:_(),level:e,event:n};try{t(i)}catch{}},info(e,t){this.write(`INFO`,e,t)},warn(e,t){this.write(`WARN`,e,t)},error(e,t){this.write(`ERROR`,e,t)},succ(e,t){this.write(`SUCC`,e,t)},debug(e,t){this.write(`DEBUG`,e,t)},verbose(e,t){this.write(`VERBOSE`,e,t)}}}function T(e,t){let n=`[${t}]`;return{write(t,r,i){e.write(t,`${n} ${r}`,i)},info(t,r){e.info(`${n} ${t}`,r)},warn(t,r){e.warn(`${n} ${t}`,r)},error(t,r){e.error(`${n} ${t}`,r)},succ(t,r){e.succ(`${n} ${t}`,r)},debug(t,r){e.debug(`${n} ${t}`,r)},verbose(t,r){e.verbose(`${n} ${t}`,r)}}}const E=typeof Error.isError==`function`?e=>Error.isError(e)?e.message:String(e):e=>e?.message||String(e);function D(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 O(e,t){if(Buffer.isBuffer(e))return e;if(typeof e==`string`){if(!e.startsWith(`-----BEGIN`)){let n=l.default.isAbsolute(e)?e:l.default.join(t,e);if(c.default.existsSync(n))return c.default.readFileSync(n)}return Buffer.from(e)}throw Error(`[fluxion error] Certificate content must be a string or Buffer`)}function ne(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:O(e.key,t),cert:O(e.cert,t)};return e.ca!==void 0&&(Array.isArray(e.ca)?n.ca=e.ca.map(e=>O(e,t)):n.ca=O(e.ca,t)),n}function re(e){if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`[fluxion error] FluxionOptions must be an object`);let{dir:t=l.default.isAbsolute(e.dir)?e.dir:l.default.join(process.cwd(),e.dir),host:n,port:r,handlerTimeoutMs:i=5e3,middlewareTimeoutMs:a=3e3,staticResourceTimeoutMs:o=10*6e5,metaPort:s=r+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}=e,y=e.logger??`one-line`;if(y!==`one-line`&&y!==`json-line`&&typeof y!=`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`);if(typeof u!=`string`)throw Error(`[fluxion error] FluxionOptions.moduleDir must be a string`);if(typeof n!=`string`)throw Error(`[fluxion error] FluxionOptions.host must be a string`);if(!Number.isSafeInteger(i)||i<=100)throw Error(`[fluxion error] FluxionOptions.handlerTimeoutMs must be an integer greater than 100`);if(!Number.isSafeInteger(a)||a<=100)throw Error(`[fluxion error] FluxionOptions.middlewareTimeoutMs must be an integer greater than 100`);if(typeof p!=`number`||p<=0||!Number.isSafeInteger(p))throw Error(`[fluxion error] FluxionOptions.reloadDelay must be a positive integer`);if(p<50)throw Error(`[fluxion error] FluxionOptions.reloadDelay must be greater than or equal to 50`);if(typeof r!=`number`||!Number.isSafeInteger(r))throw Error(`[fluxion error] FluxionOptions.port must be a positive integer`);if(r<=1||r>65535)throw Error(`[fluxion error] FluxionOptions.port must be 1 ~ 65535`);if(typeof s!=`number`||!Number.isSafeInteger(s))throw Error(`[fluxion error] FluxionOptions.metaPort must be a positive integer`);if(s<=1||s>65535)throw Error(`[fluxion error] FluxionOptions.metaPort must be 1 ~ 65535`);if(s===r)throw Error(`[fluxion error] FluxionOptions.metaPort must be different from FluxionOptions.port`);if(typeof d!=`object`||!d||Array.isArray(d))throw Error(`[fluxion error] FluxionOptions.workerOptions must be an object`);if(typeof f!=`number`||f<=0||!Number.isSafeInteger(f))throw Error(`[fluxion error] FluxionOptions.maxRequestBytes must be a positive integer`);return c.default.existsSync(t)||c.default.mkdirSync(t,{recursive:!0}),{dir:t,host:n,port:r,handlerTimeoutMs:i,middlewareTimeoutMs:a,staticResourceTimeoutMs:o,reloadDelay:p,metaPort:s,moduleDir:u,workerOptions:D(d),maxRequestBytes:f,logger:y,include:m,apiInclude:h,exclude:g,nativeWatcher:v,https:ne(_,u)}}const k=e=>[100].includes(e?.type),A=e=>[202,200,201,203].includes(e?.type),j=e=>process.send?.(e),ie=(e,t)=>e.send(t),M=Symbol.for(`fluxion.router.StaticHandled`),N=Symbol.for(`fluxion.handlerTimeout`),P=Symbol.for(`fluxion.middlewareTimeout`),ae={".css":`text/css; charset=utf-8`,".html":`text/html; charset=utf-8`,".ico":`image/x-icon`,".js":`text/javascript; charset=utf-8`,".json":`application/json; charset=utf-8`,".map":`application/json; charset=utf-8`,".png":`image/png`,".jpg":`image/jpeg`,".jpeg":`image/jpeg`,".svg":`image/svg+xml`,".txt":`text/plain; charset=utf-8`,".webp":`image/webp`};let oe=function(e){return e[e.Ok=200]=`Ok`,e[e.Created=201]=`Created`,e[e.Accepted=202]=`Accepted`,e[e.NoContent=204]=`NoContent`,e[e.PartialContent=206]=`PartialContent`,e[e.MovedPermanently=301]=`MovedPermanently`,e[e.Found=302]=`Found`,e[e.NotModified=304]=`NotModified`,e[e.TemporaryRedirect=307]=`TemporaryRedirect`,e[e.PermanentRedirect=308]=`PermanentRedirect`,e[e.BadRequest=400]=`BadRequest`,e[e.Unauthorized=401]=`Unauthorized`,e[e.Forbidden=403]=`Forbidden`,e[e.NotFound=404]=`NotFound`,e[e.MethodNotAllowed=405]=`MethodNotAllowed`,e[e.NotAcceptable=406]=`NotAcceptable`,e[e.RequestTimeout=408]=`RequestTimeout`,e[e.Conflict=409]=`Conflict`,e[e.Gone=410]=`Gone`,e[e.PayloadTooLarge=413]=`PayloadTooLarge`,e[e.UnsupportedMediaType=415]=`UnsupportedMediaType`,e[e.UnprocessableEntity=422]=`UnprocessableEntity`,e[e.TooManyRequests=429]=`TooManyRequests`,e[e.InternalServerError=500]=`InternalServerError`,e[e.NotImplemented=501]=`NotImplemented`,e[e.BadGateway=502]=`BadGateway`,e[e.ServiceUnavailable=503]=`ServiceUnavailable`,e[e.GatewayTimeout=504]=`GatewayTimeout`,e}({});const se=()=>{};function F(e,t,n=200){e.statusCode=n,e.setHeader(`Content-Type`,`application/json; charset=utf-8`),e.end(JSON.stringify(t))}function I(e,t,n=200){if(!e.writableEnded){if(e.headersSent){e.end();return}F(e,t,n)}}function ce(e,t){let n=f.default.createServer((e,n)=>{let r=e.method??`GET`,i=`/`;try{i=new URL(e.url??`/`,`http://fluxion.local`).pathname}catch{F(n,{message:`Bad Request: invalid url`},400);return}if(r===`GET`&&i===`/_fluxion/healthz`){F(n,{ok:!0,role:`primary`,pid:process.pid,now:Date.now(),uptimeSeconds:Number(process.uptime().toFixed(3))});return}if(r===`GET`&&i===`/_fluxion/workers`){F(n,{ok:!0,now:Date.now(),workers:t()});return}F(n,{message:`Not Found`},404)});return n.on(`listening`,()=>{e.logger.info(`MetaApiStarted`,{pid:process.pid,host:e.options.host,port:e.options.metaPort,prefix:`/_fluxion`})}),n.on(`error`,t=>{e.logger.error(`MetaApiError`,{host:e.options.host,port:e.options.metaPort,error:E(t)}),process.exit(1)}),n.listen(e.options.metaPort,e.options.host),n}const L=e=>Number((e/1024/1024).toFixed(2)),R=6e4;function z(e){if(!u.default.isPrimary)throw Error(`[fluxion error] createPrimary should only be called in primary process`);let{workerOptions:t}=e.options,n=t.restartWhen,r=Math.max(1,d.default.cpus().length),i=Math.max(1,Math.min(t.maxWorkerCount??Math.min(2,r),r));e.logger.info(`PrimaryStarted`,{pid:process.pid,workers:i,host:e.options.host,port:e.options.port,metaPort:e.options.metaPort});let a=new Map,o=new Map,s=e=>{let t=Date.now(),n=(o.get(e)??[]).filter(e=>t-e<R);return o.set(e,n),n.length},c=e=>{let t=Date.now(),n=(o.get(e)??[]).filter(e=>t-e<R);n.push(t),o.set(e,n)},l=e=>s(e)>=3;ce(e,()=>({primaryPid:process.pid,host:e.options.host,port:e.options.port,metaPort:e.options.metaPort,uptimeSeconds:Number(process.uptime().toFixed(3)),workers:Array.from(a.entries()).map(([e,t])=>{let{instance:n}=t,r=t.lastStats;return{workerId:e,slot:t.slot,pid:t.pid??n.process.pid??null,state:t.state,restartReason:t.restartReason??null,createdAt:t.createdAt,readyAt:t.readyAt??null,connected:n.isConnected(),dead:n.isDead(),exitedAfterDisconnect:n.exitedAfterDisconnect,lastPongAt:t.lastPongAt??null,lastRttMs:t.lastRttMs??null,stats:r===void 0?null:{at:r.at,uptimeSeconds:r.uptimeSeconds,cpu:r.cpu,memory:{...r.memory,rssMb:L(r.memory.rss),heapTotalMb:L(r.memory.heapTotal),heapUsedMb:L(r.memory.heapUsed),externalMb:L(r.memory.external),arrayBuffersMb:L(r.memory.arrayBuffers)}}}})}));let f=(t,n)=>{for(let e of a.values())if(e.state===`restarting`)return;if(l(t.slot)){e.logger.warn(`WorkerRecycleSuppressed`,{slot:t.slot,pid:t.pid,reason:n,windowMs:R,max:3});return}c(t.slot),t.state=`restarting`,t.restartReason=n,e.logger.warn(`WorkerRecycling`,{slot:t.slot,pid:t.pid,reason:n}),t.instance.kill()},p=(e,t)=>{let r=L(t.memory.rss);if(r>n.memoryUsageGreaterThan){f(e,`memoryUsageGreaterThan: rss ${r}MB > ${n.memoryUsageGreaterThan}MB`);return}let i=t.uptimeSeconds*1e3;i>n.uptimeGreaterThan&&f(e,`uptimeGreaterThan: ${Math.round(i/1e3)}s > ${Math.round(n.uptimeGreaterThan/1e3)}s`)},m=e=>{for(let t of a.values()){if(t.state!==`ready`||t.lastPongAt===void 0)continue;let r=e-t.lastPongAt;r>n.healthzTimeout&&f(t,`healthzTimeout: no pong for ${Math.round(r/1e3)}s > ${Math.round(n.healthzTimeout/1e3)}s`)}},h=e=>{g(u.default.fork({WORKER_ID:String(e)}),e)},g=(t,n)=>{let r={state:`creating`,pid:t.process.pid,slot:n,createdAt:Date.now(),instance:t};a.set(t.id,r),t.on(`message`,i=>{if(A(i)){if(i.type===202){let e=Date.now()-i.sentAt;r.pid=i.pid,r.lastPongAt=Date.now(),r.lastRttMs=e;return}if(i.type===201){r.state=`ready`,r.pid=i.pid,r.readyAt=Date.now(),e.logger.info(`WorkerReady`,{workerId:t.id,slot:n,pid:i.pid});return}if(i.type===200){r.state=`created`,r.pid=i.pid,e.logger.info(`WorkerCreated`,{workerId:t.id,slot:n,pid:i.pid});return}i.type===203&&(r.pid=i.pid,r.lastStats=i.stats,r.state===`ready`&&p(r,i.stats))}}),t.on(`exit`,(n,r)=>{let i=a.get(t.id);a.delete(t.id);let o=i?.slot,s=i?.state===`restarting`,u=i?.restartReason??null;if(e.logger.warn(`WorkerExited`,{workerId:t.id,slot:o??null,pid:t.process.pid??`unknown`,code:n,signal:r??`none`,expected:s,reason:u}),o!==void 0){if(s){h(o);return}if(c(o),l(o)){e.logger.error(`WorkerRespawnSuppressed`,{slot:o,windowMs:R,max:3});return}h(o)}})};for(let e=0;e<i;e++)h(e+1);setInterval(()=>{let e=Date.now();for(let t of a.values())if(t.instance.isConnected())try{ie(t.instance,{type:100,sentAt:e})}catch{}m(Date.now())},5e3).unref()}function B(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 V(e){let t=e.headersDistinct[`x-forwarded-for`];if(t){let e=t[0]?.split(`,`)[0]?.trim();if(e&&e.length>0)return e}let n=e.headersDistinct[`x-real-ip`]?.[0].trim();return n===void 0?e.socket.remoteAddress??`unknown`:n}function H(e){if(e===void 0)return!1;let t=e.toLowerCase();return t.startsWith(`text/`)||t.includes(`json`)||t.includes(`xml`)||t.includes(`x-www-form-urlencoded`)||t.includes(`javascript`)}function U(e){if(e!==void 0)try{return new URL(e,`http://fluxion.local`)}catch{return}}function W(e){let t={};for(let[n,r]of e.entries()){let e=t[n];if(e===void 0){t[n]=r;continue}if(Array.isArray(e)){e.push(r);continue}t[n]=[e,r]}return t}var G=class extends Error{errno;code;constructor(e,t,n){super(e),this.name=`HttpException`,this.errno=t,this.code=n}},le=class extends G{constructor(e=`Bad Request`){super(e,400,`BAD_REQUEST`)}},ue=class extends G{constructor(e=`Unauthorized`){super(e,401,`UNAUTHORIZED`)}},de=class extends G{constructor(e=`Forbidden`){super(e,403,`FORBIDDEN`)}},fe=class extends G{constructor(e=`Not Found`){super(e,404,`NOT_FOUND`)}},K=class extends G{constructor(e=`Method Not Allowed`){super(e,405,`METHOD_NOT_ALLOWED`)}},pe=class extends G{constructor(e=`Not Acceptable`){super(e,406,`NOT_ACCEPTABLE`)}},me=class extends G{constructor(e=`Request Timeout`){super(e,408,`REQUEST_TIMEOUT`)}},he=class extends G{constructor(e=`Conflict`){super(e,409,`CONFLICT`)}},ge=class extends G{constructor(e=`Gone`){super(e,410,`GONE`)}},q=class extends G{constructor(e=`Payload Too Large`){super(e,413,`PAYLOAD_TOO_LARGE`)}},_e=class extends G{constructor(e=`Unsupported Media Type`){super(e,415,`UNSUPPORTED_MEDIA_TYPE`)}},ve=class extends G{constructor(e=`Unprocessable Entity`){super(e,422,`UNPROCESSABLE_ENTITY`)}},ye=class extends G{constructor(e=`Too Many Requests`){super(e,429,`TOO_MANY_REQUESTS`)}},be=class extends G{constructor(e=`Internal Server Error`){super(e,500,`INTERNAL_SERVER_ERROR`)}},xe=class extends G{constructor(e=`Not Implemented`){super(e,501,`NOT_IMPLEMENTED`)}},Se=class extends G{constructor(e=`Bad Gateway`){super(e,502,`BAD_GATEWAY`)}},Ce=class extends G{constructor(e=`Service Unavailable`){super(e,503,`SERVICE_UNAVAILABLE`)}},we=class extends G{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 Te(e,t,n,r){return t===0?X():H(n)?{exists:!0,value:e.toString(`utf8`),bytes:t,truncated:r}:{exists:!0,value:`<binary body: ${t} bytes>`,bytes:t,truncated:r}}async function Ee(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);if(Number.isFinite(a)&&a>n)throw J(a,n);return new Promise((t,i)=>{let a=[],o=[],s=0,c=0,l=!1,u=!1,d=()=>{e.off(`data`,p),e.off(`end`,m),e.off(`error`,h),e.off(`aborted`,g)},f=e=>{u||(u=!0,e())},p=t=>{let u=Buffer.isBuffer(t)?t:Buffer.from(t);if(s+=u.byteLength,s>n){d(),e.resume(),f(()=>{i(J(s,n))});return}if(a.push(u),c<r){let e=r-c,t=u.subarray(0,e);o.push(t),c+=t.length,t.length<u.length&&(l=!0)}else l=!0},m=()=>{d(),f(()=>{let n=a.length>0?Buffer.concat(a):void 0;t({rawBody:n,preview:Te(o.length>0?Buffer.concat(o):Buffer.alloc(0),n?.byteLength??0,Y(e.headers[`content-type`]),l)})})},h=e=>{d(),f(()=>{i(e)})},g=()=>{d(),f(()=>{i(Error(`request aborted while reading body`))})};e.on(`data`,p),e.once(`end`,m),e.once(`error`,h),e.once(`aborted`,g)})}async function De(e,t,n){let{rawBody:r,preview:i}=await Ee(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}:H(a)?{body:{raw:r.toString(`utf8`)},preview:i}:{body:{},preview:i}}function Oe(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 ke(e){let t=async(t,n)=>{let r=t.method??`GET`,i=V(t),a=U(t.url);if(a===void 0){I(n,{message:`Bad Request: req.url is undefined`},400);return}let o={method:r,ip:i,url:a,query:W(a.searchParams),body:{},headers:t.headers,cookie:Oe(t.headers.cookie)},s={exists:!1,bytes:0,truncated:!1};e.logger.info(`Req`,{method:r,ip:i,path:a.pathname});let c=performance.now();n.once(`finish`,()=>{let t={workerId:process.env.WORKER_ID??`[primary]`,method:r,ip:i,path:a.pathname,status:n.statusCode,duration:(performance.now()-c).toFixed(4)};y(o.query).length>0&&(t.query=o.query),s.exists&&(t.body=s.value,t.bodyBytes=s.bytes,t.bodyTruncated=s.truncated),e.logger.info(`Res`,t)});try{if(o.url.pathname.startsWith(`/_fluxion/`)){I(n,{message:`Not Found`},404);return}let r=await De(t,o.method,e.options.maxRequestBytes);o.body=r.body,s=r.preview;let i=await e.router.getModule(a);if(!i){I(n,{message:`Not Found`},404);return}if(t.method&&i.methods&&!i.methods.includes(t.method)){I(n,{message:`Method Not Allowed`},405);return}let c=i.type===0?i.handlerTimeoutMs??e.options.handlerTimeoutMs:e.options.staticResourceTimeoutMs;if(i.middlewares)for(let r=0;r<i.middlewares.length;r++){if(await Z(B(i.middlewares[r],o,t,n),e.options.middlewareTimeoutMs,P)===P){e.logger.warn(`MiddlewareTimeout`,{method:o.method,ip:o.ip}),I(n,{message:`Internal Server Error`},500);return}if(n.writableEnded)return;if(n.headersSent){n.end();return}}let l=await Z(B(i.handler,o,t,n),c,N);if(l===N){e.logger.warn(`HandlerTimeout`,{method:o.method,ip:o.ip}),I(n,{message:`Handler timed out`},500);return}l!==M&&I(n,l)}catch(t){t instanceof G?(e.logger.error(`RequestFailed`,{method:o.method,ip:o.ip,path:o.url.pathname,error:t.message}),I(n,{message:t.message},t.errno)):(e.logger.error(`RequestFailed`,{method:o.method,ip:o.ip,path:o.url.pathname,error:E(t)}),I(n,{message:E(t)},t.errno??500))}},n=e.options.https?p.default.createServer({key:e.options.https.key,cert:e.options.https.cert,ca:e.options.https.ca},t):f.default.createServer(t);return n.on(`close`,()=>{e.logger.info(`ServerClosed`,{host:e.options.host,port:e.options.port})}),n.listen(e.options.port,e.options.host,()=>{e.logger.info(`ServerStarted`,{pid:process.pid,protocol:e.options.https?`https`:`http`,host:e.options.host,port:e.options.port}),e.logger.info(`DynamicDirectory`,{directory:e.options.dir})}),n.on(`error`,t=>{e.logger.error(`ServerError`,{error:E(t)})}),n}const Ae=()=>{let e=process.cpuUsage(),t=Date.now();setInterval(()=>{let n=Date.now(),r=Math.max(1,(n-t)*1e3),i=process.cpuUsage(e),a=Number(((i.user+i.system)/r*100).toFixed(2));e=process.cpuUsage(),t=n;let o=process.memoryUsage();j({type:203,pid:process.pid,stats:{at:n,pid:process.pid,uptimeSeconds:Number(process.uptime().toFixed(3)),cpu:{userMicros:i.user,systemMicros:i.system,percent:a},memory:{rss:o.rss,heapTotal:o.heapTotal,heapUsed:o.heapUsed,external:o.external,arrayBuffers:o.arrayBuffers}}})},2e3).unref()};function je(e){if(u.default.isPrimary)throw Error(`[fluxion error] createWorker should only be called in worker process`);process.on(`message`,e=>{if(k(e)&&e.type===100){j({type:202,pid:process.pid,sentAt:e.sentAt,receivedAt:Date.now()});return}}),j({type:200,pid:process.pid}),Ae();try{ke(e),j({type:201,pid:process.pid})}catch(t){e.logger.error(`WorkerBootstrapFailed`,{pid:process.pid,error:E(t)}),process.exit(1)}}var Q=class{cx;timer=null;filesChanged=new Map;constructor(e){this.cx=e}async init(){let e=this.cx.options.dir;if(!c.default.existsSync(e))return this.cx.logger.warn(`Directory does not exist: ${e}`),this;let t=[],n=(e,r)=>{let i=c.default.readdirSync(e,{withFileTypes:!0});for(let a=0;a<i.length;a++){let o=i[a],s=l.default.join(e,o.name),c=l.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()}},Me=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=m.default.watch(e,{persistent:!0,ignoreInitial:!0,usePolling:!1,awaitWriteFinish:{stabilityThreshold:100,pollInterval:50}}).on(`all`,(t,n)=>{n&&this.queueUp(n,l.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}},Ne=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.default.watch(e,{recursive:!0},(t,n)=>{n&&this.queueUp(l.default.join(e,n),n)}).on(`error`,e=>{this.cx.logger.error(`Watcher error: ${e.message}`),this.cx.logger.error(`Restarting watcher...`),this.start()}),this.cx.logger.info(`Watcher started on directory: ${e}`),this}stop(){return this.watcher&&=(this.watcher.close(),null),this.stopCore(),this}};function $(e,t){if(typeof t!=`object`||!t)return!1;if((0,g.static_cast)(t),typeof t.handler!=`function`)return e.logger.error(`handler must be a function`),!1;if(t.disposer!==void 0&&typeof t.disposer!=`function`)return e.logger.error(`disposer must be a function if provided`),!1;let n=t.handlerTimeoutMs;return n!==void 0&&(!Number.isSafeInteger(n)||n<100)?(e.logger.error(`handlerTimeoutMs must be an integer >= 100 if provided`),!1):t.type===0?!0:(e.logger.error(`You must use defineFluxionModule to create module`),!1)}function Pe(e,t){delete require.cache[t];let n=require(t);if(!$(e,n))if($(e,n.default))n=n.default;else throw Error(`[fluxion error] Invalid handler module '${t}', make sure it satisfies defineFluxionModule(...) helper`);return n}var Fe=class{cx;handlers=new Map;constructor(e){this.cx=e}makeStaticResource(e){return{type:1,handler:async(t,n,r)=>{if(t.method!==`GET`&&t.method!==`HEAD`){r.statusCode=405,r.setHeader(`Allow`,`GET, HEAD`),r.end();return}if(!c.default.existsSync(e)){r.statusCode=404,r.end(`Not Found`);return}let i=c.default.statSync(e);if(!i.isFile()){r.statusCode=404,r.end(`Not Found`);return}let a=ae[l.default.extname(e).toLowerCase()]??`application/octet-stream`;if(r.statusCode=200,r.setHeader(`Content-Type`,a),r.setHeader(`Content-Length`,String(i.size)),t.method===`HEAD`){r.end();return}return new Promise((t,n)=>{let i=c.default.createReadStream(e);i.on(`error`,n),i.on(`end`,()=>t(M)),i.pipe(r)})}}}async register(e,t){let n=this.handlers.get(t)?.disposer;if(n&&await B(n),!c.default.existsSync(e)){this.handlers.delete(t),this.cx.logger.info(`${x.red}Deleted ${x.reset} - ${t}`);return}if(!this.cx.options.include.some(e=>(0,h.minimatch)(t,e))){this.handlers.delete(t),this.cx.logger.info(`${x.yellow}Skipped ${x.reset} - ${t}`);return}if(this.cx.options.exclude.some(e=>(0,h.minimatch)(t,e))){this.handlers.delete(t),this.cx.logger.info(`${x.orange}Excluded${x.reset} - ${t}`);return}if(this.cx.options.apiInclude.some(e=>(0,h.minimatch)(t,e))){let n=Pe(this.cx,e);this.handlers.set(t,n),this.cx.logger.info(`${x.green}Api ${x.reset} - ${t}`);return}this.handlers.set(t,this.makeStaticResource(t)),this.cx.logger.info(`${x.brightBlue}Static ${x.reset} - ${t}`)}getModule(e){let t=e.pathname.replace(/^[/]+/,``).replace(/[/]+$/,``);return this.handlers.get(t)}remove(e){this.handlers.has(e)&&(this.handlers.delete(e),this.cx.logger.info(`${x.red}Deleted ${x.reset} - ${e}`));let t=e.endsWith(`/`)?e:e+`/`;for(let e of this.handlers.keys())e.startsWith(t)&&(this.handlers.delete(e),this.cx.logger.info(`${x.red}Deleted ${x.reset} - ${e}`))}};async function Ie(e){let t={options:re(e)};t.logger=w(t),t.router=new Fe(t),u.default.isPrimary?z(t):(t.logger=T(t.logger,process.pid),t.watcher=await new(t.options.nativeWatcher?Ne:Me)(t).start(),je(t))}function Le(e,t=se){if(typeof e==`function`){if(typeof t!=`function`)throw Error(`[fluxion error] Invalid disposer, expected a function but got ${typeof t}`);return{handler:e,disposer:t,type:0}}if(typeof e!=`object`||!e)throw Error(`[fluxion error] Invalid argument, expected a FluxionModule object or a handler function, but got ${typeof e}`);if(typeof e.handler!=`function`)throw Error(`[fluxion error] Invalid FluxionModule, "handler" must be a function`);if(e.disposer!==void 0&&typeof e.disposer!=`function`)throw Error(`[fluxion error] Invalid FluxionModule, "disposer" must be a function if provided`);if(e.methods!==void 0&&(!Array.isArray(e.methods)||e.methods.some(e=>typeof e!=`string`)))throw Error(`[fluxion error] Invalid FluxionModule, "methods" must be an array of strings if provided`);if(e.middlewares!==void 0&&(!Array.isArray(e.middlewares)||e.middlewares.some(e=>typeof e!=`function`)))throw Error(`[fluxion error] Invalid FluxionModule, "middlewares" must be an array of functions if provided`);return{...e,type:0}}function Re(e){if(typeof e!=`function`)throw Error(`[fluxion error] Invalid FluxionMiddleware, expected a function but got ${typeof e}`);return e}exports.BadGatewayException=Se,exports.BadRequestException=le,exports.ConflictException=he,exports.ForbiddenException=de,exports.GatewayTimeoutException=we,exports.GoneException=ge,exports.HttpCode=oe,exports.HttpException=G,exports.InternalServerErrorException=be,exports.MethodNotAllowedException=K,exports.NotAcceptableException=pe,exports.NotFoundException=fe,exports.NotImplementedException=xe,exports.PayloadTooLargeException=q,exports.RequestTimeoutException=me,exports.ServiceUnavailableException=Ce,exports.TooManyRequestsException=ye,exports.UnauthorizedException=ue,exports.UnprocessableEntityException=ve,exports.UnsupportedMediaTypeException=_e,exports.defineFluxionMiddleware=Re,exports.defineFluxionModule=Le,exports.fluxion=Ie;
|
|
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:fs");c=s(c);let l=require("node:path");l=s(l);let u=require("node:cluster");u=s(u);let d=require("node:os");d=s(d);let f=require("node:http");f=s(f);let p=require("node:https");p=s(p);let m=require("chokidar");m=s(m);let h=require("minimatch"),g=require("type-narrow");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=JSON.stringify,y=Object.keys,b=process.env.FLUXION_COLORS!==`0`;let x;(function(e){e.reset=b?`\x1B[0m`:``,e.bold=b?`\x1B[1m`:``,e.dim=b?`\x1B[2m`:``,e.italic=b?`\x1B[3m`:``,e.underline=b?`\x1B[4m`:``,e.blink=b?`\x1B[5m`:``,e.inverse=b?`\x1B[7m`:``,e.black=b?`\x1B[30m`:``,e.red=b?`\x1B[31m`:``,e.green=b?`\x1B[32m`:``,e.yellow=b?`\x1B[33m`:``,e.blue=b?`\x1B[34m`:``,e.magenta=b?`\x1B[35m`:``,e.cyan=b?`\x1B[36m`:``,e.white=b?`\x1B[37m`:``,e.brightBlack=b?`\x1B[90m`:``,e.brightRed=b?`\x1B[91m`:``,e.brightGreen=b?`\x1B[92m`:``,e.brightYellow=b?`\x1B[93m`:``,e.brightBlue=b?`\x1B[94m`:``,e.brightMagenta=b?`\x1B[95m`:``,e.brightCyan=b?`\x1B[96m`:``,e.brightWhite=b?`\x1B[97m`:``,e.bgBlack=b?`\x1B[40m`:``,e.bgRed=b?`\x1B[41m`:``,e.bgGreen=b?`\x1B[42m`:``,e.bgYellow=b?`\x1B[43m`:``,e.bgBlue=b?`\x1B[44m`:``,e.bgMagenta=b?`\x1B[45m`:``,e.bgCyan=b?`\x1B[46m`:``,e.bgWhite=b?`\x1B[47m`:``,e.bgBrightBlack=b?`\x1B[100m`:``,e.bgBrightRed=b?`\x1B[101m`:``,e.bgBrightGreen=b?`\x1B[102m`:``,e.bgBrightYellow=b?`\x1B[103m`:``,e.bgBrightBlue=b?`\x1B[104m`:``,e.bgBrightMagenta=b?`\x1B[105m`:``,e.bgBrightCyan=b?`\x1B[106m`:``,e.bgBrightWhite=b?`\x1B[107m`:``,e.purple=b?`\x1B[38;2;225;16;248m`:``,e.orange=b?`\x1B[38;2;248;147;16m`:``,e.darkGreen=b?`\x1B[38;2;22;101;52m`:``,e.claude=b?`\x1B[38;2;217;119;87m`:``,e.deepseek=b?`\x1B[38;2;57;100;254m`:``,e.gpt=b?`\x1B[38;2;41;60;77m`:``})(x||={});const S=e=>{try{return v(e)}catch{return`[unserializable]`}},ee={INFO:`${x.cyan}INFO${x.reset}`,WARN:`${x.orange}WARN${x.reset}`,ERROR:`${x.red}ERROR${x.reset}`,SUCC:`${x.green}SUCC${x.reset}`,DEBUG:`${x.blue}DEBUG${x.reset}`,VERBOSE:`${x.purple}VERBOSE${x.reset}`},te=e=>{let{level:t,timestamp:n,message:r,...i}=e,a=`${x.darkGreen}[${n}]${x.reset}`,o=ee[t]??t,s=r,c=y(i).length>0?`${x.dim}${S(i)}${x.reset}`:``;console.log(`${a} ${o} ${s}${c}`)};function C(e){let t=e.options.logger;return t===void 0||t===`one-line`?te:t===`json-line`?e=>console.log(S(e)):t}function ne(e){let t=C(e);return{write(e,n,r={}){let i={...r,timestamp:_(),level:e,message:n};try{t(i)}catch{}},info(e,t){this.write(`INFO`,e,t)},warn(e,t){this.write(`WARN`,e,t)},error(e,t){this.write(`ERROR`,e,t)},succ(e,t){this.write(`SUCC`,e,t)},debug(e,t){this.write(`DEBUG`,e,t)},verbose(e,t){this.write(`VERBOSE`,e,t)}}}function re(e,t){let n=`[${t}]`;return{write(t,r,i){e.write(t,`${n} ${r}`,i)},info(t,r){e.info(`${n} ${t}`,r)},warn(t,r){e.warn(`${n} ${t}`,r)},error(t,r){e.error(`${n} ${t}`,r)},succ(t,r){e.succ(`${n} ${t}`,r)},debug(t,r){e.debug(`${n} ${t}`,r)},verbose(t,r){e.verbose(`${n} ${t}`,r)}}}const w=typeof Error.isError==`function`?e=>Error.isError(e)?e.message:String(e):e=>e?.message||String(e);function ie(e={}){let t=e.restartWhen??{},n=t.healthzTimeout??3e4;if(n!==1/0&&(!Number.isFinite(n)||n<1e4))throw Error(`[fluxion error] workerOptions.restartWhen.healthzTimeout must be a finite number >= 10000 (ms) or Infinity`);return{maxWorkerCount:e.maxWorkerCount??4,restartWhen:{memoryUsageGreaterThan:t.memoryUsageGreaterThan??1/0,healthzTimeout:n,uptimeGreaterThan:t.uptimeGreaterThan??1/0}}}function T(e,t){if(Buffer.isBuffer(e))return e;if(typeof e==`string`){if(!e.startsWith(`-----BEGIN`)){let n=l.default.isAbsolute(e)?e:l.default.join(t,e);if(c.default.existsSync(n))return c.default.readFileSync(n)}return Buffer.from(e)}throw Error(`[fluxion error] Certificate content must be a string or Buffer`)}function ae(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 E(e){if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`[fluxion error] FluxionOptions must be an object`);let{dir:t=l.default.isAbsolute(e.dir)?e.dir:l.default.join(process.cwd(),e.dir),host:n,port:r,handlerTimeoutMs:i=5e3,middlewareTimeoutMs:a=3e3,staticResourceTimeoutMs:o=10*6e5,metaPort:s=r+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}=e,y=e.logger??`one-line`;if(y!==`one-line`&&y!==`json-line`&&typeof y!=`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`);if(typeof u!=`string`)throw Error(`[fluxion error] FluxionOptions.moduleDir must be a string`);if(typeof n!=`string`)throw Error(`[fluxion error] FluxionOptions.host must be a string`);if(!Number.isSafeInteger(i)||i<=100)throw Error(`[fluxion error] FluxionOptions.handlerTimeoutMs must be an integer greater than 100`);if(!Number.isSafeInteger(a)||a<=100)throw Error(`[fluxion error] FluxionOptions.middlewareTimeoutMs must be an integer greater than 100`);if(typeof p!=`number`||p<=0||!Number.isSafeInteger(p))throw Error(`[fluxion error] FluxionOptions.reloadDelay must be a positive integer`);if(p<50)throw Error(`[fluxion error] FluxionOptions.reloadDelay must be greater than or equal to 50`);if(typeof r!=`number`||!Number.isSafeInteger(r))throw Error(`[fluxion error] FluxionOptions.port must be a positive integer`);if(r<=1||r>65535)throw Error(`[fluxion error] FluxionOptions.port must be 1 ~ 65535`);if(typeof s!=`number`||!Number.isSafeInteger(s))throw Error(`[fluxion error] FluxionOptions.metaPort must be a positive integer`);if(s<=1||s>65535)throw Error(`[fluxion error] FluxionOptions.metaPort must be 1 ~ 65535`);if(s===r)throw Error(`[fluxion error] FluxionOptions.metaPort must be different from FluxionOptions.port`);if(typeof d!=`object`||!d||Array.isArray(d))throw Error(`[fluxion error] FluxionOptions.workerOptions must be an object`);if(typeof f!=`number`||f<=0||!Number.isSafeInteger(f))throw Error(`[fluxion error] FluxionOptions.maxRequestBytes must be a positive integer`);return c.default.existsSync(t)||c.default.mkdirSync(t,{recursive:!0}),{dir:t,host:n,port:r,handlerTimeoutMs:i,middlewareTimeoutMs:a,staticResourceTimeoutMs:o,reloadDelay:p,metaPort:s,moduleDir:u,workerOptions:ie(d),maxRequestBytes:f,logger:y,include:m,apiInclude:h,exclude:g,nativeWatcher:v,https:ae(_,u)}}const D=e=>[100].includes(e?.type),O=e=>[202,200,201,203].includes(e?.type),k=e=>process.send?.(e),A=(e,t)=>e.send(t),j=Symbol.for(`fluxion.router.StaticHandled`),M=Symbol.for(`fluxion.handlerTimeout`),N=Symbol.for(`fluxion.middlewareTimeout`),oe={".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 se=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 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 ce(e,t){let n=f.default.createServer((e,n)=>{let r=e.method??`GET`,i=`/`;try{i=new URL(e.url??`/`,`http://fluxion.local`).pathname}catch{P(n,{message:`Bad Request: invalid url`},400);return}if(r===`GET`&&i===`/_fluxion/healthz`){P(n,{ok:!0,role:`primary`,pid:process.pid,now:Date.now(),uptimeSeconds:Number(process.uptime().toFixed(3))});return}if(r===`GET`&&i===`/_fluxion/workers`){P(n,{ok:!0,now:Date.now(),workers:t()});return}P(n,{message:`Not Found`},404)});return n.on(`listening`,()=>{e.logger.info(`MetaApiStarted`,{pid:process.pid,host:e.options.host,port:e.options.metaPort,prefix:`/_fluxion`})}),n.on(`error`,t=>{e.logger.error(`MetaApiError`,{host:e.options.host,port:e.options.metaPort,error:w(t)}),process.exit(1)}),n.listen(e.options.metaPort,e.options.host),n}const I=e=>Number((e/1024/1024).toFixed(2)),L=6e4;function R(e){if(!u.default.isPrimary)throw Error(`[fluxion error] createPrimary should only be called in primary process`);let{workerOptions:t}=e.options,n=t.restartWhen,r=Math.max(1,d.default.cpus().length),i=Math.max(1,Math.min(t.maxWorkerCount??Math.min(2,r),r));e.logger.info(`PrimaryStarted`,{pid:process.pid,workers:i,host:e.options.host,port:e.options.port,metaPort:e.options.metaPort});let a=new Map,o=new Map,s=e=>{let t=Date.now(),n=(o.get(e)??[]).filter(e=>t-e<L);return o.set(e,n),n.length},c=e=>{let t=Date.now(),n=(o.get(e)??[]).filter(e=>t-e<L);n.push(t),o.set(e,n)},l=e=>s(e)>=3;ce(e,()=>({primaryPid:process.pid,host:e.options.host,port:e.options.port,metaPort:e.options.metaPort,uptimeSeconds:Number(process.uptime().toFixed(3)),workers:Array.from(a.entries()).map(([e,t])=>{let{instance:n}=t,r=t.lastStats;return{workerId:e,slot:t.slot,pid:t.pid??n.process.pid??null,state:t.state,restartReason:t.restartReason??null,createdAt:t.createdAt,readyAt:t.readyAt??null,connected:n.isConnected(),dead:n.isDead(),exitedAfterDisconnect:n.exitedAfterDisconnect,lastPongAt:t.lastPongAt??null,lastRttMs:t.lastRttMs??null,stats:r===void 0?null:{at:r.at,uptimeSeconds:r.uptimeSeconds,cpu:r.cpu,memory:{...r.memory,rssMb:I(r.memory.rss),heapTotalMb:I(r.memory.heapTotal),heapUsedMb:I(r.memory.heapUsed),externalMb:I(r.memory.external),arrayBuffersMb:I(r.memory.arrayBuffers)}}}})}));let f=(t,n)=>{for(let e of a.values())if(e.state===`restarting`)return;if(l(t.slot)){e.logger.warn(`WorkerRecycleSuppressed`,{slot:t.slot,pid:t.pid,reason:n,windowMs:L,max:3});return}c(t.slot),t.state=`restarting`,t.restartReason=n,e.logger.warn(`WorkerRecycling`,{slot:t.slot,pid:t.pid,reason:n}),t.instance.kill()},p=(e,t)=>{let r=I(t.memory.rss);if(r>n.memoryUsageGreaterThan){f(e,`memoryUsageGreaterThan: rss ${r}MB > ${n.memoryUsageGreaterThan}MB`);return}let i=t.uptimeSeconds*1e3;i>n.uptimeGreaterThan&&f(e,`uptimeGreaterThan: ${Math.round(i/1e3)}s > ${Math.round(n.uptimeGreaterThan/1e3)}s`)},m=e=>{for(let t of a.values()){if(t.state!==`ready`||t.lastPongAt===void 0)continue;let r=e-t.lastPongAt;r>n.healthzTimeout&&f(t,`healthzTimeout: no pong for ${Math.round(r/1e3)}s > ${Math.round(n.healthzTimeout/1e3)}s`)}},h=e=>{g(u.default.fork({WORKER_ID:String(e)}),e)},g=(t,n)=>{let r={state:`creating`,pid:t.process.pid,slot:n,createdAt:Date.now(),instance:t};a.set(t.id,r),t.on(`message`,i=>{if(O(i)){if(i.type===202){let e=Date.now()-i.sentAt;r.pid=i.pid,r.lastPongAt=Date.now(),r.lastRttMs=e;return}if(i.type===201){r.state=`ready`,r.pid=i.pid,r.readyAt=Date.now(),e.logger.info(`WorkerReady`,{workerId:t.id,slot:n,pid:i.pid});return}if(i.type===200){r.state=`created`,r.pid=i.pid,e.logger.info(`WorkerCreated`,{workerId:t.id,slot:n,pid:i.pid});return}i.type===203&&(r.pid=i.pid,r.lastStats=i.stats,r.state===`ready`&&p(r,i.stats))}}),t.on(`exit`,(n,r)=>{let i=a.get(t.id);a.delete(t.id);let o=i?.slot,s=i?.state===`restarting`,u=i?.restartReason??null;if(e.logger.warn(`WorkerExited`,{workerId:t.id,slot:o??null,pid:t.process.pid??`unknown`,code:n,signal:r??`none`,expected:s,reason:u}),o!==void 0){if(s){h(o);return}if(c(o),l(o)){e.logger.error(`WorkerRespawnSuppressed`,{slot:o,windowMs:L,max:3});return}h(o)}})};for(let e=0;e<i;e++)h(e+1);setInterval(()=>{let e=Date.now();for(let t of a.values())if(t.instance.isConnected())try{A(t.instance,{type:100,sentAt:e})}catch{}m(Date.now())},5e3).unref()}function z(e,...t){return new Promise((n,r)=>{try{let i=e(...t);i instanceof Promise?i.then(n).catch(r):n(i)}catch(e){r(e)}})}function B(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 V(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 H(e){if(e!==void 0)try{return new URL(e,`http://fluxion.local`)}catch{return}}function U(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 W=class extends Error{errno;code;constructor(e,t,n){super(e),this.name=`HttpException`,this.errno=t,this.code=n}},G=class extends W{constructor(e=`Bad Request`){super(e,400,`BAD_REQUEST`)}},le=class extends W{constructor(e=`Unauthorized`){super(e,401,`UNAUTHORIZED`)}},ue=class extends W{constructor(e=`Forbidden`){super(e,403,`FORBIDDEN`)}},de=class extends W{constructor(e=`Not Found`){super(e,404,`NOT_FOUND`)}},fe=class extends W{constructor(e=`Method Not Allowed`){super(e,405,`METHOD_NOT_ALLOWED`)}},pe=class extends W{constructor(e=`Not Acceptable`){super(e,406,`NOT_ACCEPTABLE`)}},me=class extends W{constructor(e=`Request Timeout`){super(e,408,`REQUEST_TIMEOUT`)}},he=class extends W{constructor(e=`Conflict`){super(e,409,`CONFLICT`)}},ge=class extends W{constructor(e=`Gone`){super(e,410,`GONE`)}},K=class extends W{constructor(e=`Payload Too Large`){super(e,413,`PAYLOAD_TOO_LARGE`)}},_e=class extends W{constructor(e=`Unsupported Media Type`){super(e,415,`UNSUPPORTED_MEDIA_TYPE`)}},ve=class extends W{constructor(e=`Unprocessable Entity`){super(e,422,`UNPROCESSABLE_ENTITY`)}},ye=class extends W{constructor(e=`Too Many Requests`){super(e,429,`TOO_MANY_REQUESTS`)}},be=class extends W{constructor(e=`Internal Server Error`){super(e,500,`INTERNAL_SERVER_ERROR`)}},xe=class extends W{constructor(e=`Not Implemented`){super(e,501,`NOT_IMPLEMENTED`)}},Se=class extends W{constructor(e=`Bad Gateway`){super(e,502,`BAD_GATEWAY`)}},Ce=class extends W{constructor(e=`Service Unavailable`){super(e,503,`SERVICE_UNAVAILABLE`)}},we=class extends W{constructor(e=`Gateway Timeout`){super(e,504,`GATEWAY_TIMEOUT`)}};function q(e,t){return new K(`request body too large: ${e.toString()} bytes exceeds ${t.toString()} bytes`)}function J(e){return Array.isArray(e)?e[0]:e}function Y(){return{exists:!1,bytes:0,truncated:!1}}function Te(e,t,n,r){return t===0?Y():V(n)?{exists:!0,value:e.toString(`utf8`),bytes:t,truncated:r}:{exists:!0,value:`<binary body: ${t} bytes>`,bytes:t,truncated:r}}async function Ee(e,t,n,r=8192){if(t===`GET`||t===`HEAD`||e.readableEnded)return{rawBody:void 0,preview:Y()};let i=J(e.headers[`content-length`]),a=i===void 0?NaN:Number.parseInt(i,10);if(Number.isFinite(a)&&a>n)throw q(a,n);return new Promise((t,i)=>{let a=[],o=[],s=0,c=0,l=!1,u=!1,d=()=>{e.off(`data`,p),e.off(`end`,m),e.off(`error`,h),e.off(`aborted`,g)},f=e=>{u||(u=!0,e())},p=t=>{let u=Buffer.isBuffer(t)?t:Buffer.from(t);if(s+=u.byteLength,s>n){d(),e.resume(),f(()=>{i(q(s,n))});return}if(a.push(u),c<r){let e=r-c,t=u.subarray(0,e);o.push(t),c+=t.length,t.length<u.length&&(l=!0)}else l=!0},m=()=>{d(),f(()=>{let n=a.length>0?Buffer.concat(a):void 0;t({rawBody:n,preview:Te(o.length>0?Buffer.concat(o):Buffer.alloc(0),n?.byteLength??0,J(e.headers[`content-type`]),l)})})},h=e=>{d(),f(()=>{i(e)})},g=()=>{d(),f(()=>{i(Error(`request aborted while reading body`))})};e.on(`data`,p),e.once(`end`,m),e.once(`error`,h),e.once(`aborted`,g)})}async function De(e,t,n){let{rawBody:r,preview:i}=await Ee(e,t,n);if(r===void 0||r.byteLength===0)return{body:{},preview:i};let a=J(e.headers[`content-type`])?.toLowerCase()??``;if(a.includes(`json`)){let e=r.toString(`utf8`).trim();if(e.length===0)return{body:{},preview:i};try{let t=JSON.parse(e);return typeof t==`object`&&t&&!Array.isArray(t)?{body:t,preview:i}:{body:{value:t},preview:i}}catch{return{body:{raw:e},preview:i}}}return a.includes(`x-www-form-urlencoded`)?{body:U(new URLSearchParams(r.toString(`utf8`))),preview:i}:V(a)?{body:{raw:r.toString(`utf8`)},preview:i}:{body:{},preview:i}}function Oe(e){if(!e)return{};let t={},n=e.split(`;`);for(let e of n){let[n,...r]=e.split(`=`);if(!n)continue;let i=n.trim(),a=r.join(`=`).trim();t[i]=decodeURIComponent(a)}return t}const X=(e,t,n)=>Promise.race([e,new Promise(e=>setTimeout(()=>e(n),t))]);function ke(e){let t=Object.freeze({logger:e.logger}),n=async(n,r)=>{let i=n.method??`GET`,a=B(n),o=H(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:U(o.searchParams),body:{},headers:n.headers,cookie:Oe(n.headers.cookie),meta:{}},c={exists:!1,bytes:0,truncated:!1};e.logger.info(`Req`,{method:i,ip:a,path:o.pathname});let l=performance.now();r.once(`finish`,()=>{let t={workerId:process.env.WORKER_ID??`[primary]`,method:i,ip:a,path:o.pathname,status:r.statusCode,duration:(performance.now()-l).toFixed(4)};y(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(`Res`,t)});try{if(s.url.pathname.startsWith(`/_fluxion/`)){F(r,{message:`Not Found`},404);return}let i=await De(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 X(z(a.middlewares[i],s,t,n,r),e.options.middlewareTimeoutMs,N)===N){e.logger.warn(`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 X(z(a.handler,s,t,n,r),l,M);if(u===M){e.logger.warn(`HandlerTimeout`,{method:s.method,ip:s.ip}),F(r,{message:`Handler timed out`},500);return}u!==j&&F(r,u)}catch(t){t instanceof W?(e.logger.error(`RequestFailed`,{method:s.method,ip:s.ip,path:s.url.pathname,error:t.message}),F(r,{message:t.message},t.errno)):(e.logger.error(`RequestFailed`,{method:s.method,ip:s.ip,path:s.url.pathname,error:w(t)}),F(r,{message:w(t)},t.errno??500))}},r=e.options.https?p.default.createServer({key:e.options.https.key,cert:e.options.https.cert,ca:e.options.https.ca},n):f.default.createServer(n);return r.on(`close`,()=>{e.logger.info(`ServerClosed`,{host:e.options.host,port:e.options.port})}),r.listen(e.options.port,e.options.host,()=>{e.logger.info(`ServerStarted`,{pid:process.pid,protocol:e.options.https?`https`:`http`,host:e.options.host,port:e.options.port}),e.logger.info(`DynamicDirectory`,{directory:e.options.dir})}),r.on(`error`,t=>{e.logger.error(`ServerError`,{error:w(t)})}),r}const Z=()=>{let e=process.cpuUsage(),t=Date.now();setInterval(()=>{let n=Date.now(),r=Math.max(1,(n-t)*1e3),i=process.cpuUsage(e),a=Number(((i.user+i.system)/r*100).toFixed(2));e=process.cpuUsage(),t=n;let o=process.memoryUsage();k({type:203,pid:process.pid,stats:{at:n,pid:process.pid,uptimeSeconds:Number(process.uptime().toFixed(3)),cpu:{userMicros:i.user,systemMicros:i.system,percent:a},memory:{rss:o.rss,heapTotal:o.heapTotal,heapUsed:o.heapUsed,external:o.external,arrayBuffers:o.arrayBuffers}}})},2e3).unref()};function Ae(e){if(u.default.isPrimary)throw Error(`[fluxion error] createWorker should only be called in worker process`);process.on(`message`,e=>{if(D(e)&&e.type===100){k({type:202,pid:process.pid,sentAt:e.sentAt,receivedAt:Date.now()});return}}),k({type:200,pid:process.pid}),Z();try{ke(e),k({type:201,pid:process.pid})}catch(t){e.logger.error(`WorkerBootstrapFailed`,{pid:process.pid,error:w(t)}),process.exit(1)}}var Q=class{cx;timer=null;filesChanged=new Map;constructor(e){this.cx=e}async init(){let e=this.cx.options.dir;if(!c.default.existsSync(e))return this.cx.logger.warn(`Directory does not exist: ${e}`),this;let t=[],n=(e,r)=>{let i=c.default.readdirSync(e,{withFileTypes:!0});for(let a=0;a<i.length;a++){let o=i[a],s=l.default.join(e,o.name),c=l.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()}},je=class extends Q{watcher=null;constructor(e){super(e)}async start(){this.stop(),await this.init();let e=this.cx.options.dir;return this.watcher=m.default.watch(e,{persistent:!0,ignoreInitial:!0,usePolling:!1,awaitWriteFinish:{stabilityThreshold:100,pollInterval:50}}).on(`all`,(t,n)=>{n&&this.queueUp(n,l.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}},Me=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.default.watch(e,{recursive:!0},(t,n)=>{n&&this.queueUp(l.default.join(e,n),n)}).on(`error`,e=>{this.cx.logger.error(`Watcher error: ${e.message}`),this.cx.logger.error(`Restarting watcher...`),this.start()}),this.cx.logger.info(`Watcher started on directory: ${e}`),this}stop(){return this.watcher&&=(this.watcher.close(),null),this.stopCore(),this}};function $(e,t){if(typeof t!=`object`||!t)return!1;if((0,g.static_cast)(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 require.cache[t];let n=require(t);if(!$(e,n))if($(e,n.default))n=n.default;else 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,r)=>{if(t.method!==`GET`&&t.method!==`HEAD`){r.statusCode=405,r.setHeader(`Allow`,`GET, HEAD`),r.end();return}if(!c.default.existsSync(e)){r.statusCode=404,r.end(`Not Found`);return}let i=c.default.statSync(e);if(!i.isFile()){r.statusCode=404,r.end(`Not Found`);return}let a=oe[l.default.extname(e).toLowerCase()]??`application/octet-stream`;if(r.statusCode=200,r.setHeader(`Content-Type`,a),r.setHeader(`Content-Length`,String(i.size)),t.method===`HEAD`){r.end();return}return new Promise((t,n)=>{let i=c.default.createReadStream(e);i.on(`error`,n),i.on(`end`,()=>t(j)),i.pipe(r)})}}}async register(e,t){let n=this.handlers.get(t)?.disposer;if(n&&await z(n),!c.default.existsSync(e)){this.handlers.delete(t),this.cx.logger.info(`${x.red}Deleted ${x.reset} - ${t}`);return}if(!this.cx.options.include.some(e=>(0,h.minimatch)(t,e))){this.handlers.delete(t),this.cx.logger.info(`${x.yellow}Skipped ${x.reset} - ${t}`);return}if(this.cx.options.exclude.some(e=>(0,h.minimatch)(t,e))){this.handlers.delete(t),this.cx.logger.info(`${x.orange}Excluded${x.reset} - ${t}`);return}if(this.cx.options.apiInclude.some(e=>(0,h.minimatch)(t,e))){let n=Ne(this.cx,e);this.handlers.set(t,n),this.cx.logger.info(`${x.green}Api ${x.reset} - ${t}`);return}this.handlers.set(t,this.makeStaticResource(t)),this.cx.logger.info(`${x.brightBlue}Static ${x.reset} - ${t}`)}getModule(e){let t=e.pathname.replace(/^[/]+/,``).replace(/[/]+$/,``);return this.handlers.get(t)}remove(e){this.handlers.has(e)&&(this.handlers.delete(e),this.cx.logger.info(`${x.red}Deleted ${x.reset} - ${e}`));let t=e.endsWith(`/`)?e:e+`/`;for(let e of this.handlers.keys())e.startsWith(t)&&(this.handlers.delete(e),this.cx.logger.info(`${x.red}Deleted ${x.reset} - ${e}`))}};async function Fe(e){let t={options:E(e)};t.logger=ne(t),t.router=new Pe(t),u.default.isPrimary?R(t):(t.logger=re(t.logger,process.pid),t.watcher=await new(t.options.nativeWatcher?Me:je)(t).start(),Ae(t))}function Ie(e,t){if(typeof e==`function`){if(typeof t!=`function`)throw Error(`[fluxion error] Invalid disposer, expected a function but got ${typeof t}`);return{handler:e,disposer:t,type:0}}if(typeof e!=`object`||!e)throw Error(`[fluxion error] Invalid argument, expected a FluxionModule object or a handler function, but got ${typeof e}`);if(typeof e.handler!=`function`)throw Error(`[fluxion error] Invalid FluxionModule, "handler" must be a function`);if(e.disposer!==void 0&&typeof e.disposer!=`function`)throw Error(`[fluxion error] Invalid FluxionModule, "disposer" must be a function if provided`);if(e.methods!==void 0&&(!Array.isArray(e.methods)||e.methods.some(e=>typeof e!=`string`)))throw Error(`[fluxion error] Invalid FluxionModule, "methods" must be an array of strings if provided`);if(e.middlewares!==void 0&&(!Array.isArray(e.middlewares)||e.middlewares.some(e=>typeof e!=`function`)))throw Error(`[fluxion error] Invalid FluxionModule, "middlewares" must be an array of functions if provided`);return{...e,type:0}}function Le(e){if(typeof e!=`function`)throw Error(`[fluxion error] Invalid FluxionMiddleware, expected a function but got ${typeof e}`);return e}function Re(e){if(typeof e!=`function`)throw Error(`[fluxion error] Invalid FluxionLoggerFn, expected a function but got ${typeof e}`);return e}exports.BadGatewayException=Se,exports.BadRequestException=G,exports.ConflictException=he,exports.ForbiddenException=ue,exports.GatewayTimeoutException=we,exports.GoneException=ge,exports.HttpCode=se,exports.HttpException=W,exports.InternalServerErrorException=be,exports.MethodNotAllowedException=fe,exports.NotAcceptableException=pe,exports.NotFoundException=de,exports.NotImplementedException=xe,exports.PayloadTooLargeException=K,exports.RequestTimeoutException=me,exports.ServiceUnavailableException=Ce,exports.TooManyRequestsException=ye,exports.UnauthorizedException=le,exports.UnprocessableEntityException=ve,exports.UnsupportedMediaTypeException=_e,exports.defineFluxionLogger=Re,exports.defineFluxionMiddleware=Le,exports.defineFluxionModule=Ie,exports.fluxion=Fe;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|