@increase21/simplenodejs 1.0.20 → 1.0.21
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 +418 -167
- package/dist/index.d.ts +3 -3
- package/dist/index.js +12 -2
- package/dist/router.d.ts +1 -3
- package/dist/router.js +37 -51
- package/dist/server.d.ts +9 -5
- package/dist/server.js +38 -33
- package/dist/typings/general.d.ts +7 -18
- package/dist/typings/simpletypes.d.ts +10 -0
- package/dist/utils/helpers.d.ts +6 -3
- package/dist/utils/helpers.js +51 -3
- package/dist/utils/simpleController.d.ts +5 -7
- package/dist/utils/simpleController.js +4 -21
- package/dist/utils/simpleMiddleware.d.ts +32 -4
- package/dist/utils/simpleMiddleware.js +136 -51
- package/dist/utils/simplePlugins.d.ts +67 -4
- package/dist/utils/simplePlugins.js +200 -2
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { SimpleNodeJsController } from "./utils/simpleController";
|
|
2
|
-
export { CreateSimpleJsHttpServer } from "./server";
|
|
3
|
-
export {
|
|
2
|
+
export { CreateSimpleJsHttpServer, CreateSimpleJsHttpsServer } from "./server";
|
|
3
|
+
export { SetCORS, SetHSTS, SetCSP, SetFrameGuard, SetNoSniff, SetReferrerPolicy, SetPermissionsPolicy, SetCOEP, SetCOOP, SetHelmet, SetRateLimiter, SetBodyParser, } from "./utils/simpleMiddleware";
|
|
4
4
|
export * from "./utils/simplePlugins";
|
|
5
|
-
export type { SimpleJsPrivateMethodProps, Middleware as SimpleJsMiddleware } from "./typings/general";
|
|
5
|
+
export type { SimpleJsPrivateMethodProps, Middleware as SimpleJsMiddleware, SimpleJsHttpsServer } from "./typings/general";
|
package/dist/index.js
CHANGED
|
@@ -14,13 +14,23 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.SetBodyParser = exports.SetRateLimiter = exports.
|
|
17
|
+
exports.SetBodyParser = exports.SetRateLimiter = exports.SetHelmet = exports.SetCOOP = exports.SetCOEP = exports.SetPermissionsPolicy = exports.SetReferrerPolicy = exports.SetNoSniff = exports.SetFrameGuard = exports.SetCSP = exports.SetHSTS = exports.SetCORS = exports.CreateSimpleJsHttpsServer = exports.CreateSimpleJsHttpServer = exports.SimpleNodeJsController = void 0;
|
|
18
18
|
var simpleController_1 = require("./utils/simpleController");
|
|
19
19
|
Object.defineProperty(exports, "SimpleNodeJsController", { enumerable: true, get: function () { return simpleController_1.SimpleNodeJsController; } });
|
|
20
20
|
var server_1 = require("./server");
|
|
21
21
|
Object.defineProperty(exports, "CreateSimpleJsHttpServer", { enumerable: true, get: function () { return server_1.CreateSimpleJsHttpServer; } });
|
|
22
|
+
Object.defineProperty(exports, "CreateSimpleJsHttpsServer", { enumerable: true, get: function () { return server_1.CreateSimpleJsHttpsServer; } });
|
|
22
23
|
var simpleMiddleware_1 = require("./utils/simpleMiddleware");
|
|
23
|
-
Object.defineProperty(exports, "
|
|
24
|
+
Object.defineProperty(exports, "SetCORS", { enumerable: true, get: function () { return simpleMiddleware_1.SetCORS; } });
|
|
25
|
+
Object.defineProperty(exports, "SetHSTS", { enumerable: true, get: function () { return simpleMiddleware_1.SetHSTS; } });
|
|
26
|
+
Object.defineProperty(exports, "SetCSP", { enumerable: true, get: function () { return simpleMiddleware_1.SetCSP; } });
|
|
27
|
+
Object.defineProperty(exports, "SetFrameGuard", { enumerable: true, get: function () { return simpleMiddleware_1.SetFrameGuard; } });
|
|
28
|
+
Object.defineProperty(exports, "SetNoSniff", { enumerable: true, get: function () { return simpleMiddleware_1.SetNoSniff; } });
|
|
29
|
+
Object.defineProperty(exports, "SetReferrerPolicy", { enumerable: true, get: function () { return simpleMiddleware_1.SetReferrerPolicy; } });
|
|
30
|
+
Object.defineProperty(exports, "SetPermissionsPolicy", { enumerable: true, get: function () { return simpleMiddleware_1.SetPermissionsPolicy; } });
|
|
31
|
+
Object.defineProperty(exports, "SetCOEP", { enumerable: true, get: function () { return simpleMiddleware_1.SetCOEP; } });
|
|
32
|
+
Object.defineProperty(exports, "SetCOOP", { enumerable: true, get: function () { return simpleMiddleware_1.SetCOOP; } });
|
|
33
|
+
Object.defineProperty(exports, "SetHelmet", { enumerable: true, get: function () { return simpleMiddleware_1.SetHelmet; } });
|
|
24
34
|
Object.defineProperty(exports, "SetRateLimiter", { enumerable: true, get: function () { return simpleMiddleware_1.SetRateLimiter; } });
|
|
25
35
|
Object.defineProperty(exports, "SetBodyParser", { enumerable: true, get: function () { return simpleMiddleware_1.SetBodyParser; } });
|
|
26
36
|
__exportStar(require("./utils/simplePlugins"), exports);
|
package/dist/router.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
1
|
import { RequestObject, ResponseObject } from "./typings/general";
|
|
2
|
-
import { SimpleJsControllerMeta } from "./typings/simpletypes";
|
|
3
|
-
export declare function loadControllers(root?: string): Map<string, SimpleJsControllerMeta>;
|
|
4
2
|
export declare function setControllersDir(dir: string): void;
|
|
5
|
-
export declare function route(req: RequestObject, res: ResponseObject): Promise<
|
|
3
|
+
export declare function route(req: RequestObject, res: ResponseObject): Promise<ResponseObject | undefined>;
|
package/dist/router.js
CHANGED
|
@@ -1,67 +1,40 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.loadControllers = loadControllers;
|
|
7
3
|
exports.setControllersDir = setControllersDir;
|
|
8
4
|
exports.route = route;
|
|
9
|
-
// router.ts
|
|
10
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
11
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
12
5
|
const helpers_1 = require("./utils/helpers");
|
|
6
|
+
const simpleController_1 = require("./utils/simpleController");
|
|
13
7
|
let controllers = new Map();
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
function walk(dir) {
|
|
19
|
-
//get all the file in the directory
|
|
20
|
-
for (const file of node_fs_1.default.readdirSync(dir)) {
|
|
21
|
-
//add the file name and path
|
|
22
|
-
const full = node_path_1.default.join(dir, file);
|
|
23
|
-
//load direct and reload the files
|
|
24
|
-
if (node_fs_1.default.statSync(full).isDirectory())
|
|
25
|
-
walk(full);
|
|
26
|
-
//if it's file load the file
|
|
27
|
-
else if (file.endsWith(".js") || file.endsWith(".ts")) {
|
|
28
|
-
const mod = require(full);
|
|
29
|
-
// const Controller = mod.default;
|
|
30
|
-
if (!full.startsWith(base))
|
|
31
|
-
return;
|
|
32
|
-
const Controller = require(full)?.default;
|
|
33
|
-
if (typeof Controller !== "function")
|
|
34
|
-
return;
|
|
35
|
-
const key = full.replace(base, "").replace(/\\/g, "/").replace(/\.(ts|js)$/, "");
|
|
36
|
-
map.set(key.toLowerCase(), { name: Controller.name, Controller });
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
walk(base);
|
|
41
|
-
return map;
|
|
42
|
-
}
|
|
8
|
+
const UNSAFE_METHODS = new Set([
|
|
9
|
+
...Object.getOwnPropertyNames(Object.prototype),
|
|
10
|
+
...Object.getOwnPropertyNames(simpleController_1.SimpleNodeJsController.prototype),
|
|
11
|
+
]);
|
|
43
12
|
function setControllersDir(dir) {
|
|
44
|
-
controllers = loadControllers(dir);
|
|
13
|
+
controllers = (0, helpers_1.loadControllers)(dir);
|
|
45
14
|
}
|
|
46
15
|
async function route(req, res) {
|
|
47
16
|
let parts = req._end_point_path || [];
|
|
48
|
-
let controllerPath = (parts.length > 2 ? "/" + parts.slice(0, 2).join("/") : `/${parts.join("/")}`).
|
|
17
|
+
let controllerPath = (parts.length > 2 ? "/" + parts.slice(0, 2).join("/") : `/${parts.join("/")}`).toLowerCase().replace(/\-{1}\w{1}/g, match => match.replace("-", "").toUpperCase());
|
|
49
18
|
let methodName = parts.length > 2 ? parts[2] : "index";
|
|
50
|
-
let id = methodName !== "index" ? parts.slice(
|
|
19
|
+
let id = methodName !== "index" ? parts.slice(3).join("/") : null;
|
|
20
|
+
let httpMethod = (req.method || "").toLowerCase();
|
|
51
21
|
const meta = controllers.get(controllerPath);
|
|
52
22
|
//if the controller is not available or not found
|
|
53
23
|
if (!meta || !meta.name || !meta.Controller)
|
|
54
24
|
return (0, helpers_1.throwHttpError)(404, "The requested resource does not exist");
|
|
55
25
|
const ControllerClass = meta.Controller;
|
|
56
26
|
const controller = new ControllerClass();
|
|
57
|
-
//Update the method name to the framework
|
|
27
|
+
//Update the method name to the framework pattern
|
|
58
28
|
methodName = (methodName || "").replace(/\-{1}\w{1}/g, match => match.replace("-", "").toUpperCase());
|
|
29
|
+
// Block Object.prototype methods (constructor, toString, etc.) and __private convention
|
|
30
|
+
if (methodName.startsWith("__") || UNSAFE_METHODS.has(methodName)) {
|
|
31
|
+
return (0, helpers_1.throwHttpError)(404, "The requested resource does not exist");
|
|
32
|
+
}
|
|
59
33
|
//if the endpoint not a function
|
|
60
34
|
if (typeof controller[methodName] !== "function") {
|
|
61
|
-
//if it's using index
|
|
62
35
|
if (typeof controller["index"] === "function" && parts.length === 3) {
|
|
63
36
|
methodName = "index";
|
|
64
|
-
id = parts.slice(2);
|
|
37
|
+
id = parts.slice(2).join("/"); // pass the rest of the path as ID;
|
|
65
38
|
}
|
|
66
39
|
else {
|
|
67
40
|
return (0, helpers_1.throwHttpError)(404, "The requested resource does not exist");
|
|
@@ -73,13 +46,26 @@ async function route(req, res) {
|
|
|
73
46
|
}
|
|
74
47
|
//bind the controller to use the global properties
|
|
75
48
|
controller.__bindContext({ req, res });
|
|
76
|
-
|
|
77
|
-
if
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
//if
|
|
81
|
-
if (!res.writableEnded
|
|
82
|
-
res.
|
|
83
|
-
|
|
84
|
-
|
|
49
|
+
let result = await controller[methodName](id);
|
|
50
|
+
//if the cycle has ended
|
|
51
|
+
if (res.writableEnded)
|
|
52
|
+
return;
|
|
53
|
+
//if the controller returned nothing and response is not ended, end it
|
|
54
|
+
if (!result && !res.writableEnded)
|
|
55
|
+
return res.end();
|
|
56
|
+
//if there's no method defined for the http verb, return 405
|
|
57
|
+
if (result && typeof result[httpMethod] !== "function")
|
|
58
|
+
return (0, helpers_1.throwHttpError)(405, "Method Not Allowed");
|
|
59
|
+
// ID validation rules
|
|
60
|
+
if (id && (!result.id || !result.id[httpMethod]))
|
|
61
|
+
return (0, helpers_1.throwHttpError)(404, "Resource not found");
|
|
62
|
+
if (result.id && result.id[httpMethod] === "required" && !id)
|
|
63
|
+
return (0, helpers_1.throwHttpError)(404, "Resource not found");
|
|
64
|
+
result = await result[httpMethod]({
|
|
65
|
+
req, res, query: controller.query, body: controller.body,
|
|
66
|
+
id: id, customData: controller._custom_data
|
|
67
|
+
});
|
|
68
|
+
//if not responded
|
|
69
|
+
if (!res.writableEnded)
|
|
70
|
+
res.end("");
|
|
85
71
|
}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { SimpleJsServer } from "./typings/general";
|
|
3
|
-
|
|
4
|
-
controllersDir
|
|
5
|
-
|
|
1
|
+
import https from "node:https";
|
|
2
|
+
import { SimpleJsHttpsServer, SimpleJsServer } from "./typings/general";
|
|
3
|
+
type ServerOptions = {
|
|
4
|
+
controllersDir?: string;
|
|
5
|
+
tlsOpts?: https.ServerOptions;
|
|
6
|
+
};
|
|
7
|
+
export declare const CreateSimpleJsHttpServer: (opts?: ServerOptions) => SimpleJsServer;
|
|
8
|
+
export declare const CreateSimpleJsHttpsServer: (opts?: ServerOptions) => SimpleJsHttpsServer;
|
|
9
|
+
export {};
|
package/dist/server.js
CHANGED
|
@@ -3,75 +3,80 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.CreateSimpleJsHttpServer = void 0;
|
|
6
|
+
exports.CreateSimpleJsHttpsServer = exports.CreateSimpleJsHttpServer = void 0;
|
|
7
7
|
const http_1 = __importDefault(require("http"));
|
|
8
|
+
const node_https_1 = __importDefault(require("node:https"));
|
|
9
|
+
const node_querystring_1 = __importDefault(require("node:querystring"));
|
|
8
10
|
const router_1 = require("./router");
|
|
9
11
|
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
10
12
|
const helpers_1 = require("./utils/helpers");
|
|
11
13
|
const extension = (req, res) => {
|
|
12
|
-
//for response status
|
|
13
14
|
res.status = (code) => {
|
|
14
|
-
if (
|
|
15
|
+
if (typeof code !== "number")
|
|
15
16
|
throw new Error("Status code expected to be number but got " + typeof code);
|
|
16
|
-
res.statusCode = code
|
|
17
|
+
res.statusCode = code ?? 200;
|
|
17
18
|
return res;
|
|
18
19
|
};
|
|
19
|
-
///convert the response to JSON
|
|
20
20
|
res.json = (param) => {
|
|
21
21
|
res.setHeader('Content-Type', 'application/json');
|
|
22
22
|
res.end(JSON.stringify(param));
|
|
23
23
|
};
|
|
24
|
-
//convert the response to text/plain
|
|
25
24
|
res.text = (param) => {
|
|
26
25
|
res.setHeader('Content-Type', 'text/plain');
|
|
27
26
|
res.end(param);
|
|
28
27
|
};
|
|
29
28
|
const url = new URL(req.url, "http://localhost");
|
|
30
|
-
req.query = url.search ? url.search.substring(1) :
|
|
31
|
-
//endpoint path
|
|
29
|
+
req.query = url.search ? node_querystring_1.default.parse(url.search.substring(1)) : {};
|
|
32
30
|
req._end_point_path = url.pathname.replace(/^\/+|\/+$/g, "").split("/");
|
|
33
|
-
//adding the request ID
|
|
34
31
|
req.id = node_crypto_1.default.randomUUID();
|
|
35
32
|
res.setHeader("X-Request-Id", req.id);
|
|
36
33
|
};
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const errorMiddlewares = [];
|
|
40
|
-
const plugins = [];
|
|
41
|
-
//set the director of the controller
|
|
42
|
-
if (opts?.controllersDir)
|
|
43
|
-
(0, router_1.setControllersDir)(opts.controllersDir);
|
|
44
|
-
const server = http_1.default.createServer(async (req, res) => {
|
|
34
|
+
function buildRequestHandler(middlewares, errorMiddlewares) {
|
|
35
|
+
return async (req, res) => {
|
|
45
36
|
try {
|
|
46
37
|
extension(req, res);
|
|
47
|
-
const run = (0, helpers_1.composeWithError)(middlewares);
|
|
48
|
-
// handler && await handler(req, res)
|
|
49
38
|
if (res.writableEnded)
|
|
50
39
|
return;
|
|
40
|
+
const run = (0, helpers_1.composeMiddleware)(middlewares);
|
|
51
41
|
await run(req, res);
|
|
52
|
-
//if the request has ended stop here
|
|
53
42
|
if (res.writableEnded)
|
|
54
43
|
return;
|
|
55
44
|
await (0, router_1.route)(req, res);
|
|
56
45
|
}
|
|
57
46
|
catch (err) {
|
|
58
|
-
|
|
59
|
-
for (const mw of errorMiddlewares) {
|
|
60
|
-
await mw(err, req, res, () => { });
|
|
61
|
-
}
|
|
62
|
-
// 2. Safe HTTP response fallback
|
|
47
|
+
await (0, helpers_1.runErrorMiddlewares)(err, errorMiddlewares, req, res);
|
|
63
48
|
if (!res.headersSent) {
|
|
64
|
-
|
|
65
|
-
res.
|
|
49
|
+
let errorCode = (err || {}).code;
|
|
50
|
+
res.statusCode = errorCode || 503;
|
|
51
|
+
res.end(errorCode ? err.error : "Service unavailable");
|
|
66
52
|
}
|
|
67
53
|
}
|
|
68
|
-
});
|
|
69
|
-
server.use = mw => { middlewares.push(mw); };
|
|
70
|
-
server.useError = mw => errorMiddlewares.push(mw);
|
|
71
|
-
server.registerPlugin = async (plugin) => {
|
|
72
|
-
plugins.push(plugin);
|
|
73
|
-
await plugin(server);
|
|
74
54
|
};
|
|
55
|
+
}
|
|
56
|
+
function attachServerMethods(server, middlewares, errorMiddlewares, opts) {
|
|
57
|
+
server.use = mw => { middlewares.push(mw); };
|
|
58
|
+
server.useError = mw => { errorMiddlewares.push(mw); };
|
|
59
|
+
server.registerPlugin = async (plugin) => { await plugin(server); };
|
|
60
|
+
}
|
|
61
|
+
const CreateSimpleJsHttpServer = (opts) => {
|
|
62
|
+
const middlewares = [];
|
|
63
|
+
const errorMiddlewares = [];
|
|
64
|
+
if (opts && opts.controllersDir)
|
|
65
|
+
(0, router_1.setControllersDir)(opts.controllersDir);
|
|
66
|
+
const server = http_1.default.createServer(buildRequestHandler(middlewares, errorMiddlewares));
|
|
67
|
+
attachServerMethods(server, middlewares, errorMiddlewares, opts);
|
|
75
68
|
return server;
|
|
76
69
|
};
|
|
77
70
|
exports.CreateSimpleJsHttpServer = CreateSimpleJsHttpServer;
|
|
71
|
+
const CreateSimpleJsHttpsServer = (opts) => {
|
|
72
|
+
const middlewares = [];
|
|
73
|
+
const errorMiddlewares = [];
|
|
74
|
+
if (!opts?.tlsOpts)
|
|
75
|
+
throw new Error("CreateSimpleJsHttpsServer requires opts.tlsOpts");
|
|
76
|
+
if (opts.controllersDir)
|
|
77
|
+
(0, router_1.setControllersDir)(opts.controllersDir);
|
|
78
|
+
const server = node_https_1.default.createServer(opts.tlsOpts, buildRequestHandler(middlewares, errorMiddlewares));
|
|
79
|
+
attachServerMethods(server, middlewares, errorMiddlewares, opts);
|
|
80
|
+
return server;
|
|
81
|
+
};
|
|
82
|
+
exports.CreateSimpleJsHttpsServer = CreateSimpleJsHttpsServer;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import http, { IncomingMessage, ServerResponse } from "http";
|
|
2
|
+
import https from "node:https";
|
|
2
3
|
export type Next = () => Promise<any> | void;
|
|
3
4
|
export type Plugin = (app: SimpleJsServer, opts?: any) => Promise<any> | void;
|
|
4
5
|
export type HttpMethod = "get" | "post" | "put" | "patch" | "delete";
|
|
@@ -11,14 +12,17 @@ export interface SimpleJsServer extends http.Server {
|
|
|
11
12
|
use(mw: Middleware): Promise<any> | void;
|
|
12
13
|
useError: (mw: ErrorMiddleware) => void;
|
|
13
14
|
registerPlugin: (plugin: Plugin) => Promise<any> | void;
|
|
14
|
-
|
|
15
|
+
}
|
|
16
|
+
export interface SimpleJsHttpsServer extends https.Server {
|
|
17
|
+
use(mw: Middleware): Promise<any> | void;
|
|
18
|
+
useError: (mw: ErrorMiddleware) => void;
|
|
19
|
+
registerPlugin: (plugin: Plugin) => Promise<any> | void;
|
|
15
20
|
}
|
|
16
21
|
export interface RequestObject extends IncomingMessage {
|
|
17
22
|
body?: any;
|
|
18
23
|
query?: any;
|
|
19
24
|
id?: string;
|
|
20
25
|
_end_point_path?: string[];
|
|
21
|
-
_server_environment?: 'dev' | 'stag' | 'live';
|
|
22
26
|
_custom_data?: ObjectPayload;
|
|
23
27
|
}
|
|
24
28
|
export interface ResponseObject extends ServerResponse {
|
|
@@ -26,26 +30,11 @@ export interface ResponseObject extends ServerResponse {
|
|
|
26
30
|
json: (value: object) => void;
|
|
27
31
|
text: (value?: string) => void;
|
|
28
32
|
}
|
|
29
|
-
export interface SubRequestHandler {
|
|
30
|
-
post?: (params: SimpleJsPrivateMethodProps) => void;
|
|
31
|
-
put?: (params: SimpleJsPrivateMethodProps) => void;
|
|
32
|
-
get?: (params: SimpleJsPrivateMethodProps) => void;
|
|
33
|
-
delete?: (params: SimpleJsPrivateMethodProps) => void;
|
|
34
|
-
patch?: (params: SimpleJsPrivateMethodProps) => void;
|
|
35
|
-
}
|
|
36
33
|
export interface SimpleJsPrivateMethodProps {
|
|
37
34
|
body: ObjectPayload;
|
|
38
35
|
res: ResponseObject;
|
|
39
36
|
req: RequestObject;
|
|
40
37
|
query: ObjectPayload;
|
|
41
|
-
id?: string;
|
|
38
|
+
id?: string | null;
|
|
42
39
|
customData?: any;
|
|
43
|
-
idMethod?: {
|
|
44
|
-
post?: 'required' | 'optional';
|
|
45
|
-
get?: 'required' | 'optional';
|
|
46
|
-
put?: 'required' | 'optional';
|
|
47
|
-
delete?: 'required' | 'optional';
|
|
48
|
-
patch?: 'required' | 'optional';
|
|
49
|
-
};
|
|
50
40
|
}
|
|
51
|
-
export type AcceptHeaderValue = 'application/media' | 'application/text';
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { HttpMethod, SimpleJsPrivateMethodProps } from "./general";
|
|
1
2
|
export type SimpleJSRateLimitType = {
|
|
2
3
|
windowMs: number;
|
|
3
4
|
max: number;
|
|
5
|
+
trustProxy?: boolean;
|
|
4
6
|
keyGenerator?: (req: any) => string;
|
|
5
7
|
};
|
|
6
8
|
export type SimpleJSBodyParseType = {
|
|
@@ -10,3 +12,11 @@ export interface SimpleJsControllerMeta {
|
|
|
10
12
|
name: string;
|
|
11
13
|
Controller: any;
|
|
12
14
|
}
|
|
15
|
+
export interface SubRequestHandler {
|
|
16
|
+
post?: (params: SimpleJsPrivateMethodProps) => void;
|
|
17
|
+
put?: (params: SimpleJsPrivateMethodProps) => void;
|
|
18
|
+
get?: (params: SimpleJsPrivateMethodProps) => void;
|
|
19
|
+
delete?: (params: SimpleJsPrivateMethodProps) => void;
|
|
20
|
+
patch?: (params: SimpleJsPrivateMethodProps) => void;
|
|
21
|
+
id?: Partial<Record<HttpMethod, "required" | "optional">>;
|
|
22
|
+
}
|
package/dist/utils/helpers.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
import { Middleware, RequestObject, ResponseObject } from "../typings/general";
|
|
2
|
-
|
|
3
|
-
export declare function
|
|
1
|
+
import { ErrorMiddleware, Middleware, RequestObject, ResponseObject } from "../typings/general";
|
|
2
|
+
import { SimpleJsControllerMeta } from "../typings/simpletypes";
|
|
3
|
+
export declare function composeMiddleware(middlewares: Middleware[]): (req: RequestObject, res: ResponseObject) => Promise<void>;
|
|
4
|
+
export declare function runErrorMiddlewares(err: unknown, errorMiddlewares: ErrorMiddleware[], req: RequestObject, res: ResponseObject): Promise<void>;
|
|
5
|
+
export declare function throwHttpError(code: number, message: string): never;
|
|
6
|
+
export declare function loadControllers(root?: string): Map<string, SimpleJsControllerMeta>;
|
package/dist/utils/helpers.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
6
|
+
exports.composeMiddleware = composeMiddleware;
|
|
7
|
+
exports.runErrorMiddlewares = runErrorMiddlewares;
|
|
4
8
|
exports.throwHttpError = throwHttpError;
|
|
5
|
-
|
|
9
|
+
exports.loadControllers = loadControllers;
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
12
|
+
function composeMiddleware(middlewares) {
|
|
6
13
|
return async function (req, res) {
|
|
7
14
|
let idx = -1;
|
|
8
15
|
async function dispatch(i) {
|
|
@@ -26,8 +33,49 @@ function composeWithError(middlewares) {
|
|
|
26
33
|
return await dispatch(0);
|
|
27
34
|
};
|
|
28
35
|
}
|
|
36
|
+
async function runErrorMiddlewares(err, errorMiddlewares, req, res) {
|
|
37
|
+
let idx = 0;
|
|
38
|
+
async function next() {
|
|
39
|
+
const mw = errorMiddlewares[idx++];
|
|
40
|
+
if (!mw || res.writableEnded)
|
|
41
|
+
return;
|
|
42
|
+
await mw(err, req, res, next);
|
|
43
|
+
}
|
|
44
|
+
await next();
|
|
45
|
+
}
|
|
29
46
|
function throwHttpError(code, message) {
|
|
30
47
|
const error = new Error(message);
|
|
31
|
-
error.
|
|
48
|
+
error.code = code;
|
|
32
49
|
throw error;
|
|
33
50
|
}
|
|
51
|
+
function loadControllers(root = "controllers") {
|
|
52
|
+
const base = node_path_1.default.resolve(process.cwd(), root);
|
|
53
|
+
const realBase = node_fs_1.default.realpathSync(base); // resolve the base itself (may be a symlink)
|
|
54
|
+
const map = new Map();
|
|
55
|
+
function walk(dir) {
|
|
56
|
+
for (const file of node_fs_1.default.readdirSync(dir)) {
|
|
57
|
+
const full = node_path_1.default.join(dir, file);
|
|
58
|
+
let realFull;
|
|
59
|
+
try {
|
|
60
|
+
realFull = node_fs_1.default.realpathSync(full); // resolve actual disk path, following all symlinks
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
continue; // skip broken symlinks
|
|
64
|
+
}
|
|
65
|
+
// Block anything whose real path is outside the controllers directory
|
|
66
|
+
if (!realFull.startsWith(realBase + node_path_1.default.sep))
|
|
67
|
+
continue;
|
|
68
|
+
if (node_fs_1.default.statSync(full).isDirectory())
|
|
69
|
+
walk(full);
|
|
70
|
+
else if (file.endsWith(".js") || file.endsWith(".ts")) {
|
|
71
|
+
const Controller = require(full)?.default;
|
|
72
|
+
if (typeof Controller !== "function")
|
|
73
|
+
continue;
|
|
74
|
+
const key = full.slice(base.length).replace(/\\/g, "/").replace(/\.(ts|js)$/, "");
|
|
75
|
+
map.set(key.toLowerCase(), { name: Controller.name, Controller });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
walk(base);
|
|
80
|
+
return map;
|
|
81
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { HttpMethod, ObjectPayload, RequestObject, ResponseObject
|
|
2
|
-
|
|
1
|
+
import { HttpMethod, ObjectPayload, RequestObject, ResponseObject } from "../typings/general";
|
|
2
|
+
import { SubRequestHandler } from "../typings/simpletypes";
|
|
3
3
|
export declare class SimpleNodeJsController {
|
|
4
4
|
protected req: RequestObject;
|
|
5
5
|
protected res: ResponseObject;
|
|
@@ -7,13 +7,11 @@ export declare class SimpleNodeJsController {
|
|
|
7
7
|
protected query: ObjectPayload;
|
|
8
8
|
protected method: HttpMethod;
|
|
9
9
|
protected _custom_data: any;
|
|
10
|
-
/**
|
|
10
|
+
/** @internal */
|
|
11
11
|
__bindContext(ctx: {
|
|
12
12
|
req: RequestObject;
|
|
13
13
|
res: ResponseObject;
|
|
14
14
|
}): void;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
protected RunRequest(handlers: SubRequestHandler, params?: Partial<SimpleJsPrivateMethodProps>): any;
|
|
15
|
+
protected __checkContext(): void;
|
|
16
|
+
protected __run(handlers: SubRequestHandler): SubRequestHandler;
|
|
18
17
|
}
|
|
19
|
-
export {};
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SimpleNodeJsController = void 0;
|
|
4
|
-
const helpers_1 = require("./helpers");
|
|
5
4
|
class SimpleNodeJsController {
|
|
6
|
-
/**
|
|
5
|
+
/** @internal */
|
|
7
6
|
__bindContext(ctx) {
|
|
8
7
|
this.req = ctx.req;
|
|
9
8
|
this.res = ctx.res;
|
|
@@ -11,27 +10,11 @@ class SimpleNodeJsController {
|
|
|
11
10
|
this.query = ctx.req.query;
|
|
12
11
|
this.method = (ctx.req.method || "").toLocaleLowerCase();
|
|
13
12
|
this._custom_data = ctx.req._custom_data;
|
|
13
|
+
this.__checkContext();
|
|
14
14
|
}
|
|
15
|
-
/** framework-internal method */
|
|
16
15
|
__checkContext() { }
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (!method)
|
|
20
|
-
return (0, helpers_1.throwHttpError)(400, "Invalid HTTP Method");
|
|
21
|
-
const runFn = handlers[method];
|
|
22
|
-
if (typeof runFn !== "function")
|
|
23
|
-
return (0, helpers_1.throwHttpError)(405, "Method Not Allowed");
|
|
24
|
-
// ID validation rules
|
|
25
|
-
if (params && params.id && (!params.idMethod || !params.idMethod[method]))
|
|
26
|
-
return (0, helpers_1.throwHttpError)(404, "Resource not found");
|
|
27
|
-
if (params && params.idMethod?.[method] === "required" && !params.id)
|
|
28
|
-
return (0, helpers_1.throwHttpError)(404, "Resource not found");
|
|
29
|
-
return runFn({
|
|
30
|
-
...(params || {}), req: this.req,
|
|
31
|
-
res: this.res, query: this.query,
|
|
32
|
-
customData: this._custom_data,
|
|
33
|
-
body: this.body,
|
|
34
|
-
});
|
|
16
|
+
__run(handlers) {
|
|
17
|
+
return handlers;
|
|
35
18
|
}
|
|
36
19
|
}
|
|
37
20
|
exports.SimpleNodeJsController = SimpleNodeJsController;
|
|
@@ -1,8 +1,36 @@
|
|
|
1
1
|
import { RequestObject, ResponseObject } from "../typings/general";
|
|
2
2
|
import { SimpleJSBodyParseType, SimpleJSRateLimitType } from "../typings/simpletypes";
|
|
3
|
-
export declare function
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
export declare function SetCORS(opts?: {
|
|
4
|
+
origin?: string;
|
|
5
|
+
methods?: string;
|
|
6
|
+
headers?: string;
|
|
7
|
+
credentials?: boolean;
|
|
8
|
+
}): (req: RequestObject, res: ResponseObject, next: any) => Promise<void>;
|
|
9
|
+
export declare function SetHSTS(opts?: {
|
|
10
|
+
maxAge?: number;
|
|
11
|
+
includeSubDomains?: boolean;
|
|
12
|
+
preload?: boolean;
|
|
13
|
+
}): (_req: RequestObject, res: ResponseObject, next: any) => Promise<void>;
|
|
14
|
+
export declare function SetCSP(policy?: string): (_req: RequestObject, res: ResponseObject, next: any) => Promise<void>;
|
|
15
|
+
export declare function SetFrameGuard(action?: "DENY" | "SAMEORIGIN"): (_req: RequestObject, res: ResponseObject, next: any) => Promise<void>;
|
|
16
|
+
export declare function SetNoSniff(): (_req: RequestObject, res: ResponseObject, next: any) => Promise<void>;
|
|
17
|
+
export declare function SetReferrerPolicy(policy?: string): (_req: RequestObject, res: ResponseObject, next: any) => Promise<void>;
|
|
18
|
+
export declare function SetPermissionsPolicy(policy?: string): (_req: RequestObject, res: ResponseObject, next: any) => Promise<void>;
|
|
19
|
+
export declare function SetCOEP(value?: string): (_req: RequestObject, res: ResponseObject, next: any) => Promise<void>;
|
|
20
|
+
export declare function SetCOOP(value?: string): (_req: RequestObject, res: ResponseObject, next: any) => Promise<void>;
|
|
21
|
+
export declare function SetHelmet(opts?: {
|
|
22
|
+
hsts?: false | {
|
|
23
|
+
maxAge?: number;
|
|
24
|
+
includeSubDomains?: boolean;
|
|
25
|
+
preload?: boolean;
|
|
26
|
+
};
|
|
27
|
+
csp?: false | string;
|
|
28
|
+
frameGuard?: false | "DENY" | "SAMEORIGIN";
|
|
29
|
+
noSniff?: false;
|
|
30
|
+
referrerPolicy?: false | string;
|
|
31
|
+
permissionsPolicy?: false | string;
|
|
32
|
+
coep?: false | string;
|
|
33
|
+
coop?: false | string;
|
|
34
|
+
}): (_req: RequestObject, res: ResponseObject, next: any) => Promise<void>;
|
|
7
35
|
export declare function SetRateLimiter(opts: SimpleJSRateLimitType): (req: RequestObject, res: ResponseObject, next: () => Promise<any> | void) => Promise<void>;
|
|
8
36
|
export declare function SetBodyParser(opts: SimpleJSBodyParseType): (req: RequestObject, res: ResponseObject, next: () => Promise<any> | void) => Promise<void>;
|