mikroserve 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,8 +2,13 @@
2
2
 
3
3
  **Minimalistic, ready-to-use API, built on Node.js primitives**.
4
4
 
5
+ [![npm version](https://img.shields.io/npm/v/mikroserve.svg)](https://www.npmjs.com/package/mikroserve)
6
+
7
+ [![bundle size](https://img.shields.io/bundlephobia/minzip/mikroserve)](https://bundlephobia.com/package/mikroserve)
8
+
5
9
  ![Build Status](https://github.com/mikaelvesavuori/mikroserve/workflows/main/badge.svg)
6
- [![License](https://img.shields.io/badge/license-MIT-green.svg)](https://opensource.org/licenses/MIT)
10
+
11
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
12
 
8
13
  ---
9
14
 
@@ -1,6 +1,7 @@
1
- import http from 'node:http';
2
- import https from 'node:https';
3
- import { MikroServeOptions, Middleware, RouteHandler } from './interfaces/index.mjs';
1
+ import { MikroServeOptions, Middleware, RouteHandler, ServerType } from './interfaces/index.mjs';
2
+ import 'node:http';
3
+ import 'node:http2';
4
+ import 'node:https';
4
5
 
5
6
  /**
6
7
  * @description MikroServe manages HTTP server operations with routing.
@@ -44,11 +45,11 @@ declare class MikroServe {
44
45
  /**
45
46
  * @description Creates an HTTP/HTTPS server, sets up graceful shutdown, and starts listening.
46
47
  */
47
- start(): http.Server | https.Server;
48
+ start(): ServerType;
48
49
  /**
49
50
  * @description Creates and configures a server instance without starting it.
50
51
  */
51
- createServer(): http.Server | https.Server;
52
+ createServer(): ServerType;
52
53
  /**
53
54
  * @description Rate limiting middleware.
54
55
  */
@@ -80,7 +81,7 @@ declare class MikroServe {
80
81
  /**
81
82
  * @description Sets up graceful shutdown handlers for a server.
82
83
  */
83
- setupGracefulShutdown(server: http.Server | https.Server): void;
84
+ setupGracefulShutdown(server: ServerType): void;
84
85
  }
85
86
 
86
87
  export { MikroServe };
@@ -1,6 +1,7 @@
1
- import http from 'node:http';
2
- import https from 'node:https';
3
- import { MikroServeOptions, Middleware, RouteHandler } from './interfaces/index.js';
1
+ import { MikroServeOptions, Middleware, RouteHandler, ServerType } from './interfaces/index.js';
2
+ import 'node:http';
3
+ import 'node:http2';
4
+ import 'node:https';
4
5
 
5
6
  /**
6
7
  * @description MikroServe manages HTTP server operations with routing.
@@ -44,11 +45,11 @@ declare class MikroServe {
44
45
  /**
45
46
  * @description Creates an HTTP/HTTPS server, sets up graceful shutdown, and starts listening.
46
47
  */
47
- start(): http.Server | https.Server;
48
+ start(): ServerType;
48
49
  /**
49
50
  * @description Creates and configures a server instance without starting it.
50
51
  */
51
- createServer(): http.Server | https.Server;
52
+ createServer(): ServerType;
52
53
  /**
53
54
  * @description Rate limiting middleware.
54
55
  */
@@ -80,7 +81,7 @@ declare class MikroServe {
80
81
  /**
81
82
  * @description Sets up graceful shutdown handlers for a server.
82
83
  */
83
- setupGracefulShutdown(server: http.Server | https.Server): void;
84
+ setupGracefulShutdown(server: ServerType): void;
84
85
  }
85
86
 
86
87
  export { MikroServe };
package/lib/MikroServe.js CHANGED
@@ -35,6 +35,7 @@ __export(MikroServe_exports, {
35
35
  module.exports = __toCommonJS(MikroServe_exports);
36
36
  var import_node_fs = require("fs");
37
37
  var import_node_http = __toESM(require("http"));
38
+ var import_node_http2 = __toESM(require("http2"));
38
39
  var import_node_https = __toESM(require("https"));
39
40
  var import_mikroconf = require("mikroconf");
40
41
 
@@ -281,18 +282,13 @@ var Router = class {
281
282
  }
282
283
  };
283
284
 
284
- // src/utils/getTruthyValue.ts
285
- function getTruthyValue(value) {
286
- if (value === "true" || value === true) return true;
287
- return false;
288
- }
289
-
290
285
  // src/utils/configDefaults.ts
291
286
  var configDefaults = () => {
292
287
  return {
293
288
  port: Number(process.env.PORT) || 3e3,
294
289
  host: process.env.HOST || "0.0.0.0",
295
290
  useHttps: false,
291
+ useHttp2: false,
296
292
  sslCert: "",
297
293
  sslKey: "",
298
294
  sslCa: "",
@@ -304,6 +300,10 @@ var configDefaults = () => {
304
300
  allowedDomains: ["*"]
305
301
  };
306
302
  };
303
+ function getTruthyValue(value) {
304
+ if (value === "true" || value === true) return true;
305
+ return false;
306
+ }
307
307
 
308
308
  // src/MikroServe.ts
309
309
  var MikroServe = class {
@@ -322,6 +322,7 @@ var MikroServe = class {
322
322
  { flag: "--port", path: "port", defaultValue: defaults.port },
323
323
  { flag: "--host", path: "host", defaultValue: defaults.host },
324
324
  { flag: "--https", path: "useHttps", defaultValue: defaults.useHttps, isFlag: true },
325
+ { flag: "--http2", path: "useHttp2", defaultValue: defaults.useHttp2, isFlag: true },
325
326
  { flag: "--cert", path: "sslCert", defaultValue: defaults.sslCert },
326
327
  { flag: "--key", path: "sslKey", defaultValue: defaults.sslKey },
327
328
  { flag: "--ca", path: "sslCa", defaultValue: defaults.sslCa },
@@ -423,7 +424,22 @@ var MikroServe = class {
423
424
  */
424
425
  createServer() {
425
426
  const boundRequestHandler = this.requestHandler.bind(this);
426
- if (this.config.useHttps) {
427
+ if (this.config.useHttp2) {
428
+ if (!this.config.sslCert || !this.config.sslKey)
429
+ throw new Error("SSL certificate and key paths are required when useHttp2 is true");
430
+ try {
431
+ const httpsOptions = {
432
+ key: (0, import_node_fs.readFileSync)(this.config.sslKey),
433
+ cert: (0, import_node_fs.readFileSync)(this.config.sslCert),
434
+ ...this.config.sslCa ? { ca: (0, import_node_fs.readFileSync)(this.config.sslCa) } : {}
435
+ };
436
+ return import_node_http2.default.createSecureServer(httpsOptions, boundRequestHandler);
437
+ } catch (error) {
438
+ if (error.message.includes("key values mismatch"))
439
+ throw new Error(`SSL certificate and key do not match: ${error.message}`);
440
+ throw error;
441
+ }
442
+ } else if (this.config.useHttps) {
427
443
  if (!this.config.sslCert || !this.config.sslKey)
428
444
  throw new Error("SSL certificate and key paths are required when useHttps is true");
429
445
  try {
@@ -477,8 +493,14 @@ var MikroServe = class {
477
493
  this.setSecurityHeaders(res, this.config.useHttps);
478
494
  if (isDebug) console.log(`${method} ${url}`);
479
495
  if (req.method === "OPTIONS") {
480
- res.statusCode = 204;
481
- res.end();
496
+ if (res instanceof import_node_http.default.ServerResponse) {
497
+ res.statusCode = 204;
498
+ res.end();
499
+ } else {
500
+ const h2Res = res;
501
+ h2Res.writeHead(204);
502
+ h2Res.end();
503
+ }
482
504
  return;
483
505
  }
484
506
  try {
@@ -603,14 +625,25 @@ var MikroServe = class {
603
625
  * @description Set security headers.
604
626
  */
605
627
  setSecurityHeaders(res, isHttps = false) {
606
- res.setHeader("X-Content-Type-Options", "nosniff");
607
- res.setHeader("X-Frame-Options", "DENY");
608
- res.setHeader(
609
- "Content-Security-Policy",
610
- "default-src 'self'; script-src 'self'; object-src 'none'"
611
- );
612
- if (isHttps) res.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
613
- res.setHeader("X-XSS-Protection", "1; mode=block");
628
+ const securityHeaders = {
629
+ "X-Content-Type-Options": "nosniff",
630
+ "X-Frame-Options": "DENY",
631
+ "Content-Security-Policy": "default-src 'self'; script-src 'self'; object-src 'none'",
632
+ "X-XSS-Protection": "1; mode=block"
633
+ };
634
+ if (isHttps || this.config.useHttp2) {
635
+ securityHeaders["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains";
636
+ }
637
+ if (res instanceof import_node_http.default.ServerResponse) {
638
+ Object.entries(securityHeaders).forEach(([name, value]) => {
639
+ res.setHeader(name, value);
640
+ });
641
+ } else {
642
+ const h2Res = res;
643
+ Object.entries(securityHeaders).forEach(([name, value]) => {
644
+ h2Res.setHeader(name, value);
645
+ });
646
+ }
614
647
  }
615
648
  /**
616
649
  * @description Sends a response with appropriate headers.
@@ -619,10 +652,21 @@ var MikroServe = class {
619
652
  const headers = {
620
653
  ...response.headers || {}
621
654
  };
622
- res.writeHead(response.statusCode, headers);
623
- if (response.body === null || response.body === void 0) res.end();
624
- else if (typeof response.body === "string") res.end(response.body);
625
- else res.end(JSON.stringify(response.body));
655
+ const hasWriteHead = (res2) => {
656
+ return typeof res2.writeHead === "function" && typeof res2.end === "function";
657
+ };
658
+ if (hasWriteHead(res)) {
659
+ res.writeHead(response.statusCode, headers);
660
+ if (response.body === null || response.body === void 0) res.end();
661
+ else if (typeof response.body === "string") res.end(response.body);
662
+ else res.end(JSON.stringify(response.body));
663
+ } else {
664
+ console.warn("Unexpected response object type without writeHead/end methods");
665
+ res.writeHead?.(response.statusCode, headers);
666
+ if (response.body === null || response.body === void 0) res.end?.();
667
+ else if (typeof response.body === "string") res.end?.(response.body);
668
+ else res.end?.(JSON.stringify(response.body));
669
+ }
626
670
  }
627
671
  /**
628
672
  * @description Sets up graceful shutdown handlers for a server.
@@ -1,10 +1,9 @@
1
1
  import {
2
2
  MikroServe
3
- } from "./chunk-E3RGQ7QF.mjs";
3
+ } from "./chunk-J2WPHNMW.mjs";
4
4
  import "./chunk-ZFBBESGU.mjs";
5
5
  import "./chunk-KJT4SET2.mjs";
6
- import "./chunk-NSHBEU32.mjs";
7
- import "./chunk-6HESV5Q6.mjs";
6
+ import "./chunk-JJX5XRNB.mjs";
8
7
  export {
9
8
  MikroServe
10
9
  };
package/lib/Router.d.mts CHANGED
@@ -1,5 +1,7 @@
1
- import http from 'node:http';
2
- import { Middleware, RouteHandler, Route, HandlerResponse } from './interfaces/index.mjs';
1
+ import { Middleware, RouteHandler, Route, RequestType, ResponseType, HandlerResponse } from './interfaces/index.mjs';
2
+ import 'node:http';
3
+ import 'node:http2';
4
+ import 'node:https';
3
5
 
4
6
  /**
5
7
  * Router class to manage routes and middleware
@@ -54,7 +56,7 @@ declare class Router {
54
56
  /**
55
57
  * Handle a request and find the matching route
56
58
  */
57
- handle(req: http.IncomingMessage, res: http.ServerResponse): Promise<HandlerResponse | null>;
59
+ handle(req: RequestType, res: ResponseType): Promise<HandlerResponse | null>;
58
60
  /**
59
61
  * Execute middleware chain and final handler
60
62
  */
package/lib/Router.d.ts CHANGED
@@ -1,5 +1,7 @@
1
- import http from 'node:http';
2
- import { Middleware, RouteHandler, Route, HandlerResponse } from './interfaces/index.js';
1
+ import { Middleware, RouteHandler, Route, RequestType, ResponseType, HandlerResponse } from './interfaces/index.js';
2
+ import 'node:http';
3
+ import 'node:http2';
4
+ import 'node:https';
3
5
 
4
6
  /**
5
7
  * Router class to manage routes and middleware
@@ -54,7 +56,7 @@ declare class Router {
54
56
  /**
55
57
  * Handle a request and find the matching route
56
58
  */
57
- handle(req: http.IncomingMessage, res: http.ServerResponse): Promise<HandlerResponse | null>;
59
+ handle(req: RequestType, res: ResponseType): Promise<HandlerResponse | null>;
58
60
  /**
59
61
  * Execute middleware chain and final handler
60
62
  */
@@ -6,11 +6,12 @@ import {
6
6
  } from "./chunk-KJT4SET2.mjs";
7
7
  import {
8
8
  configDefaults
9
- } from "./chunk-NSHBEU32.mjs";
9
+ } from "./chunk-JJX5XRNB.mjs";
10
10
 
11
11
  // src/MikroServe.ts
12
12
  import { readFileSync } from "node:fs";
13
13
  import http from "node:http";
14
+ import http2 from "node:http2";
14
15
  import https from "node:https";
15
16
  import { MikroConf, parsers } from "mikroconf";
16
17
  var MikroServe = class {
@@ -29,6 +30,7 @@ var MikroServe = class {
29
30
  { flag: "--port", path: "port", defaultValue: defaults.port },
30
31
  { flag: "--host", path: "host", defaultValue: defaults.host },
31
32
  { flag: "--https", path: "useHttps", defaultValue: defaults.useHttps, isFlag: true },
33
+ { flag: "--http2", path: "useHttp2", defaultValue: defaults.useHttp2, isFlag: true },
32
34
  { flag: "--cert", path: "sslCert", defaultValue: defaults.sslCert },
33
35
  { flag: "--key", path: "sslKey", defaultValue: defaults.sslKey },
34
36
  { flag: "--ca", path: "sslCa", defaultValue: defaults.sslCa },
@@ -130,7 +132,22 @@ var MikroServe = class {
130
132
  */
131
133
  createServer() {
132
134
  const boundRequestHandler = this.requestHandler.bind(this);
133
- if (this.config.useHttps) {
135
+ if (this.config.useHttp2) {
136
+ if (!this.config.sslCert || !this.config.sslKey)
137
+ throw new Error("SSL certificate and key paths are required when useHttp2 is true");
138
+ try {
139
+ const httpsOptions = {
140
+ key: readFileSync(this.config.sslKey),
141
+ cert: readFileSync(this.config.sslCert),
142
+ ...this.config.sslCa ? { ca: readFileSync(this.config.sslCa) } : {}
143
+ };
144
+ return http2.createSecureServer(httpsOptions, boundRequestHandler);
145
+ } catch (error) {
146
+ if (error.message.includes("key values mismatch"))
147
+ throw new Error(`SSL certificate and key do not match: ${error.message}`);
148
+ throw error;
149
+ }
150
+ } else if (this.config.useHttps) {
134
151
  if (!this.config.sslCert || !this.config.sslKey)
135
152
  throw new Error("SSL certificate and key paths are required when useHttps is true");
136
153
  try {
@@ -184,8 +201,14 @@ var MikroServe = class {
184
201
  this.setSecurityHeaders(res, this.config.useHttps);
185
202
  if (isDebug) console.log(`${method} ${url}`);
186
203
  if (req.method === "OPTIONS") {
187
- res.statusCode = 204;
188
- res.end();
204
+ if (res instanceof http.ServerResponse) {
205
+ res.statusCode = 204;
206
+ res.end();
207
+ } else {
208
+ const h2Res = res;
209
+ h2Res.writeHead(204);
210
+ h2Res.end();
211
+ }
189
212
  return;
190
213
  }
191
214
  try {
@@ -310,14 +333,25 @@ var MikroServe = class {
310
333
  * @description Set security headers.
311
334
  */
312
335
  setSecurityHeaders(res, isHttps = false) {
313
- res.setHeader("X-Content-Type-Options", "nosniff");
314
- res.setHeader("X-Frame-Options", "DENY");
315
- res.setHeader(
316
- "Content-Security-Policy",
317
- "default-src 'self'; script-src 'self'; object-src 'none'"
318
- );
319
- if (isHttps) res.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
320
- res.setHeader("X-XSS-Protection", "1; mode=block");
336
+ const securityHeaders = {
337
+ "X-Content-Type-Options": "nosniff",
338
+ "X-Frame-Options": "DENY",
339
+ "Content-Security-Policy": "default-src 'self'; script-src 'self'; object-src 'none'",
340
+ "X-XSS-Protection": "1; mode=block"
341
+ };
342
+ if (isHttps || this.config.useHttp2) {
343
+ securityHeaders["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains";
344
+ }
345
+ if (res instanceof http.ServerResponse) {
346
+ Object.entries(securityHeaders).forEach(([name, value]) => {
347
+ res.setHeader(name, value);
348
+ });
349
+ } else {
350
+ const h2Res = res;
351
+ Object.entries(securityHeaders).forEach(([name, value]) => {
352
+ h2Res.setHeader(name, value);
353
+ });
354
+ }
321
355
  }
322
356
  /**
323
357
  * @description Sends a response with appropriate headers.
@@ -326,10 +360,21 @@ var MikroServe = class {
326
360
  const headers = {
327
361
  ...response.headers || {}
328
362
  };
329
- res.writeHead(response.statusCode, headers);
330
- if (response.body === null || response.body === void 0) res.end();
331
- else if (typeof response.body === "string") res.end(response.body);
332
- else res.end(JSON.stringify(response.body));
363
+ const hasWriteHead = (res2) => {
364
+ return typeof res2.writeHead === "function" && typeof res2.end === "function";
365
+ };
366
+ if (hasWriteHead(res)) {
367
+ res.writeHead(response.statusCode, headers);
368
+ if (response.body === null || response.body === void 0) res.end();
369
+ else if (typeof response.body === "string") res.end(response.body);
370
+ else res.end(JSON.stringify(response.body));
371
+ } else {
372
+ console.warn("Unexpected response object type without writeHead/end methods");
373
+ res.writeHead?.(response.statusCode, headers);
374
+ if (response.body === null || response.body === void 0) res.end?.();
375
+ else if (typeof response.body === "string") res.end?.(response.body);
376
+ else res.end?.(JSON.stringify(response.body));
377
+ }
333
378
  }
334
379
  /**
335
380
  * @description Sets up graceful shutdown handlers for a server.
@@ -1,13 +1,10 @@
1
- import {
2
- getTruthyValue
3
- } from "./chunk-6HESV5Q6.mjs";
4
-
5
1
  // src/utils/configDefaults.ts
6
2
  var configDefaults = () => {
7
3
  return {
8
4
  port: Number(process.env.PORT) || 3e3,
9
5
  host: process.env.HOST || "0.0.0.0",
10
6
  useHttps: false,
7
+ useHttp2: false,
11
8
  sslCert: "",
12
9
  sslKey: "",
13
10
  sslCa: "",
@@ -25,6 +22,7 @@ var getDefaultConfig = () => {
25
22
  port: defaults.port,
26
23
  host: defaults.host,
27
24
  useHttps: defaults.useHttps,
25
+ useHttp2: defaults.useHttp2,
28
26
  sslCert: defaults.sslCert,
29
27
  sslKey: defaults.sslKey,
30
28
  sslCa: defaults.sslCa,
@@ -36,6 +34,10 @@ var getDefaultConfig = () => {
36
34
  allowedDomains: defaults.allowedDomains
37
35
  };
38
36
  };
37
+ function getTruthyValue(value) {
38
+ if (value === "true" || value === true) return true;
39
+ return false;
40
+ }
39
41
 
40
42
  export {
41
43
  configDefaults,
package/lib/index.d.mts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { MikroServe } from './MikroServe.mjs';
2
2
  export { Context } from './interfaces/index.mjs';
3
3
  import 'node:http';
4
+ import 'node:http2';
4
5
  import 'node:https';
package/lib/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { MikroServe } from './MikroServe.js';
2
2
  export { Context } from './interfaces/index.js';
3
3
  import 'node:http';
4
+ import 'node:http2';
4
5
  import 'node:https';
package/lib/index.js CHANGED
@@ -37,6 +37,7 @@ module.exports = __toCommonJS(index_exports);
37
37
  // src/MikroServe.ts
38
38
  var import_node_fs = require("fs");
39
39
  var import_node_http = __toESM(require("http"));
40
+ var import_node_http2 = __toESM(require("http2"));
40
41
  var import_node_https = __toESM(require("https"));
41
42
  var import_mikroconf = require("mikroconf");
42
43
 
@@ -283,18 +284,13 @@ var Router = class {
283
284
  }
284
285
  };
285
286
 
286
- // src/utils/getTruthyValue.ts
287
- function getTruthyValue(value) {
288
- if (value === "true" || value === true) return true;
289
- return false;
290
- }
291
-
292
287
  // src/utils/configDefaults.ts
293
288
  var configDefaults = () => {
294
289
  return {
295
290
  port: Number(process.env.PORT) || 3e3,
296
291
  host: process.env.HOST || "0.0.0.0",
297
292
  useHttps: false,
293
+ useHttp2: false,
298
294
  sslCert: "",
299
295
  sslKey: "",
300
296
  sslCa: "",
@@ -306,6 +302,10 @@ var configDefaults = () => {
306
302
  allowedDomains: ["*"]
307
303
  };
308
304
  };
305
+ function getTruthyValue(value) {
306
+ if (value === "true" || value === true) return true;
307
+ return false;
308
+ }
309
309
 
310
310
  // src/MikroServe.ts
311
311
  var MikroServe = class {
@@ -324,6 +324,7 @@ var MikroServe = class {
324
324
  { flag: "--port", path: "port", defaultValue: defaults.port },
325
325
  { flag: "--host", path: "host", defaultValue: defaults.host },
326
326
  { flag: "--https", path: "useHttps", defaultValue: defaults.useHttps, isFlag: true },
327
+ { flag: "--http2", path: "useHttp2", defaultValue: defaults.useHttp2, isFlag: true },
327
328
  { flag: "--cert", path: "sslCert", defaultValue: defaults.sslCert },
328
329
  { flag: "--key", path: "sslKey", defaultValue: defaults.sslKey },
329
330
  { flag: "--ca", path: "sslCa", defaultValue: defaults.sslCa },
@@ -425,7 +426,22 @@ var MikroServe = class {
425
426
  */
426
427
  createServer() {
427
428
  const boundRequestHandler = this.requestHandler.bind(this);
428
- if (this.config.useHttps) {
429
+ if (this.config.useHttp2) {
430
+ if (!this.config.sslCert || !this.config.sslKey)
431
+ throw new Error("SSL certificate and key paths are required when useHttp2 is true");
432
+ try {
433
+ const httpsOptions = {
434
+ key: (0, import_node_fs.readFileSync)(this.config.sslKey),
435
+ cert: (0, import_node_fs.readFileSync)(this.config.sslCert),
436
+ ...this.config.sslCa ? { ca: (0, import_node_fs.readFileSync)(this.config.sslCa) } : {}
437
+ };
438
+ return import_node_http2.default.createSecureServer(httpsOptions, boundRequestHandler);
439
+ } catch (error) {
440
+ if (error.message.includes("key values mismatch"))
441
+ throw new Error(`SSL certificate and key do not match: ${error.message}`);
442
+ throw error;
443
+ }
444
+ } else if (this.config.useHttps) {
429
445
  if (!this.config.sslCert || !this.config.sslKey)
430
446
  throw new Error("SSL certificate and key paths are required when useHttps is true");
431
447
  try {
@@ -479,8 +495,14 @@ var MikroServe = class {
479
495
  this.setSecurityHeaders(res, this.config.useHttps);
480
496
  if (isDebug) console.log(`${method} ${url}`);
481
497
  if (req.method === "OPTIONS") {
482
- res.statusCode = 204;
483
- res.end();
498
+ if (res instanceof import_node_http.default.ServerResponse) {
499
+ res.statusCode = 204;
500
+ res.end();
501
+ } else {
502
+ const h2Res = res;
503
+ h2Res.writeHead(204);
504
+ h2Res.end();
505
+ }
484
506
  return;
485
507
  }
486
508
  try {
@@ -605,14 +627,25 @@ var MikroServe = class {
605
627
  * @description Set security headers.
606
628
  */
607
629
  setSecurityHeaders(res, isHttps = false) {
608
- res.setHeader("X-Content-Type-Options", "nosniff");
609
- res.setHeader("X-Frame-Options", "DENY");
610
- res.setHeader(
611
- "Content-Security-Policy",
612
- "default-src 'self'; script-src 'self'; object-src 'none'"
613
- );
614
- if (isHttps) res.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
615
- res.setHeader("X-XSS-Protection", "1; mode=block");
630
+ const securityHeaders = {
631
+ "X-Content-Type-Options": "nosniff",
632
+ "X-Frame-Options": "DENY",
633
+ "Content-Security-Policy": "default-src 'self'; script-src 'self'; object-src 'none'",
634
+ "X-XSS-Protection": "1; mode=block"
635
+ };
636
+ if (isHttps || this.config.useHttp2) {
637
+ securityHeaders["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains";
638
+ }
639
+ if (res instanceof import_node_http.default.ServerResponse) {
640
+ Object.entries(securityHeaders).forEach(([name, value]) => {
641
+ res.setHeader(name, value);
642
+ });
643
+ } else {
644
+ const h2Res = res;
645
+ Object.entries(securityHeaders).forEach(([name, value]) => {
646
+ h2Res.setHeader(name, value);
647
+ });
648
+ }
616
649
  }
617
650
  /**
618
651
  * @description Sends a response with appropriate headers.
@@ -621,10 +654,21 @@ var MikroServe = class {
621
654
  const headers = {
622
655
  ...response.headers || {}
623
656
  };
624
- res.writeHead(response.statusCode, headers);
625
- if (response.body === null || response.body === void 0) res.end();
626
- else if (typeof response.body === "string") res.end(response.body);
627
- else res.end(JSON.stringify(response.body));
657
+ const hasWriteHead = (res2) => {
658
+ return typeof res2.writeHead === "function" && typeof res2.end === "function";
659
+ };
660
+ if (hasWriteHead(res)) {
661
+ res.writeHead(response.statusCode, headers);
662
+ if (response.body === null || response.body === void 0) res.end();
663
+ else if (typeof response.body === "string") res.end(response.body);
664
+ else res.end(JSON.stringify(response.body));
665
+ } else {
666
+ console.warn("Unexpected response object type without writeHead/end methods");
667
+ res.writeHead?.(response.statusCode, headers);
668
+ if (response.body === null || response.body === void 0) res.end?.();
669
+ else if (typeof response.body === "string") res.end?.(response.body);
670
+ else res.end?.(JSON.stringify(response.body));
671
+ }
628
672
  }
629
673
  /**
630
674
  * @description Sets up graceful shutdown handlers for a server.
package/lib/index.mjs CHANGED
@@ -1,10 +1,9 @@
1
1
  import {
2
2
  MikroServe
3
- } from "./chunk-E3RGQ7QF.mjs";
3
+ } from "./chunk-J2WPHNMW.mjs";
4
4
  import "./chunk-ZFBBESGU.mjs";
5
5
  import "./chunk-KJT4SET2.mjs";
6
- import "./chunk-NSHBEU32.mjs";
7
- import "./chunk-6HESV5Q6.mjs";
6
+ import "./chunk-JJX5XRNB.mjs";
8
7
  export {
9
8
  MikroServe
10
9
  };
@@ -1,4 +1,6 @@
1
1
  import http from 'node:http';
2
+ import http2 from 'node:http2';
3
+ import https from 'node:https';
2
4
 
3
5
  /**
4
6
  * @description Server configuration options.
@@ -21,6 +23,11 @@ type MikroServeConfiguration = {
21
23
  * @default false
22
24
  */
23
25
  useHttps: boolean;
26
+ /**
27
+ * Should the server use HTTP2?
28
+ * @default false
29
+ */
30
+ useHttp2: boolean;
24
31
  /**
25
32
  * The path to the SSL certificate.
26
33
  * @default '''
@@ -82,12 +89,12 @@ interface ResponseHelpers {
82
89
  * @description Context object passed to route handlers.
83
90
  */
84
91
  interface Context extends ResponseHelpers {
85
- req: http.IncomingMessage;
86
- res: http.ServerResponse;
92
+ req: http.IncomingMessage | http2.Http2ServerRequest;
93
+ res: http.ServerResponse | http2.Http2ServerResponse;
87
94
  params: Record<string, string>;
88
95
  query: Record<string, string>;
89
96
  body: any;
90
- headers: http.IncomingHttpHeaders;
97
+ headers: http.IncomingHttpHeaders | http2.IncomingHttpHeaders;
91
98
  path: string;
92
99
  state: Record<string, any>;
93
100
  }
@@ -124,5 +131,13 @@ interface PathPattern {
124
131
  pattern: RegExp;
125
132
  paramNames: string[];
126
133
  }
134
+ type ServerType = http.Server | https.Server | http2.Http2Server | http2.Http2SecureServer;
135
+ type RequestType = http.IncomingMessage | http2.Http2ServerRequest;
136
+ type ResponseType = http.ServerResponse | http2.Http2ServerResponse | {
137
+ setHeader: (name: string, value: string) => void;
138
+ getHeaders?: () => Record<string, string | string[] | number>;
139
+ writeHead: (statusCode: number, headers: Record<string, string | string[] | number>) => void;
140
+ statusCode?: number;
141
+ };
127
142
 
128
- export type { Context, HandlerResponse, Middleware, MikroServeConfiguration, MikroServeOptions, PathPattern, ResponseHelpers, Route, RouteHandler };
143
+ export type { Context, HandlerResponse, Middleware, MikroServeConfiguration, MikroServeOptions, PathPattern, RequestType, ResponseHelpers, ResponseType, Route, RouteHandler, ServerType };
@@ -1,4 +1,6 @@
1
1
  import http from 'node:http';
2
+ import http2 from 'node:http2';
3
+ import https from 'node:https';
2
4
 
3
5
  /**
4
6
  * @description Server configuration options.
@@ -21,6 +23,11 @@ type MikroServeConfiguration = {
21
23
  * @default false
22
24
  */
23
25
  useHttps: boolean;
26
+ /**
27
+ * Should the server use HTTP2?
28
+ * @default false
29
+ */
30
+ useHttp2: boolean;
24
31
  /**
25
32
  * The path to the SSL certificate.
26
33
  * @default '''
@@ -82,12 +89,12 @@ interface ResponseHelpers {
82
89
  * @description Context object passed to route handlers.
83
90
  */
84
91
  interface Context extends ResponseHelpers {
85
- req: http.IncomingMessage;
86
- res: http.ServerResponse;
92
+ req: http.IncomingMessage | http2.Http2ServerRequest;
93
+ res: http.ServerResponse | http2.Http2ServerResponse;
87
94
  params: Record<string, string>;
88
95
  query: Record<string, string>;
89
96
  body: any;
90
- headers: http.IncomingHttpHeaders;
97
+ headers: http.IncomingHttpHeaders | http2.IncomingHttpHeaders;
91
98
  path: string;
92
99
  state: Record<string, any>;
93
100
  }
@@ -124,5 +131,13 @@ interface PathPattern {
124
131
  pattern: RegExp;
125
132
  paramNames: string[];
126
133
  }
134
+ type ServerType = http.Server | https.Server | http2.Http2Server | http2.Http2SecureServer;
135
+ type RequestType = http.IncomingMessage | http2.Http2ServerRequest;
136
+ type ResponseType = http.ServerResponse | http2.Http2ServerResponse | {
137
+ setHeader: (name: string, value: string) => void;
138
+ getHeaders?: () => Record<string, string | string[] | number>;
139
+ writeHead: (statusCode: number, headers: Record<string, string | string[] | number>) => void;
140
+ statusCode?: number;
141
+ };
127
142
 
128
- export type { Context, HandlerResponse, Middleware, MikroServeConfiguration, MikroServeOptions, PathPattern, ResponseHelpers, Route, RouteHandler };
143
+ export type { Context, HandlerResponse, Middleware, MikroServeConfiguration, MikroServeOptions, PathPattern, RequestType, ResponseHelpers, ResponseType, Route, RouteHandler, ServerType };
@@ -1,11 +1,14 @@
1
1
  import { MikroServeConfiguration } from '../interfaces/index.mjs';
2
2
  import 'node:http';
3
+ import 'node:http2';
4
+ import 'node:https';
3
5
 
4
6
  declare const configDefaults: () => MikroServeConfiguration;
5
7
  declare const getDefaultConfig: () => {
6
8
  port: number;
7
9
  host: string;
8
10
  useHttps: boolean;
11
+ useHttp2: boolean;
9
12
  sslCert: string;
10
13
  sslKey: string;
11
14
  sslCa: string;
@@ -1,11 +1,14 @@
1
1
  import { MikroServeConfiguration } from '../interfaces/index.js';
2
2
  import 'node:http';
3
+ import 'node:http2';
4
+ import 'node:https';
3
5
 
4
6
  declare const configDefaults: () => MikroServeConfiguration;
5
7
  declare const getDefaultConfig: () => {
6
8
  port: number;
7
9
  host: string;
8
10
  useHttps: boolean;
11
+ useHttp2: boolean;
9
12
  sslCert: string;
10
13
  sslKey: string;
11
14
  sslCa: string;
@@ -24,19 +24,12 @@ __export(configDefaults_exports, {
24
24
  getDefaultConfig: () => getDefaultConfig
25
25
  });
26
26
  module.exports = __toCommonJS(configDefaults_exports);
27
-
28
- // src/utils/getTruthyValue.ts
29
- function getTruthyValue(value) {
30
- if (value === "true" || value === true) return true;
31
- return false;
32
- }
33
-
34
- // src/utils/configDefaults.ts
35
27
  var configDefaults = () => {
36
28
  return {
37
29
  port: Number(process.env.PORT) || 3e3,
38
30
  host: process.env.HOST || "0.0.0.0",
39
31
  useHttps: false,
32
+ useHttp2: false,
40
33
  sslCert: "",
41
34
  sslKey: "",
42
35
  sslCa: "",
@@ -54,6 +47,7 @@ var getDefaultConfig = () => {
54
47
  port: defaults.port,
55
48
  host: defaults.host,
56
49
  useHttps: defaults.useHttps,
50
+ useHttp2: defaults.useHttp2,
57
51
  sslCert: defaults.sslCert,
58
52
  sslKey: defaults.sslKey,
59
53
  sslCa: defaults.sslCa,
@@ -65,6 +59,10 @@ var getDefaultConfig = () => {
65
59
  allowedDomains: defaults.allowedDomains
66
60
  };
67
61
  };
62
+ function getTruthyValue(value) {
63
+ if (value === "true" || value === true) return true;
64
+ return false;
65
+ }
68
66
  // Annotate the CommonJS export names for ESM import in node:
69
67
  0 && (module.exports = {
70
68
  configDefaults,
@@ -1,8 +1,7 @@
1
1
  import {
2
2
  configDefaults,
3
3
  getDefaultConfig
4
- } from "../chunk-NSHBEU32.mjs";
5
- import "../chunk-6HESV5Q6.mjs";
4
+ } from "../chunk-JJX5XRNB.mjs";
6
5
  export {
7
6
  configDefaults,
8
7
  getDefaultConfig
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mikroserve",
3
3
  "description": "Minimalistic, ready-to-use API, built on Node.js primitives.",
4
- "version": "0.0.6",
4
+ "version": "0.0.7",
5
5
  "author": "Mikael Vesavuori",
6
6
  "license": "MIT",
7
7
  "keywords": [
@@ -61,6 +61,6 @@
61
61
  "vitest": "2"
62
62
  },
63
63
  "dependencies": {
64
- "mikroconf": "^0.0.2"
64
+ "mikroconf": "latest"
65
65
  }
66
66
  }
@@ -1,9 +0,0 @@
1
- // src/utils/getTruthyValue.ts
2
- function getTruthyValue(value) {
3
- if (value === "true" || value === true) return true;
4
- return false;
5
- }
6
-
7
- export {
8
- getTruthyValue
9
- };
@@ -1,6 +0,0 @@
1
- /**
2
- * @description Check if a value is a boolean or stringly "true".
3
- */
4
- declare function getTruthyValue(value: string | boolean | undefined): boolean;
5
-
6
- export { getTruthyValue };
@@ -1,6 +0,0 @@
1
- /**
2
- * @description Check if a value is a boolean or stringly "true".
3
- */
4
- declare function getTruthyValue(value: string | boolean | undefined): boolean;
5
-
6
- export { getTruthyValue };
@@ -1,33 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/utils/getTruthyValue.ts
21
- var getTruthyValue_exports = {};
22
- __export(getTruthyValue_exports, {
23
- getTruthyValue: () => getTruthyValue
24
- });
25
- module.exports = __toCommonJS(getTruthyValue_exports);
26
- function getTruthyValue(value) {
27
- if (value === "true" || value === true) return true;
28
- return false;
29
- }
30
- // Annotate the CommonJS export names for ESM import in node:
31
- 0 && (module.exports = {
32
- getTruthyValue
33
- });
@@ -1,6 +0,0 @@
1
- import {
2
- getTruthyValue
3
- } from "../chunk-6HESV5Q6.mjs";
4
- export {
5
- getTruthyValue
6
- };