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.
- package/README.md +11 -4
- package/lib/MikroServe.d.mts +7 -6
- package/lib/MikroServe.d.ts +7 -6
- package/lib/MikroServe.js +125 -54
- package/lib/MikroServe.mjs +4 -4
- package/lib/Router.d.mts +5 -3
- package/lib/Router.d.ts +5 -3
- package/lib/Router.js +20 -0
- package/lib/Router.mjs +1 -1
- package/lib/{chunk-KJT4SET2.mjs → chunk-GUYBTPZH.mjs} +20 -0
- package/lib/{chunk-NSHBEU32.mjs → chunk-JJX5XRNB.mjs} +6 -4
- package/lib/{chunk-E3RGQ7QF.mjs → chunk-SLBFEKEH.mjs} +68 -51
- package/lib/chunk-YOHL3T54.mjs +43 -0
- package/lib/config.d.mts +37 -0
- package/lib/config.d.ts +37 -0
- package/lib/config.js +88 -0
- package/lib/config.mjs +7 -0
- package/lib/index.d.mts +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +125 -54
- package/lib/index.mjs +4 -4
- package/lib/interfaces/index.d.mts +21 -4
- package/lib/interfaces/index.d.ts +21 -4
- package/lib/utils/configDefaults.d.mts +3 -0
- package/lib/utils/configDefaults.d.ts +3 -0
- package/lib/utils/configDefaults.js +6 -8
- package/lib/utils/configDefaults.mjs +1 -2
- package/package.json +2 -2
- package/lib/chunk-6HESV5Q6.mjs +0 -9
- package/lib/utils/getTruthyValue.d.mts +0 -6
- package/lib/utils/getTruthyValue.d.ts +0 -6
- package/lib/utils/getTruthyValue.js +0 -33
- package/lib/utils/getTruthyValue.mjs +0 -6
|
@@ -3,16 +3,20 @@ import {
|
|
|
3
3
|
} from "./chunk-ZFBBESGU.mjs";
|
|
4
4
|
import {
|
|
5
5
|
Router
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-GUYBTPZH.mjs";
|
|
7
|
+
import {
|
|
8
|
+
baseConfig
|
|
9
|
+
} from "./chunk-YOHL3T54.mjs";
|
|
7
10
|
import {
|
|
8
11
|
configDefaults
|
|
9
|
-
} from "./chunk-
|
|
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
|
|
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
|
|
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 ||
|
|
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.
|
|
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.
|
|
188
|
-
|
|
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
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
"Content-Security-Policy",
|
|
317
|
-
"
|
|
318
|
-
|
|
319
|
-
if (isHttps
|
|
320
|
-
|
|
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
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
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
|
+
};
|
package/lib/config.d.mts
ADDED
|
@@ -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 };
|
package/lib/config.d.ts
ADDED
|
@@ -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
package/lib/index.d.mts
CHANGED
package/lib/index.d.ts
CHANGED
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
|
|
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/
|
|
287
|
-
|
|
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
|
|
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 ||
|
|
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.
|
|
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.
|
|
483
|
-
|
|
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
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
"Content-Security-Policy",
|
|
612
|
-
"
|
|
613
|
-
|
|
614
|
-
if (isHttps
|
|
615
|
-
|
|
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
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
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-
|
|
3
|
+
} from "./chunk-SLBFEKEH.mjs";
|
|
4
4
|
import "./chunk-ZFBBESGU.mjs";
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
5
|
+
import "./chunk-GUYBTPZH.mjs";
|
|
6
|
+
import "./chunk-YOHL3T54.mjs";
|
|
7
|
+
import "./chunk-JJX5XRNB.mjs";
|
|
8
8
|
export {
|
|
9
9
|
MikroServe
|
|
10
10
|
};
|