fluxion-ts 0.1.6 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +115 -0
- package/dist/index.cjs +59 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +20 -0
- package/dist/index.mjs +61 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -288,6 +288,11 @@ interface FluxionOptions {
|
|
|
288
288
|
logger?: 'one-line' | 'json-line' | InjectionConfig;
|
|
289
289
|
apiExts?: string[];
|
|
290
290
|
routerExclude?: string[];
|
|
291
|
+
https?: {
|
|
292
|
+
key: string | Buffer;
|
|
293
|
+
cert: string | Buffer;
|
|
294
|
+
ca?: string | Buffer | Array<string | Buffer>;
|
|
295
|
+
};
|
|
291
296
|
}
|
|
292
297
|
```
|
|
293
298
|
|
|
@@ -382,6 +387,116 @@ interface WorkerOptions {
|
|
|
382
387
|
|
|
383
388
|
Current implementation uses `maxWorkerCount` for process count and reports CPU/memory telemetry from workers.
|
|
384
389
|
|
|
390
|
+
### `https`
|
|
391
|
+
|
|
392
|
+
HTTPS server configuration. When provided, Fluxion creates an HTTPS server instead of HTTP.
|
|
393
|
+
|
|
394
|
+
```ts
|
|
395
|
+
fluxion({
|
|
396
|
+
dir: './dynamicDirectory',
|
|
397
|
+
host: '127.0.0.1',
|
|
398
|
+
port: 9443,
|
|
399
|
+
https: {
|
|
400
|
+
key: './certs/private-key.pem', // 私钥文件路径或内容
|
|
401
|
+
cert: './certs/certificate.pem', // 证书文件路径或内容
|
|
402
|
+
ca: './certs/ca-bundle.crt', // 可选:CA 证书链
|
|
403
|
+
},
|
|
404
|
+
});
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
Relative paths are resolved relative to `moduleDir`. PEM content can be passed directly as strings.
|
|
408
|
+
|
|
409
|
+
### `dir`
|
|
410
|
+
|
|
411
|
+
Dynamic directory root. Created automatically if missing.
|
|
412
|
+
|
|
413
|
+
### `host`
|
|
414
|
+
|
|
415
|
+
Host passed to `server.listen`.
|
|
416
|
+
|
|
417
|
+
### `port`
|
|
418
|
+
|
|
419
|
+
Business server port.
|
|
420
|
+
|
|
421
|
+
### `metaPort`
|
|
422
|
+
|
|
423
|
+
Primary meta API port. Defaults to `port + 1` and must be different from `port`.
|
|
424
|
+
|
|
425
|
+
### `reloadDelay`
|
|
426
|
+
|
|
427
|
+
Debounce delay for file re-registration. Defaults to `300` and must be at least `50`.
|
|
428
|
+
|
|
429
|
+
### `apiExts`
|
|
430
|
+
|
|
431
|
+
Extensions registered as API handlers. Defaults to:
|
|
432
|
+
|
|
433
|
+
```ts
|
|
434
|
+
['.ts']
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
Example:
|
|
438
|
+
|
|
439
|
+
```ts
|
|
440
|
+
fluxion({
|
|
441
|
+
dir: './dynamicDirectory',
|
|
442
|
+
host: '127.0.0.1',
|
|
443
|
+
port: 3000,
|
|
444
|
+
apiExts: ['.ts', '.mjs'],
|
|
445
|
+
});
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### `routerExclude`
|
|
449
|
+
|
|
450
|
+
Extensions excluded from both API and static registration.
|
|
451
|
+
|
|
452
|
+
Example:
|
|
453
|
+
|
|
454
|
+
```ts
|
|
455
|
+
routerExclude: ['.map']
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### `maxRequestBytes`
|
|
459
|
+
|
|
460
|
+
Maximum accepted request body size. Defaults to `8_000_000`.
|
|
461
|
+
|
|
462
|
+
### `logger`
|
|
463
|
+
|
|
464
|
+
Built-in modes:
|
|
465
|
+
|
|
466
|
+
- `one-line`
|
|
467
|
+
- `json-line`
|
|
468
|
+
|
|
469
|
+
A custom logger can be loaded through an injection config object whose module exports a function.
|
|
470
|
+
|
|
471
|
+
### `injections`
|
|
472
|
+
|
|
473
|
+
Worker startup injections. Each item is loaded with `require(modulePath)` and called as a factory. The resulting instances are stored on:
|
|
474
|
+
|
|
475
|
+
```ts
|
|
476
|
+
globalThis[Symbol.for('fluxion.injection')]
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
### `workerOptions`
|
|
480
|
+
|
|
481
|
+
Runtime tuning options:
|
|
482
|
+
|
|
483
|
+
```ts
|
|
484
|
+
interface WorkerOptions {
|
|
485
|
+
maxWorkerCount: number;
|
|
486
|
+
requestTimeoutMs: number;
|
|
487
|
+
maxInflight: number;
|
|
488
|
+
memorySoftLimitMb: number;
|
|
489
|
+
memoryHardLimitMb: number;
|
|
490
|
+
memorySampleIntervalMs: number;
|
|
491
|
+
maxOldGenerationSizeMb: number;
|
|
492
|
+
maxYoungGenerationSizeMb: number;
|
|
493
|
+
stackSizeMb: number;
|
|
494
|
+
maxResponseBytes: number;
|
|
495
|
+
}
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
Current implementation uses `maxWorkerCount` for process count and reports CPU/memory telemetry from workers.
|
|
499
|
+
|
|
385
500
|
## Build and Test
|
|
386
501
|
|
|
387
502
|
```bash
|
package/dist/index.cjs
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var fs = require('node:fs');
|
|
4
|
+
var path = require('node:path');
|
|
4
5
|
var cluster = require('node:cluster');
|
|
5
6
|
var os = require('node:os');
|
|
6
7
|
var http = require('node:http');
|
|
7
|
-
var
|
|
8
|
+
var https = require('node:https');
|
|
8
9
|
|
|
9
10
|
const ANSI_BACKGROUND_OFFSET = 10;
|
|
10
11
|
|
|
@@ -660,12 +661,56 @@ function expectLoggerOption(o) {
|
|
|
660
661
|
}
|
|
661
662
|
throw new Error(`[FluxionTs error] Invalid logger option, must be 'one-line', 'json-line' or { modulePath: string; name: string; }`);
|
|
662
663
|
}
|
|
664
|
+
/**
|
|
665
|
+
* Read certificate content from a file path or return the content directly.
|
|
666
|
+
*/
|
|
667
|
+
function readCertificateContent(content, moduleDir) {
|
|
668
|
+
if (Buffer.isBuffer(content)) {
|
|
669
|
+
return content;
|
|
670
|
+
}
|
|
671
|
+
if (typeof content === 'string') {
|
|
672
|
+
// Check if it looks like a file path (not a PEM certificate)
|
|
673
|
+
// PEM certificates start with "-----BEGIN"
|
|
674
|
+
if (!content.startsWith('-----BEGIN')) {
|
|
675
|
+
const filePath = path.isAbsolute(content) ? content : path.join(moduleDir, content);
|
|
676
|
+
if (fs.existsSync(filePath)) {
|
|
677
|
+
return fs.readFileSync(filePath);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
return Buffer.from(content);
|
|
681
|
+
}
|
|
682
|
+
throw new Error('[FluxionTs error] Certificate content must be a string or Buffer');
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Normalize HTTPS options.
|
|
686
|
+
*/
|
|
687
|
+
function normalizeHttpsOptions(https, moduleDir) {
|
|
688
|
+
if (!https) {
|
|
689
|
+
return undefined;
|
|
690
|
+
}
|
|
691
|
+
expect.isObject(https, 'FluxionOptions.https must be an object');
|
|
692
|
+
expect.isString(https.key, 'FluxionOptions.https.key must be a string');
|
|
693
|
+
expect.isString(https.cert, 'FluxionOptions.https.cert must be a string');
|
|
694
|
+
const result = {
|
|
695
|
+
key: readCertificateContent(https.key, moduleDir),
|
|
696
|
+
cert: readCertificateContent(https.cert, moduleDir),
|
|
697
|
+
};
|
|
698
|
+
if (https.ca !== undefined) {
|
|
699
|
+
if (Array.isArray(https.ca)) {
|
|
700
|
+
result.ca = https.ca.map((item) => readCertificateContent(item, moduleDir));
|
|
701
|
+
}
|
|
702
|
+
else {
|
|
703
|
+
result.ca = readCertificateContent(https.ca, moduleDir);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
return result;
|
|
707
|
+
}
|
|
663
708
|
/**
|
|
664
709
|
* Normalize options and create necessary resources like the dynamic directory and logger.
|
|
665
710
|
*/
|
|
666
711
|
function normalizeOptions(options) {
|
|
667
712
|
expect.isObject(options, 'FluxionOptions must be an object');
|
|
668
|
-
let { dir, host, port, metaPort, injections = [], moduleDir = process.cwd(), workerOptions = {}, maxRequestBytes =
|
|
713
|
+
let { dir, host, port, metaPort, injections = [], moduleDir = process.cwd(), workerOptions = {}, maxRequestBytes = 8_000_000, reloadDelay = 300, apiExts = ['.ts'], routerExclude = [], https, } = options;
|
|
669
714
|
const logger = options.logger ?? 'one-line';
|
|
670
715
|
expectLoggerOption(logger);
|
|
671
716
|
expect.isString(dir, 'FluxionOptions.dir must be a string');
|
|
@@ -679,7 +724,7 @@ function normalizeOptions(options) {
|
|
|
679
724
|
if (port > 65535) {
|
|
680
725
|
throw new Error('[FluxionTs error] FluxionOptions.port must be less than or equal to 65535');
|
|
681
726
|
}
|
|
682
|
-
metaPort
|
|
727
|
+
metaPort ??= port + 1;
|
|
683
728
|
expect.isPositiveInteger(metaPort, 'FluxionOptions.metaPort must be a positive integer');
|
|
684
729
|
if (metaPort > 65535) {
|
|
685
730
|
throw new Error('[FluxionTs error] FluxionOptions.metaPort must be less than or equal to 65535');
|
|
@@ -706,6 +751,7 @@ function normalizeOptions(options) {
|
|
|
706
751
|
logger,
|
|
707
752
|
apiExts,
|
|
708
753
|
routerExclude,
|
|
754
|
+
https: normalizeHttpsOptions(https, moduleDir),
|
|
709
755
|
};
|
|
710
756
|
}
|
|
711
757
|
|
|
@@ -1204,7 +1250,7 @@ function parseCookie(cookieHeader) {
|
|
|
1204
1250
|
}
|
|
1205
1251
|
|
|
1206
1252
|
function createWorkerServer(cx) {
|
|
1207
|
-
const
|
|
1253
|
+
const requestHandler = async (req, res) => {
|
|
1208
1254
|
const method = req.method ?? 'GET';
|
|
1209
1255
|
const ip = getRealIp(req);
|
|
1210
1256
|
const url = toURL(req.url);
|
|
@@ -1280,7 +1326,14 @@ function createWorkerServer(cx) {
|
|
|
1280
1326
|
safeSendJson(res, { message: 'Internal Server Error' }, 500 /* HttpCode.InternalServerError */);
|
|
1281
1327
|
}
|
|
1282
1328
|
}
|
|
1283
|
-
}
|
|
1329
|
+
};
|
|
1330
|
+
const server = cx.options.https
|
|
1331
|
+
? https.createServer({
|
|
1332
|
+
key: cx.options.https.key,
|
|
1333
|
+
cert: cx.options.https.cert,
|
|
1334
|
+
ca: cx.options.https.ca,
|
|
1335
|
+
}, requestHandler)
|
|
1336
|
+
: http.createServer(requestHandler);
|
|
1284
1337
|
server.on('close', () => {
|
|
1285
1338
|
cx.logger.info('ServerClosed', {
|
|
1286
1339
|
host: cx.options.host,
|
|
@@ -1290,6 +1343,7 @@ function createWorkerServer(cx) {
|
|
|
1290
1343
|
server.listen(cx.options.port, cx.options.host, () => {
|
|
1291
1344
|
cx.logger.info('ServerStarted', {
|
|
1292
1345
|
pid: process.pid,
|
|
1346
|
+
protocol: cx.options.https ? 'https' : 'http',
|
|
1293
1347
|
host: cx.options.host,
|
|
1294
1348
|
port: cx.options.port,
|
|
1295
1349
|
});
|