mikroserve 0.0.6 → 0.0.8

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.
@@ -3,16 +3,20 @@ import {
3
3
  } from "./chunk-ZFBBESGU.mjs";
4
4
  import {
5
5
  Router
6
- } from "./chunk-KJT4SET2.mjs";
6
+ } from "./chunk-GUYBTPZH.mjs";
7
+ import {
8
+ baseConfig
9
+ } from "./chunk-YOHL3T54.mjs";
7
10
  import {
8
11
  configDefaults
9
- } from "./chunk-NSHBEU32.mjs";
12
+ } from "./chunk-JJX5XRNB.mjs";
10
13
 
11
14
  // src/MikroServe.ts
12
15
  import { readFileSync } from "node:fs";
13
16
  import http from "node:http";
17
+ import http2 from "node:http2";
14
18
  import https from "node:https";
15
- import { MikroConf, parsers } from "mikroconf";
19
+ import { MikroConf } from "mikroconf";
16
20
  var MikroServe = class {
17
21
  config;
18
22
  rateLimiter;
@@ -21,42 +25,11 @@ var MikroServe = class {
21
25
  * @description Creates a new MikroServe instance.
22
26
  */
23
27
  constructor(options) {
24
- const defaults = configDefaults();
25
- const config = new MikroConf({
26
- configFilePath: "mikroserve.config.json",
27
- args: process.argv,
28
- options: [
29
- { flag: "--port", path: "port", defaultValue: defaults.port },
30
- { flag: "--host", path: "host", defaultValue: defaults.host },
31
- { flag: "--https", path: "useHttps", defaultValue: defaults.useHttps, isFlag: true },
32
- { flag: "--cert", path: "sslCert", defaultValue: defaults.sslCert },
33
- { flag: "--key", path: "sslKey", defaultValue: defaults.sslKey },
34
- { flag: "--ca", path: "sslCa", defaultValue: defaults.sslCa },
35
- {
36
- flag: "--ratelimit",
37
- path: "rateLimit.enabled",
38
- defaultValue: defaults.rateLimit.enabled,
39
- isFlag: true
40
- },
41
- {
42
- flag: "--rps",
43
- path: "rateLimit.requestsPerMinute",
44
- defaultValue: defaults.rateLimit.requestsPerMinute
45
- },
46
- {
47
- flag: "--allowed",
48
- path: "allowedDomains",
49
- defaultValue: defaults.allowedDomains,
50
- parser: parsers.array
51
- },
52
- { flag: "--debug", path: "debug", defaultValue: defaults.debug, isFlag: true }
53
- ],
54
- config: options
55
- }).get();
28
+ const config = new MikroConf(baseConfig(options || {})).get();
56
29
  if (config.debug) console.log("Using configuration:", config);
57
30
  this.config = config;
58
31
  this.router = new Router();
59
- const requestsPerMinute = config.rateLimit.requestsPerMinute || defaults.rateLimit.requestsPerMinute;
32
+ const requestsPerMinute = config.rateLimit.requestsPerMinute || configDefaults().rateLimit.requestsPerMinute;
60
33
  this.rateLimiter = new RateLimiter(requestsPerMinute, 60);
61
34
  if (config.rateLimit.enabled === true) this.use(this.rateLimitMiddleware.bind(this));
62
35
  }
@@ -130,7 +103,22 @@ var MikroServe = class {
130
103
  */
131
104
  createServer() {
132
105
  const boundRequestHandler = this.requestHandler.bind(this);
133
- if (this.config.useHttps) {
106
+ if (this.config.useHttp2) {
107
+ if (!this.config.sslCert || !this.config.sslKey)
108
+ throw new Error("SSL certificate and key paths are required when useHttp2 is true");
109
+ try {
110
+ const httpsOptions = {
111
+ key: readFileSync(this.config.sslKey),
112
+ cert: readFileSync(this.config.sslCert),
113
+ ...this.config.sslCa ? { ca: readFileSync(this.config.sslCa) } : {}
114
+ };
115
+ return http2.createSecureServer(httpsOptions, boundRequestHandler);
116
+ } catch (error) {
117
+ if (error.message.includes("key values mismatch"))
118
+ throw new Error(`SSL certificate and key do not match: ${error.message}`);
119
+ throw error;
120
+ }
121
+ } else if (this.config.useHttps) {
134
122
  if (!this.config.sslCert || !this.config.sslKey)
135
123
  throw new Error("SSL certificate and key paths are required when useHttps is true");
136
124
  try {
@@ -184,8 +172,14 @@ var MikroServe = class {
184
172
  this.setSecurityHeaders(res, this.config.useHttps);
185
173
  if (isDebug) console.log(`${method} ${url}`);
186
174
  if (req.method === "OPTIONS") {
187
- res.statusCode = 204;
188
- res.end();
175
+ if (res instanceof http.ServerResponse) {
176
+ res.statusCode = 204;
177
+ res.end();
178
+ } else {
179
+ const h2Res = res;
180
+ h2Res.writeHead(204);
181
+ h2Res.end();
182
+ }
189
183
  return;
190
184
  }
191
185
  try {
@@ -310,14 +304,24 @@ var MikroServe = class {
310
304
  * @description Set security headers.
311
305
  */
312
306
  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");
307
+ const securityHeaders = {
308
+ "X-Content-Type-Options": "nosniff",
309
+ "X-Frame-Options": "DENY",
310
+ "Content-Security-Policy": "default-src 'self'; script-src 'self'; object-src 'none'",
311
+ "X-XSS-Protection": "1; mode=block"
312
+ };
313
+ if (isHttps || this.config.useHttp2)
314
+ securityHeaders["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains";
315
+ if (res instanceof http.ServerResponse) {
316
+ Object.entries(securityHeaders).forEach(([name, value]) => {
317
+ res.setHeader(name, value);
318
+ });
319
+ } else {
320
+ const h2Res = res;
321
+ Object.entries(securityHeaders).forEach(([name, value]) => {
322
+ h2Res.setHeader(name, value);
323
+ });
324
+ }
321
325
  }
322
326
  /**
323
327
  * @description Sends a response with appropriate headers.
@@ -326,10 +330,23 @@ var MikroServe = class {
326
330
  const headers = {
327
331
  ...response.headers || {}
328
332
  };
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));
333
+ const hasWriteHead = (res2) => {
334
+ return typeof res2.writeHead === "function" && typeof res2.end === "function";
335
+ };
336
+ if (hasWriteHead(res)) {
337
+ res.writeHead(response.statusCode, headers);
338
+ if (response.body === null || response.body === void 0) res.end();
339
+ else if (response.isRaw) res.end(response.body);
340
+ else if (typeof response.body === "string") res.end(response.body);
341
+ else res.end(JSON.stringify(response.body));
342
+ } else {
343
+ console.warn("Unexpected response object type without writeHead/end methods");
344
+ res.writeHead?.(response.statusCode, headers);
345
+ if (response.body === null || response.body === void 0) res.end?.();
346
+ else if (response.isRaw) res.end?.(response.body);
347
+ else if (typeof response.body === "string") res.end?.(response.body);
348
+ else res.end?.(JSON.stringify(response.body));
349
+ }
333
350
  }
334
351
  /**
335
352
  * @description Sets up graceful shutdown handlers for a server.
@@ -0,0 +1,43 @@
1
+ import {
2
+ configDefaults
3
+ } from "./chunk-JJX5XRNB.mjs";
4
+
5
+ // src/config.ts
6
+ import { parsers } from "mikroconf";
7
+ var defaults = configDefaults();
8
+ var baseConfig = (options) => ({
9
+ configFilePath: "mikroserve.config.json",
10
+ args: process.argv,
11
+ options: [
12
+ { flag: "--port", path: "port", defaultValue: defaults.port },
13
+ { flag: "--host", path: "host", defaultValue: defaults.host },
14
+ { flag: "--https", path: "useHttps", defaultValue: defaults.useHttps, isFlag: true },
15
+ { flag: "--http2", path: "useHttp2", defaultValue: defaults.useHttp2, isFlag: true },
16
+ { flag: "--cert", path: "sslCert", defaultValue: defaults.sslCert },
17
+ { flag: "--key", path: "sslKey", defaultValue: defaults.sslKey },
18
+ { flag: "--ca", path: "sslCa", defaultValue: defaults.sslCa },
19
+ {
20
+ flag: "--ratelimit",
21
+ path: "rateLimit.enabled",
22
+ defaultValue: defaults.rateLimit.enabled,
23
+ isFlag: true
24
+ },
25
+ {
26
+ flag: "--rps",
27
+ path: "rateLimit.requestsPerMinute",
28
+ defaultValue: defaults.rateLimit.requestsPerMinute
29
+ },
30
+ {
31
+ flag: "--allowed",
32
+ path: "allowedDomains",
33
+ defaultValue: defaults.allowedDomains,
34
+ parser: parsers.array
35
+ },
36
+ { flag: "--debug", path: "debug", defaultValue: defaults.debug, isFlag: true }
37
+ ],
38
+ config: options
39
+ });
40
+
41
+ export {
42
+ baseConfig
43
+ };
@@ -0,0 +1,37 @@
1
+ import { MikroServeOptions, MikroServeConfiguration } from './interfaces/index.mjs';
2
+ import 'node:http';
3
+ import 'node:http2';
4
+ import 'node:https';
5
+
6
+ declare const baseConfig: (options: MikroServeOptions) => {
7
+ configFilePath: string;
8
+ args: string[];
9
+ options: ({
10
+ flag: string;
11
+ path: string;
12
+ defaultValue: number;
13
+ isFlag?: undefined;
14
+ parser?: undefined;
15
+ } | {
16
+ flag: string;
17
+ path: string;
18
+ defaultValue: string;
19
+ isFlag?: undefined;
20
+ parser?: undefined;
21
+ } | {
22
+ flag: string;
23
+ path: string;
24
+ defaultValue: boolean;
25
+ isFlag: boolean;
26
+ parser?: undefined;
27
+ } | {
28
+ flag: string;
29
+ path: string;
30
+ defaultValue: string[];
31
+ parser: (value: string) => string[];
32
+ isFlag?: undefined;
33
+ })[];
34
+ config: Partial<MikroServeConfiguration>;
35
+ };
36
+
37
+ export { baseConfig };
@@ -0,0 +1,37 @@
1
+ import { MikroServeOptions, MikroServeConfiguration } from './interfaces/index.js';
2
+ import 'node:http';
3
+ import 'node:http2';
4
+ import 'node:https';
5
+
6
+ declare const baseConfig: (options: MikroServeOptions) => {
7
+ configFilePath: string;
8
+ args: string[];
9
+ options: ({
10
+ flag: string;
11
+ path: string;
12
+ defaultValue: number;
13
+ isFlag?: undefined;
14
+ parser?: undefined;
15
+ } | {
16
+ flag: string;
17
+ path: string;
18
+ defaultValue: string;
19
+ isFlag?: undefined;
20
+ parser?: undefined;
21
+ } | {
22
+ flag: string;
23
+ path: string;
24
+ defaultValue: boolean;
25
+ isFlag: boolean;
26
+ parser?: undefined;
27
+ } | {
28
+ flag: string;
29
+ path: string;
30
+ defaultValue: string[];
31
+ parser: (value: string) => string[];
32
+ isFlag?: undefined;
33
+ })[];
34
+ config: Partial<MikroServeConfiguration>;
35
+ };
36
+
37
+ export { baseConfig };
package/lib/config.js ADDED
@@ -0,0 +1,88 @@
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/config.ts
21
+ var config_exports = {};
22
+ __export(config_exports, {
23
+ baseConfig: () => baseConfig
24
+ });
25
+ module.exports = __toCommonJS(config_exports);
26
+ var import_mikroconf = require("mikroconf");
27
+
28
+ // src/utils/configDefaults.ts
29
+ var configDefaults = () => {
30
+ return {
31
+ port: Number(process.env.PORT) || 3e3,
32
+ host: process.env.HOST || "0.0.0.0",
33
+ useHttps: false,
34
+ useHttp2: false,
35
+ sslCert: "",
36
+ sslKey: "",
37
+ sslCa: "",
38
+ debug: getTruthyValue(process.env.DEBUG) || false,
39
+ rateLimit: {
40
+ enabled: true,
41
+ requestsPerMinute: 100
42
+ },
43
+ allowedDomains: ["*"]
44
+ };
45
+ };
46
+ function getTruthyValue(value) {
47
+ if (value === "true" || value === true) return true;
48
+ return false;
49
+ }
50
+
51
+ // src/config.ts
52
+ var defaults = configDefaults();
53
+ var baseConfig = (options) => ({
54
+ configFilePath: "mikroserve.config.json",
55
+ args: process.argv,
56
+ options: [
57
+ { flag: "--port", path: "port", defaultValue: defaults.port },
58
+ { flag: "--host", path: "host", defaultValue: defaults.host },
59
+ { flag: "--https", path: "useHttps", defaultValue: defaults.useHttps, isFlag: true },
60
+ { flag: "--http2", path: "useHttp2", defaultValue: defaults.useHttp2, isFlag: true },
61
+ { flag: "--cert", path: "sslCert", defaultValue: defaults.sslCert },
62
+ { flag: "--key", path: "sslKey", defaultValue: defaults.sslKey },
63
+ { flag: "--ca", path: "sslCa", defaultValue: defaults.sslCa },
64
+ {
65
+ flag: "--ratelimit",
66
+ path: "rateLimit.enabled",
67
+ defaultValue: defaults.rateLimit.enabled,
68
+ isFlag: true
69
+ },
70
+ {
71
+ flag: "--rps",
72
+ path: "rateLimit.requestsPerMinute",
73
+ defaultValue: defaults.rateLimit.requestsPerMinute
74
+ },
75
+ {
76
+ flag: "--allowed",
77
+ path: "allowedDomains",
78
+ defaultValue: defaults.allowedDomains,
79
+ parser: import_mikroconf.parsers.array
80
+ },
81
+ { flag: "--debug", path: "debug", defaultValue: defaults.debug, isFlag: true }
82
+ ],
83
+ config: options
84
+ });
85
+ // Annotate the CommonJS export names for ESM import in node:
86
+ 0 && (module.exports = {
87
+ baseConfig
88
+ });
package/lib/config.mjs ADDED
@@ -0,0 +1,7 @@
1
+ import {
2
+ baseConfig
3
+ } from "./chunk-YOHL3T54.mjs";
4
+ import "./chunk-JJX5XRNB.mjs";
5
+ export {
6
+ baseConfig
7
+ };
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,8 +37,9 @@ 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
- var import_mikroconf = require("mikroconf");
42
+ var import_mikroconf2 = require("mikroconf");
42
43
 
43
44
  // src/RateLimiter.ts
44
45
  var RateLimiter = class {
@@ -207,6 +208,16 @@ var Router = class {
207
208
  path,
208
209
  state: {},
209
210
  // Add the missing state property
211
+ raw: () => res,
212
+ binary: (content, contentType = "application/octet-stream", status = 200) => ({
213
+ statusCode: status,
214
+ body: content,
215
+ headers: {
216
+ "Content-Type": contentType,
217
+ "Content-Length": content.length.toString()
218
+ },
219
+ isRaw: true
220
+ }),
210
221
  text: (content, status = 200) => ({
211
222
  statusCode: status,
212
223
  body: content,
@@ -234,6 +245,16 @@ var Router = class {
234
245
  }),
235
246
  status: function(code) {
236
247
  return {
248
+ raw: () => res,
249
+ binary: (content, contentType = "application/octet-stream") => ({
250
+ statusCode: code,
251
+ body: content,
252
+ headers: {
253
+ "Content-Type": contentType,
254
+ "Content-Length": content.length.toString()
255
+ },
256
+ isRaw: true
257
+ }),
237
258
  text: (content) => ({
238
259
  statusCode: code,
239
260
  body: content,
@@ -283,11 +304,8 @@ var Router = class {
283
304
  }
284
305
  };
285
306
 
286
- // src/utils/getTruthyValue.ts
287
- function getTruthyValue(value) {
288
- if (value === "true" || value === true) return true;
289
- return false;
290
- }
307
+ // src/config.ts
308
+ var import_mikroconf = require("mikroconf");
291
309
 
292
310
  // src/utils/configDefaults.ts
293
311
  var configDefaults = () => {
@@ -295,6 +313,7 @@ var configDefaults = () => {
295
313
  port: Number(process.env.PORT) || 3e3,
296
314
  host: process.env.HOST || "0.0.0.0",
297
315
  useHttps: false,
316
+ useHttp2: false,
298
317
  sslCert: "",
299
318
  sslKey: "",
300
319
  sslCa: "",
@@ -306,6 +325,45 @@ var configDefaults = () => {
306
325
  allowedDomains: ["*"]
307
326
  };
308
327
  };
328
+ function getTruthyValue(value) {
329
+ if (value === "true" || value === true) return true;
330
+ return false;
331
+ }
332
+
333
+ // src/config.ts
334
+ var defaults = configDefaults();
335
+ var baseConfig = (options) => ({
336
+ configFilePath: "mikroserve.config.json",
337
+ args: process.argv,
338
+ options: [
339
+ { flag: "--port", path: "port", defaultValue: defaults.port },
340
+ { flag: "--host", path: "host", defaultValue: defaults.host },
341
+ { flag: "--https", path: "useHttps", defaultValue: defaults.useHttps, isFlag: true },
342
+ { flag: "--http2", path: "useHttp2", defaultValue: defaults.useHttp2, isFlag: true },
343
+ { flag: "--cert", path: "sslCert", defaultValue: defaults.sslCert },
344
+ { flag: "--key", path: "sslKey", defaultValue: defaults.sslKey },
345
+ { flag: "--ca", path: "sslCa", defaultValue: defaults.sslCa },
346
+ {
347
+ flag: "--ratelimit",
348
+ path: "rateLimit.enabled",
349
+ defaultValue: defaults.rateLimit.enabled,
350
+ isFlag: true
351
+ },
352
+ {
353
+ flag: "--rps",
354
+ path: "rateLimit.requestsPerMinute",
355
+ defaultValue: defaults.rateLimit.requestsPerMinute
356
+ },
357
+ {
358
+ flag: "--allowed",
359
+ path: "allowedDomains",
360
+ defaultValue: defaults.allowedDomains,
361
+ parser: import_mikroconf.parsers.array
362
+ },
363
+ { flag: "--debug", path: "debug", defaultValue: defaults.debug, isFlag: true }
364
+ ],
365
+ config: options
366
+ });
309
367
 
310
368
  // src/MikroServe.ts
311
369
  var MikroServe = class {
@@ -316,42 +374,11 @@ var MikroServe = class {
316
374
  * @description Creates a new MikroServe instance.
317
375
  */
318
376
  constructor(options) {
319
- const defaults = configDefaults();
320
- const config = new import_mikroconf.MikroConf({
321
- configFilePath: "mikroserve.config.json",
322
- args: process.argv,
323
- options: [
324
- { flag: "--port", path: "port", defaultValue: defaults.port },
325
- { flag: "--host", path: "host", defaultValue: defaults.host },
326
- { flag: "--https", path: "useHttps", defaultValue: defaults.useHttps, isFlag: true },
327
- { flag: "--cert", path: "sslCert", defaultValue: defaults.sslCert },
328
- { flag: "--key", path: "sslKey", defaultValue: defaults.sslKey },
329
- { flag: "--ca", path: "sslCa", defaultValue: defaults.sslCa },
330
- {
331
- flag: "--ratelimit",
332
- path: "rateLimit.enabled",
333
- defaultValue: defaults.rateLimit.enabled,
334
- isFlag: true
335
- },
336
- {
337
- flag: "--rps",
338
- path: "rateLimit.requestsPerMinute",
339
- defaultValue: defaults.rateLimit.requestsPerMinute
340
- },
341
- {
342
- flag: "--allowed",
343
- path: "allowedDomains",
344
- defaultValue: defaults.allowedDomains,
345
- parser: import_mikroconf.parsers.array
346
- },
347
- { flag: "--debug", path: "debug", defaultValue: defaults.debug, isFlag: true }
348
- ],
349
- config: options
350
- }).get();
377
+ const config = new import_mikroconf2.MikroConf(baseConfig(options || {})).get();
351
378
  if (config.debug) console.log("Using configuration:", config);
352
379
  this.config = config;
353
380
  this.router = new Router();
354
- const requestsPerMinute = config.rateLimit.requestsPerMinute || defaults.rateLimit.requestsPerMinute;
381
+ const requestsPerMinute = config.rateLimit.requestsPerMinute || configDefaults().rateLimit.requestsPerMinute;
355
382
  this.rateLimiter = new RateLimiter(requestsPerMinute, 60);
356
383
  if (config.rateLimit.enabled === true) this.use(this.rateLimitMiddleware.bind(this));
357
384
  }
@@ -425,7 +452,22 @@ var MikroServe = class {
425
452
  */
426
453
  createServer() {
427
454
  const boundRequestHandler = this.requestHandler.bind(this);
428
- if (this.config.useHttps) {
455
+ if (this.config.useHttp2) {
456
+ if (!this.config.sslCert || !this.config.sslKey)
457
+ throw new Error("SSL certificate and key paths are required when useHttp2 is true");
458
+ try {
459
+ const httpsOptions = {
460
+ key: (0, import_node_fs.readFileSync)(this.config.sslKey),
461
+ cert: (0, import_node_fs.readFileSync)(this.config.sslCert),
462
+ ...this.config.sslCa ? { ca: (0, import_node_fs.readFileSync)(this.config.sslCa) } : {}
463
+ };
464
+ return import_node_http2.default.createSecureServer(httpsOptions, boundRequestHandler);
465
+ } catch (error) {
466
+ if (error.message.includes("key values mismatch"))
467
+ throw new Error(`SSL certificate and key do not match: ${error.message}`);
468
+ throw error;
469
+ }
470
+ } else if (this.config.useHttps) {
429
471
  if (!this.config.sslCert || !this.config.sslKey)
430
472
  throw new Error("SSL certificate and key paths are required when useHttps is true");
431
473
  try {
@@ -479,8 +521,14 @@ var MikroServe = class {
479
521
  this.setSecurityHeaders(res, this.config.useHttps);
480
522
  if (isDebug) console.log(`${method} ${url}`);
481
523
  if (req.method === "OPTIONS") {
482
- res.statusCode = 204;
483
- res.end();
524
+ if (res instanceof import_node_http.default.ServerResponse) {
525
+ res.statusCode = 204;
526
+ res.end();
527
+ } else {
528
+ const h2Res = res;
529
+ h2Res.writeHead(204);
530
+ h2Res.end();
531
+ }
484
532
  return;
485
533
  }
486
534
  try {
@@ -605,14 +653,24 @@ var MikroServe = class {
605
653
  * @description Set security headers.
606
654
  */
607
655
  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");
656
+ const securityHeaders = {
657
+ "X-Content-Type-Options": "nosniff",
658
+ "X-Frame-Options": "DENY",
659
+ "Content-Security-Policy": "default-src 'self'; script-src 'self'; object-src 'none'",
660
+ "X-XSS-Protection": "1; mode=block"
661
+ };
662
+ if (isHttps || this.config.useHttp2)
663
+ securityHeaders["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains";
664
+ if (res instanceof import_node_http.default.ServerResponse) {
665
+ Object.entries(securityHeaders).forEach(([name, value]) => {
666
+ res.setHeader(name, value);
667
+ });
668
+ } else {
669
+ const h2Res = res;
670
+ Object.entries(securityHeaders).forEach(([name, value]) => {
671
+ h2Res.setHeader(name, value);
672
+ });
673
+ }
616
674
  }
617
675
  /**
618
676
  * @description Sends a response with appropriate headers.
@@ -621,10 +679,23 @@ var MikroServe = class {
621
679
  const headers = {
622
680
  ...response.headers || {}
623
681
  };
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));
682
+ const hasWriteHead = (res2) => {
683
+ return typeof res2.writeHead === "function" && typeof res2.end === "function";
684
+ };
685
+ if (hasWriteHead(res)) {
686
+ res.writeHead(response.statusCode, headers);
687
+ if (response.body === null || response.body === void 0) res.end();
688
+ else if (response.isRaw) res.end(response.body);
689
+ else if (typeof response.body === "string") res.end(response.body);
690
+ else res.end(JSON.stringify(response.body));
691
+ } else {
692
+ console.warn("Unexpected response object type without writeHead/end methods");
693
+ res.writeHead?.(response.statusCode, headers);
694
+ if (response.body === null || response.body === void 0) res.end?.();
695
+ else if (response.isRaw) res.end?.(response.body);
696
+ else if (typeof response.body === "string") res.end?.(response.body);
697
+ else res.end?.(JSON.stringify(response.body));
698
+ }
628
699
  }
629
700
  /**
630
701
  * @description Sets up graceful shutdown handlers for a server.
package/lib/index.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  MikroServe
3
- } from "./chunk-E3RGQ7QF.mjs";
3
+ } from "./chunk-SLBFEKEH.mjs";
4
4
  import "./chunk-ZFBBESGU.mjs";
5
- import "./chunk-KJT4SET2.mjs";
6
- import "./chunk-NSHBEU32.mjs";
7
- import "./chunk-6HESV5Q6.mjs";
5
+ import "./chunk-GUYBTPZH.mjs";
6
+ import "./chunk-YOHL3T54.mjs";
7
+ import "./chunk-JJX5XRNB.mjs";
8
8
  export {
9
9
  MikroServe
10
10
  };