mikroserve 0.0.2 → 0.0.5
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 +215 -1
- package/lib/MikroServe.d.mts +20 -40
- package/lib/MikroServe.d.ts +20 -40
- package/lib/MikroServe.js +101 -77
- package/lib/MikroServe.mjs +3 -1
- package/lib/chunk-6HESV5Q6.mjs +9 -0
- package/lib/{chunk-GGGGATKH.mjs → chunk-BUKLE4JV.mjs} +80 -77
- package/lib/chunk-NSHBEU32.mjs +43 -0
- package/lib/index.d.mts +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +101 -77
- package/lib/index.mjs +3 -1
- package/lib/interfaces/index.d.mts +71 -207
- package/lib/interfaces/index.d.ts +71 -207
- package/lib/utils/configDefaults.d.mts +20 -0
- package/lib/utils/configDefaults.d.ts +20 -0
- package/lib/utils/configDefaults.js +72 -0
- package/lib/utils/configDefaults.mjs +9 -0
- package/lib/utils/getTruthyValue.d.mts +6 -0
- package/lib/utils/getTruthyValue.d.ts +6 -0
- package/lib/utils/getTruthyValue.js +33 -0
- package/lib/utils/getTruthyValue.mjs +6 -0
- package/package.json +5 -3
package/lib/MikroServe.js
CHANGED
|
@@ -36,6 +36,7 @@ module.exports = __toCommonJS(MikroServe_exports);
|
|
|
36
36
|
var import_node_fs = require("fs");
|
|
37
37
|
var import_node_http = __toESM(require("http"));
|
|
38
38
|
var import_node_https = __toESM(require("https"));
|
|
39
|
+
var import_mikroconf = require("mikroconf");
|
|
39
40
|
|
|
40
41
|
// src/RateLimiter.ts
|
|
41
42
|
var RateLimiter = class {
|
|
@@ -280,93 +281,137 @@ var Router = class {
|
|
|
280
281
|
}
|
|
281
282
|
};
|
|
282
283
|
|
|
284
|
+
// src/utils/getTruthyValue.ts
|
|
285
|
+
function getTruthyValue(value) {
|
|
286
|
+
if (value === "true" || value === true) return true;
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// src/utils/configDefaults.ts
|
|
291
|
+
var configDefaults = () => {
|
|
292
|
+
return {
|
|
293
|
+
port: Number(process.env.PORT) || 3e3,
|
|
294
|
+
host: process.env.HOST || "0.0.0.0",
|
|
295
|
+
useHttps: false,
|
|
296
|
+
sslCert: "",
|
|
297
|
+
sslKey: "",
|
|
298
|
+
sslCa: "",
|
|
299
|
+
debug: getTruthyValue(process.env.DEBUG) || false,
|
|
300
|
+
rateLimit: {
|
|
301
|
+
enabled: true,
|
|
302
|
+
requestsPerMinute: 100
|
|
303
|
+
},
|
|
304
|
+
allowedDomains: ["*"]
|
|
305
|
+
};
|
|
306
|
+
};
|
|
307
|
+
|
|
283
308
|
// src/MikroServe.ts
|
|
284
309
|
var MikroServe = class {
|
|
285
310
|
config;
|
|
286
311
|
rateLimiter;
|
|
287
312
|
router;
|
|
288
|
-
useHttps;
|
|
289
|
-
sslCert;
|
|
290
|
-
sslKey;
|
|
291
|
-
sslCa;
|
|
292
|
-
debug;
|
|
293
313
|
/**
|
|
294
314
|
* @description Creates a new MikroServe instance.
|
|
295
|
-
* @param config - Server configuration options
|
|
296
315
|
*/
|
|
297
|
-
constructor(
|
|
316
|
+
constructor(options) {
|
|
317
|
+
const defaults = configDefaults();
|
|
318
|
+
const config = new import_mikroconf.MikroConf({
|
|
319
|
+
configFilePath: "mikroserve.config.json",
|
|
320
|
+
args: process.argv,
|
|
321
|
+
options: [
|
|
322
|
+
{ flag: "--port", path: "port", defaultValue: defaults.port },
|
|
323
|
+
{ flag: "--host", path: "host", defaultValue: defaults.host },
|
|
324
|
+
{ flag: "--https", path: "useHttps", defaultValue: defaults.useHttps, isFlag: true },
|
|
325
|
+
{ flag: "--cert", path: "sslCert", defaultValue: defaults.sslCert },
|
|
326
|
+
{ flag: "--key", path: "sslKey", defaultValue: defaults.sslKey },
|
|
327
|
+
{ flag: "--ca", path: "sslCa", defaultValue: defaults.sslCa },
|
|
328
|
+
{
|
|
329
|
+
flag: "--ratelimit",
|
|
330
|
+
path: "rateLimit.enabled",
|
|
331
|
+
defaultValue: defaults.rateLimit.enabled,
|
|
332
|
+
isFlag: true
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
flag: "--rps",
|
|
336
|
+
path: "rateLimit.requestsPerMinute",
|
|
337
|
+
defaultValue: defaults.rateLimit.requestsPerMinute
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
flag: "--allowed",
|
|
341
|
+
path: "allowedDomains",
|
|
342
|
+
defaultValue: defaults.allowedDomains,
|
|
343
|
+
parser: import_mikroconf.parsers.array
|
|
344
|
+
},
|
|
345
|
+
{ flag: "--debug", path: "debug", defaultValue: defaults.debug, isFlag: true }
|
|
346
|
+
],
|
|
347
|
+
config: options
|
|
348
|
+
}).get();
|
|
349
|
+
if (config.debug) console.log("Using configuration:", config);
|
|
298
350
|
this.config = config;
|
|
299
|
-
const { useHttps, sslCa, sslCert, sslKey, debug } = config;
|
|
300
|
-
const requestsPerMinute = config.rateLimit?.requestsPerMinute || 50;
|
|
301
|
-
this.rateLimiter = new RateLimiter(requestsPerMinute, 60);
|
|
302
351
|
this.router = new Router();
|
|
303
|
-
|
|
304
|
-
this.
|
|
305
|
-
|
|
306
|
-
this.sslCa = sslCa;
|
|
307
|
-
this.debug = debug || false;
|
|
308
|
-
if (config.rateLimit?.enabled !== false) this.use(this.rateLimitMiddleware.bind(this));
|
|
352
|
+
const requestsPerMinute = config.rateLimit.requestsPerMinute || defaults.rateLimit.requestsPerMinute;
|
|
353
|
+
this.rateLimiter = new RateLimiter(requestsPerMinute, 60);
|
|
354
|
+
if (config.rateLimit.enabled === true) this.use(this.rateLimitMiddleware.bind(this));
|
|
309
355
|
}
|
|
310
356
|
/**
|
|
311
|
-
* Register a global middleware
|
|
357
|
+
* @description Register a global middleware.
|
|
312
358
|
*/
|
|
313
359
|
use(middleware) {
|
|
314
360
|
this.router.use(middleware);
|
|
315
361
|
return this;
|
|
316
362
|
}
|
|
317
363
|
/**
|
|
318
|
-
* Register a GET route
|
|
364
|
+
* @description Register a GET route.
|
|
319
365
|
*/
|
|
320
366
|
get(path, ...handlers) {
|
|
321
367
|
this.router.get(path, ...handlers);
|
|
322
368
|
return this;
|
|
323
369
|
}
|
|
324
370
|
/**
|
|
325
|
-
* Register a POST route
|
|
371
|
+
* @description Register a POST route.
|
|
326
372
|
*/
|
|
327
373
|
post(path, ...handlers) {
|
|
328
374
|
this.router.post(path, ...handlers);
|
|
329
375
|
return this;
|
|
330
376
|
}
|
|
331
377
|
/**
|
|
332
|
-
* Register a PUT route
|
|
378
|
+
* @description Register a PUT route.
|
|
333
379
|
*/
|
|
334
380
|
put(path, ...handlers) {
|
|
335
381
|
this.router.put(path, ...handlers);
|
|
336
382
|
return this;
|
|
337
383
|
}
|
|
338
384
|
/**
|
|
339
|
-
* Register a DELETE route
|
|
385
|
+
* @description Register a DELETE route.
|
|
340
386
|
*/
|
|
341
387
|
delete(path, ...handlers) {
|
|
342
388
|
this.router.delete(path, ...handlers);
|
|
343
389
|
return this;
|
|
344
390
|
}
|
|
345
391
|
/**
|
|
346
|
-
* Register a PATCH route
|
|
392
|
+
* @description Register a PATCH route.
|
|
347
393
|
*/
|
|
348
394
|
patch(path, ...handlers) {
|
|
349
395
|
this.router.patch(path, ...handlers);
|
|
350
396
|
return this;
|
|
351
397
|
}
|
|
352
398
|
/**
|
|
353
|
-
* Register an OPTIONS route
|
|
399
|
+
* @description Register an OPTIONS route.
|
|
354
400
|
*/
|
|
355
401
|
options(path, ...handlers) {
|
|
356
402
|
this.router.options(path, ...handlers);
|
|
357
403
|
return this;
|
|
358
404
|
}
|
|
359
405
|
/**
|
|
360
|
-
* Creates an HTTP/HTTPS server, sets up graceful shutdown, and starts listening.
|
|
361
|
-
* @returns Running HTTP/HTTPS server
|
|
406
|
+
* @description Creates an HTTP/HTTPS server, sets up graceful shutdown, and starts listening.
|
|
362
407
|
*/
|
|
363
408
|
start() {
|
|
364
409
|
const server = this.createServer();
|
|
365
|
-
const { port
|
|
410
|
+
const { port, host } = this.config;
|
|
366
411
|
this.setupGracefulShutdown(server);
|
|
367
412
|
server.listen(port, host, () => {
|
|
368
413
|
const address = server.address();
|
|
369
|
-
const protocol = this.useHttps ? "https" : "http";
|
|
414
|
+
const protocol = this.config.useHttps ? "https" : "http";
|
|
370
415
|
console.log(
|
|
371
416
|
`MikroServe running at ${protocol}://${address.address !== "::" ? address.address : "localhost"}:${address.port}`
|
|
372
417
|
);
|
|
@@ -374,19 +419,18 @@ var MikroServe = class {
|
|
|
374
419
|
return server;
|
|
375
420
|
}
|
|
376
421
|
/**
|
|
377
|
-
* Creates and configures a server instance without starting it.
|
|
378
|
-
* @returns Configured HTTP or HTTPS server instance
|
|
422
|
+
* @description Creates and configures a server instance without starting it.
|
|
379
423
|
*/
|
|
380
424
|
createServer() {
|
|
381
425
|
const boundRequestHandler = this.requestHandler.bind(this);
|
|
382
|
-
if (this.useHttps) {
|
|
383
|
-
if (!this.sslCert || !this.sslKey)
|
|
426
|
+
if (this.config.useHttps) {
|
|
427
|
+
if (!this.config.sslCert || !this.config.sslKey)
|
|
384
428
|
throw new Error("SSL certificate and key paths are required when useHttps is true");
|
|
385
429
|
try {
|
|
386
430
|
const httpsOptions = {
|
|
387
|
-
key: (0, import_node_fs.readFileSync)(this.sslKey),
|
|
388
|
-
cert: (0, import_node_fs.readFileSync)(this.sslCert),
|
|
389
|
-
...this.sslCa ? { ca: (0, import_node_fs.readFileSync)(this.sslCa) } : {}
|
|
431
|
+
key: (0, import_node_fs.readFileSync)(this.config.sslKey),
|
|
432
|
+
cert: (0, import_node_fs.readFileSync)(this.config.sslCert),
|
|
433
|
+
...this.config.sslCa ? { ca: (0, import_node_fs.readFileSync)(this.config.sslCa) } : {}
|
|
390
434
|
};
|
|
391
435
|
return import_node_https.default.createServer(httpsOptions, boundRequestHandler);
|
|
392
436
|
} catch (error) {
|
|
@@ -398,7 +442,7 @@ var MikroServe = class {
|
|
|
398
442
|
return import_node_http.default.createServer(boundRequestHandler);
|
|
399
443
|
}
|
|
400
444
|
/**
|
|
401
|
-
* Rate limiting middleware
|
|
445
|
+
* @description Rate limiting middleware.
|
|
402
446
|
*/
|
|
403
447
|
async rateLimitMiddleware(context, next) {
|
|
404
448
|
const ip = context.req.socket.remoteAddress || "unknown";
|
|
@@ -421,16 +465,17 @@ var MikroServe = class {
|
|
|
421
465
|
return next();
|
|
422
466
|
}
|
|
423
467
|
/**
|
|
424
|
-
* Request handler for HTTP and HTTPS servers.
|
|
468
|
+
* @description Request handler for HTTP and HTTPS servers.
|
|
425
469
|
*/
|
|
426
470
|
async requestHandler(req, res) {
|
|
427
471
|
const start = Date.now();
|
|
428
472
|
const method = req.method || "UNKNOWN";
|
|
429
473
|
const url = req.url || "/unknown";
|
|
474
|
+
const isDebug = this.config.debug;
|
|
430
475
|
try {
|
|
431
476
|
this.setCorsHeaders(res, req);
|
|
432
|
-
this.setSecurityHeaders(res, this.useHttps);
|
|
433
|
-
if (
|
|
477
|
+
this.setSecurityHeaders(res, this.config.useHttps);
|
|
478
|
+
if (isDebug) console.log(`${method} ${url}`);
|
|
434
479
|
if (req.method === "OPTIONS") {
|
|
435
480
|
res.statusCode = 204;
|
|
436
481
|
res.end();
|
|
@@ -439,9 +484,7 @@ var MikroServe = class {
|
|
|
439
484
|
try {
|
|
440
485
|
req.body = await this.parseBody(req);
|
|
441
486
|
} catch (error) {
|
|
442
|
-
if (
|
|
443
|
-
console.error("Body parsing error:", error.message);
|
|
444
|
-
}
|
|
487
|
+
if (isDebug) console.error("Body parsing error:", error.message);
|
|
445
488
|
return this.respond(res, {
|
|
446
489
|
statusCode: 400,
|
|
447
490
|
body: {
|
|
@@ -465,33 +508,22 @@ var MikroServe = class {
|
|
|
465
508
|
statusCode: 500,
|
|
466
509
|
body: {
|
|
467
510
|
error: "Internal Server Error",
|
|
468
|
-
message:
|
|
511
|
+
message: isDebug ? error.message : "An unexpected error occurred"
|
|
469
512
|
}
|
|
470
513
|
});
|
|
471
514
|
} finally {
|
|
472
|
-
if (this.
|
|
473
|
-
this.logDuration(start, method, url);
|
|
474
|
-
}
|
|
515
|
+
if (isDebug) this.logDuration(start, method, url);
|
|
475
516
|
}
|
|
476
517
|
}
|
|
477
518
|
/**
|
|
478
|
-
* Writes out a clean log to represent the duration of the request.
|
|
519
|
+
* @description Writes out a clean log to represent the duration of the request.
|
|
479
520
|
*/
|
|
480
521
|
logDuration(start, method, url) {
|
|
481
522
|
const duration = Date.now() - start;
|
|
482
523
|
console.log(`${method} ${url} completed in ${duration}ms`);
|
|
483
524
|
}
|
|
484
525
|
/**
|
|
485
|
-
* Parses the request body based on content type.
|
|
486
|
-
* @param req - HTTP request object
|
|
487
|
-
* @returns Promise resolving to the parsed body
|
|
488
|
-
* @throws Will throw if body cannot be parsed
|
|
489
|
-
*/
|
|
490
|
-
/**
|
|
491
|
-
* Parses the request body based on content type.
|
|
492
|
-
* @param req - HTTP request object
|
|
493
|
-
* @returns Promise resolving to the parsed body
|
|
494
|
-
* @throws Will throw if body cannot be parsed
|
|
526
|
+
* @description Parses the request body based on content type.
|
|
495
527
|
*/
|
|
496
528
|
async parseBody(req) {
|
|
497
529
|
return new Promise((resolve, reject) => {
|
|
@@ -499,17 +531,17 @@ var MikroServe = class {
|
|
|
499
531
|
let bodySize = 0;
|
|
500
532
|
const MAX_BODY_SIZE = 1024 * 1024;
|
|
501
533
|
let rejected = false;
|
|
534
|
+
const isDebug = this.config.debug;
|
|
502
535
|
const contentType = req.headers["content-type"] || "";
|
|
503
|
-
if (
|
|
536
|
+
if (isDebug) {
|
|
504
537
|
console.log("Content-Type:", contentType);
|
|
505
538
|
}
|
|
506
539
|
req.on("data", (chunk) => {
|
|
507
540
|
bodySize += chunk.length;
|
|
508
|
-
if (
|
|
509
|
-
console.log(`Received chunk: ${chunk.length} bytes, total size: ${bodySize}`);
|
|
541
|
+
if (isDebug) console.log(`Received chunk: ${chunk.length} bytes, total size: ${bodySize}`);
|
|
510
542
|
if (bodySize > MAX_BODY_SIZE && !rejected) {
|
|
511
543
|
rejected = true;
|
|
512
|
-
if (
|
|
544
|
+
if (isDebug) console.log(`Body size exceeded limit: ${bodySize} > ${MAX_BODY_SIZE}`);
|
|
513
545
|
reject(new Error("Request body too large"));
|
|
514
546
|
return;
|
|
515
547
|
}
|
|
@@ -517,7 +549,7 @@ var MikroServe = class {
|
|
|
517
549
|
});
|
|
518
550
|
req.on("end", () => {
|
|
519
551
|
if (rejected) return;
|
|
520
|
-
if (
|
|
552
|
+
if (isDebug) console.log(`Request body complete: ${bodySize} bytes`);
|
|
521
553
|
try {
|
|
522
554
|
if (bodyChunks.length > 0) {
|
|
523
555
|
const bodyString = Buffer.concat(bodyChunks).toString("utf8");
|
|
@@ -549,17 +581,14 @@ var MikroServe = class {
|
|
|
549
581
|
});
|
|
550
582
|
}
|
|
551
583
|
/**
|
|
552
|
-
* CORS middleware
|
|
584
|
+
* @description CORS middleware.
|
|
553
585
|
*/
|
|
554
|
-
// Update the setCorsHeaders method in MikroServe class to handle allowed domains
|
|
555
586
|
setCorsHeaders(res, req) {
|
|
556
587
|
const origin = req.headers.origin;
|
|
557
588
|
const { allowedDomains = ["*"] } = this.config;
|
|
558
|
-
if (!origin || allowedDomains.length === 0)
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
562
|
-
} else if (allowedDomains.includes(origin)) {
|
|
589
|
+
if (!origin || allowedDomains.length === 0) res.setHeader("Access-Control-Allow-Origin", "*");
|
|
590
|
+
else if (allowedDomains.includes("*")) res.setHeader("Access-Control-Allow-Origin", "*");
|
|
591
|
+
else if (allowedDomains.includes(origin)) {
|
|
563
592
|
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
564
593
|
res.setHeader("Vary", "Origin");
|
|
565
594
|
}
|
|
@@ -568,7 +597,7 @@ var MikroServe = class {
|
|
|
568
597
|
res.setHeader("Access-Control-Max-Age", "86400");
|
|
569
598
|
}
|
|
570
599
|
/**
|
|
571
|
-
* Set security headers
|
|
600
|
+
* @description Set security headers.
|
|
572
601
|
*/
|
|
573
602
|
setSecurityHeaders(res, isHttps = false) {
|
|
574
603
|
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
@@ -581,9 +610,7 @@ var MikroServe = class {
|
|
|
581
610
|
res.setHeader("X-XSS-Protection", "1; mode=block");
|
|
582
611
|
}
|
|
583
612
|
/**
|
|
584
|
-
* Sends a response with appropriate headers.
|
|
585
|
-
* @param res - HTTP response object
|
|
586
|
-
* @param response - Response data and status code
|
|
613
|
+
* @description Sends a response with appropriate headers.
|
|
587
614
|
*/
|
|
588
615
|
respond(res, response) {
|
|
589
616
|
const headers = {
|
|
@@ -595,8 +622,7 @@ var MikroServe = class {
|
|
|
595
622
|
else res.end(JSON.stringify(response.body));
|
|
596
623
|
}
|
|
597
624
|
/**
|
|
598
|
-
* Sets up graceful shutdown handlers for a server.
|
|
599
|
-
* @param server - The HTTP/HTTPS server to add shutdown handlers to
|
|
625
|
+
* @description Sets up graceful shutdown handlers for a server.
|
|
600
626
|
*/
|
|
601
627
|
setupGracefulShutdown(server) {
|
|
602
628
|
const shutdown = (error) => {
|
|
@@ -604,9 +630,7 @@ var MikroServe = class {
|
|
|
604
630
|
if (error) console.error("Error:", error);
|
|
605
631
|
server.close(() => {
|
|
606
632
|
console.log("Server closed successfully");
|
|
607
|
-
setImmediate(() =>
|
|
608
|
-
process.exit(error ? 1 : 0);
|
|
609
|
-
});
|
|
633
|
+
setImmediate(() => process.exit(error ? 1 : 0));
|
|
610
634
|
});
|
|
611
635
|
};
|
|
612
636
|
process.on("SIGINT", () => shutdown());
|
package/lib/MikroServe.mjs
CHANGED