@lara-node/middlewares 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index-CG4VYL03.d.cts +62 -0
- package/dist/index-CG4VYL03.d.cts.map +1 -0
- package/dist/index.cjs +270 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.d.ts.map +1 -0
- package/package.json +19 -13
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
2
|
+
import { NextFunction, Request, Response } from "express";
|
|
3
|
+
|
|
4
|
+
//#region src/index.d.ts
|
|
5
|
+
declare const asyncLocalStorage: AsyncLocalStorage<Record<string, any>>;
|
|
6
|
+
sideEffect();
|
|
7
|
+
declare class AsyncContextMiddleware {
|
|
8
|
+
handle(req: Request, _res: Response, next: NextFunction): void;
|
|
9
|
+
}
|
|
10
|
+
declare class RequestLoggerMiddleware {
|
|
11
|
+
handle(req: Request, res: Response, next: NextFunction): void;
|
|
12
|
+
}
|
|
13
|
+
declare class ValidatorMiddleware {
|
|
14
|
+
handle(req: Request & {
|
|
15
|
+
validate?: any;
|
|
16
|
+
}, _res: Response, next: NextFunction): void;
|
|
17
|
+
}
|
|
18
|
+
declare class ResponseExtenderMiddleware {
|
|
19
|
+
handle(_req: Request, res: Response, next: NextFunction): void;
|
|
20
|
+
}
|
|
21
|
+
interface AuthMiddlewareOptions {
|
|
22
|
+
userLoader?: (uid: string | number) => Promise<{
|
|
23
|
+
id: number | string;
|
|
24
|
+
roles?: string[];
|
|
25
|
+
permissions?: string[];
|
|
26
|
+
[key: string]: any;
|
|
27
|
+
} | null>;
|
|
28
|
+
decryptToken?: (token: string) => string;
|
|
29
|
+
}
|
|
30
|
+
declare class AuthMiddleware {
|
|
31
|
+
private userLoader?;
|
|
32
|
+
private decryptFn?;
|
|
33
|
+
constructor(options?: AuthMiddlewareOptions);
|
|
34
|
+
handle(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
35
|
+
toHandler(): (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
declare class AuthorizeByStatusMiddleware {
|
|
38
|
+
handle(req: Request, res: Response, next: NextFunction): void;
|
|
39
|
+
}
|
|
40
|
+
declare class ErrorHandlerMiddleware {
|
|
41
|
+
handle(err: any, _req: Request, res: Response, _next: NextFunction): void;
|
|
42
|
+
toHandler(): (err: any, req: Request, res: Response, next: NextFunction) => void;
|
|
43
|
+
}
|
|
44
|
+
declare function authorizeRoles(...roles: string[]): (req: Request, res: Response, next: NextFunction) => void;
|
|
45
|
+
declare function authorizePermissions(...perms: string[]): (req: Request, res: Response, next: NextFunction) => void;
|
|
46
|
+
declare const asyncContextMiddleware: AsyncContextMiddleware;
|
|
47
|
+
declare const requestLoggerMiddleware: RequestLoggerMiddleware;
|
|
48
|
+
declare const validatorMiddleware: ValidatorMiddleware;
|
|
49
|
+
declare const responseExtenderMiddleware: ResponseExtenderMiddleware;
|
|
50
|
+
declare const authorizeByStatusMiddleware: AuthorizeByStatusMiddleware;
|
|
51
|
+
declare const errorHandlerMiddleware: ErrorHandlerMiddleware;
|
|
52
|
+
declare const asyncContext: (req: Request, res: Response, next: NextFunction) => void;
|
|
53
|
+
declare const requestLogger: (req: Request, res: Response, next: NextFunction) => void;
|
|
54
|
+
declare const validatorAttach: (req: Request, res: Response, next: NextFunction) => void;
|
|
55
|
+
declare const responseExtender: (req: Request, res: Response, next: NextFunction) => void;
|
|
56
|
+
declare const authorizeByStatus: (req: Request, res: Response, next: NextFunction) => void;
|
|
57
|
+
declare const errorHandler: (err: any, req: Request, res: Response, next: NextFunction) => void;
|
|
58
|
+
//# sourceMappingURL=index.d.ts.map
|
|
59
|
+
|
|
60
|
+
//#endregion
|
|
61
|
+
export { AsyncContextMiddleware, AuthMiddleware, AuthMiddlewareOptions, AuthorizeByStatusMiddleware, ErrorHandlerMiddleware, RequestLoggerMiddleware, ResponseExtenderMiddleware, ValidatorMiddleware, asyncContext, asyncContextMiddleware, asyncLocalStorage, authorizeByStatus, authorizeByStatusMiddleware, authorizePermissions, authorizeRoles, errorHandler, errorHandlerMiddleware, requestLogger, requestLoggerMiddleware, responseExtender, responseExtenderMiddleware, validatorAttach, validatorMiddleware };
|
|
62
|
+
//# sourceMappingURL=index-CG4VYL03.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-CG4VYL03.d.cts","names":[],"sources":["../src/index.ts"],"mappings":"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"}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
+
get: ((k) => from[k]).bind(null, key),
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
20
|
+
value: mod,
|
|
21
|
+
enumerable: true
|
|
22
|
+
}) : target, mod));
|
|
23
|
+
//#endregion
|
|
24
|
+
let async_hooks = require("async_hooks");
|
|
25
|
+
let jsonwebtoken = require("jsonwebtoken");
|
|
26
|
+
jsonwebtoken = __toESM(jsonwebtoken, 1);
|
|
27
|
+
let _lara_node_validator = require("@lara-node/validator");
|
|
28
|
+
let _lara_node_db = require("@lara-node/db");
|
|
29
|
+
//#region src/index.ts
|
|
30
|
+
const asyncLocalStorage = new async_hooks.AsyncLocalStorage();
|
|
31
|
+
var AsyncContextMiddleware = class {
|
|
32
|
+
handle(req, _res, next) {
|
|
33
|
+
asyncLocalStorage.run({ req }, () => next());
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var RequestLoggerMiddleware = class {
|
|
37
|
+
handle(req, res, next) {
|
|
38
|
+
const start = process.hrtime();
|
|
39
|
+
const { method, originalUrl } = req;
|
|
40
|
+
const ip = req.ip || req.headers["x-forwarded-for"] || req.socket && req.socket.remoteAddress;
|
|
41
|
+
res.on("finish", () => {
|
|
42
|
+
const [sec, nano] = process.hrtime(start);
|
|
43
|
+
const ms = (sec * 1e3 + nano / 1e6).toFixed(2);
|
|
44
|
+
const status = res.statusCode;
|
|
45
|
+
const reset = "\x1B[0m";
|
|
46
|
+
let color = "\x1B[32m";
|
|
47
|
+
if (status >= 500) color = "\x1B[31m";
|
|
48
|
+
else if (status >= 400) color = "\x1B[33m";
|
|
49
|
+
const maybeUser = req.user;
|
|
50
|
+
const userInfo = maybeUser ? ` - user:${maybeUser.id ?? maybeUser.email ?? JSON.stringify(maybeUser)}` : "";
|
|
51
|
+
const query = req.query && Object.keys(req.query).length ? ` query=${JSON.stringify(req.query)}` : "";
|
|
52
|
+
const params = req.params && Object.keys(req.params).length ? ` params=${JSON.stringify(req.params)}` : "";
|
|
53
|
+
console.log(`${method} ${originalUrl} ${color}${status}${reset} - ${ms} ms - ${ip || "-"}${userInfo}${query}${params}`);
|
|
54
|
+
});
|
|
55
|
+
next();
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
var ValidatorMiddleware = class {
|
|
59
|
+
handle(req, _res, next) {
|
|
60
|
+
req.validate = async function(payloadOrRules, maybeRules, customMessages) {
|
|
61
|
+
let payload;
|
|
62
|
+
let rules;
|
|
63
|
+
if (maybeRules === void 0 && typeof payloadOrRules === "object" && !Array.isArray(payloadOrRules) && Object.keys(payloadOrRules || {}).length && Object.values(payloadOrRules).every((v) => typeof v === "string" || typeof v === "function" || typeof v === "object" && v && "rule" in v)) {
|
|
64
|
+
rules = payloadOrRules;
|
|
65
|
+
payload = req.body?.payload ?? req.body;
|
|
66
|
+
} else if (maybeRules !== void 0) {
|
|
67
|
+
payload = payloadOrRules;
|
|
68
|
+
rules = maybeRules;
|
|
69
|
+
} else {
|
|
70
|
+
payload = payloadOrRules ?? req.body?.payload ?? req.body;
|
|
71
|
+
rules = maybeRules;
|
|
72
|
+
}
|
|
73
|
+
if (!rules) throw new Error("No validation rules provided");
|
|
74
|
+
return await (0, _lara_node_validator.validate)(payload, rules, customMessages);
|
|
75
|
+
};
|
|
76
|
+
next();
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
function isQueryResult(obj) {
|
|
80
|
+
return obj && typeof obj === "object" && Array.isArray(obj.data);
|
|
81
|
+
}
|
|
82
|
+
async function serializeItem(item) {
|
|
83
|
+
if (item && typeof item.toJSONAsync === "function") return await item.toJSONAsync();
|
|
84
|
+
return item;
|
|
85
|
+
}
|
|
86
|
+
function containsModels(obj, visited = /* @__PURE__ */ new WeakSet()) {
|
|
87
|
+
if (obj === null || obj === void 0) return false;
|
|
88
|
+
const isObj = typeof obj === "object";
|
|
89
|
+
if (isObj && visited.has(obj)) return false;
|
|
90
|
+
if (isObj) visited.add(obj);
|
|
91
|
+
if (obj instanceof _lara_node_db.Model) return true;
|
|
92
|
+
if (Array.isArray(obj)) return obj.some((item) => containsModels(item, visited));
|
|
93
|
+
if (isQueryResult(obj)) return obj.data.some((item) => containsModels(item, visited));
|
|
94
|
+
if (isObj) return Object.values(obj).some((val) => containsModels(val, visited));
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
var ResponseExtenderMiddleware = class {
|
|
98
|
+
handle(_req, res, next) {
|
|
99
|
+
const originalJson = res.json.bind(res);
|
|
100
|
+
res.jsonAsync = async function(data) {
|
|
101
|
+
if (data instanceof _lara_node_db.Model) return originalJson(await data.toJSONAsync());
|
|
102
|
+
if (Array.isArray(data)) {
|
|
103
|
+
if (data.length === 0) return originalJson(data);
|
|
104
|
+
return originalJson(await Promise.all(data.map(serializeItem)));
|
|
105
|
+
}
|
|
106
|
+
if (isQueryResult(data)) {
|
|
107
|
+
if (data.data.length > 0) {
|
|
108
|
+
const processed = await Promise.all(data.data.map(serializeItem));
|
|
109
|
+
return originalJson({
|
|
110
|
+
...data,
|
|
111
|
+
data: processed
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
return originalJson(data);
|
|
115
|
+
}
|
|
116
|
+
return originalJson(data);
|
|
117
|
+
};
|
|
118
|
+
res.json = function(data) {
|
|
119
|
+
if (data instanceof _lara_node_db.Model) return res.jsonAsync(data);
|
|
120
|
+
if (Array.isArray(data) && data.length > 0 && data.some((item) => item instanceof _lara_node_db.Model)) return res.jsonAsync(data);
|
|
121
|
+
if (isQueryResult(data)) return res.jsonAsync(data);
|
|
122
|
+
if (containsModels(data)) return res.jsonAsync(data);
|
|
123
|
+
return originalJson(data);
|
|
124
|
+
}.bind(res);
|
|
125
|
+
next();
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
var AuthMiddleware = class {
|
|
129
|
+
constructor(options = {}) {
|
|
130
|
+
this.userLoader = options.userLoader;
|
|
131
|
+
this.decryptFn = options.decryptToken;
|
|
132
|
+
}
|
|
133
|
+
async handle(req, res, next) {
|
|
134
|
+
const header = req.headers["authorization"] || "";
|
|
135
|
+
const token = header.startsWith("Bearer ") ? header.slice(7) : "";
|
|
136
|
+
if (!token) {
|
|
137
|
+
res.status(401).json({ message: "Unauthorized" });
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
const JWT_SECRET = process.env.JWT_SECRET || "dev-secret-change";
|
|
142
|
+
const rawToken = this.decryptFn ? this.decryptFn(token) : token;
|
|
143
|
+
const decoded = jsonwebtoken.default.verify(rawToken, JWT_SECRET);
|
|
144
|
+
const uid = decoded.sub;
|
|
145
|
+
if (this.userLoader) {
|
|
146
|
+
const user = await this.userLoader(uid);
|
|
147
|
+
if (!user) {
|
|
148
|
+
res.status(401).json({ message: "Unauthorized" });
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
req.user = {
|
|
152
|
+
id: user.id,
|
|
153
|
+
roles: user.roles,
|
|
154
|
+
permissions: user.permissions
|
|
155
|
+
};
|
|
156
|
+
const store = asyncLocalStorage.getStore();
|
|
157
|
+
if (store) store.user = user;
|
|
158
|
+
} else req.user = {
|
|
159
|
+
id: uid,
|
|
160
|
+
roles: decoded.roles,
|
|
161
|
+
permissions: decoded.permissions
|
|
162
|
+
};
|
|
163
|
+
next();
|
|
164
|
+
} catch {
|
|
165
|
+
res.status(401).json({ message: "Unauthorized" });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
toHandler() {
|
|
169
|
+
return this.handle.bind(this);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
var AuthorizeByStatusMiddleware = class {
|
|
173
|
+
handle(req, res, next) {
|
|
174
|
+
const user = req.user;
|
|
175
|
+
if (!user) {
|
|
176
|
+
res.status(401).json({ message: "Unauthorized" });
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (typeof user.isActive === "function" && !user.isActive()) {
|
|
180
|
+
res.status(401).json({ message: "Account Inactive" });
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (user.status && user.status !== "active") {
|
|
184
|
+
res.status(401).json({ message: "Account Inactive" });
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
next();
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
var ErrorHandlerMiddleware = class {
|
|
191
|
+
handle(err, _req, res, _next) {
|
|
192
|
+
if (res.headersSent) return;
|
|
193
|
+
if (err instanceof _lara_node_validator.ValidationError) {
|
|
194
|
+
res.status(422).json({
|
|
195
|
+
success: false,
|
|
196
|
+
errors: err.errors,
|
|
197
|
+
messages: err.messages,
|
|
198
|
+
message: err.message
|
|
199
|
+
});
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const status = typeof err.status === "number" && err.status >= 400 && err.status < 600 ? err.status : 500;
|
|
203
|
+
const payload = {
|
|
204
|
+
success: false,
|
|
205
|
+
message: err.message || "Internal Server Error"
|
|
206
|
+
};
|
|
207
|
+
if (err.code) payload.code = err.code;
|
|
208
|
+
if (err.errors && typeof err.errors === "object") payload.errors = err.errors;
|
|
209
|
+
if (process.env.NODE_ENV !== "production" && err.stack) payload.stack = err.stack.split("\n").map((l) => l.trim());
|
|
210
|
+
res.status(status).json(payload);
|
|
211
|
+
}
|
|
212
|
+
toHandler() {
|
|
213
|
+
return this.handle.bind(this);
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
function authorizeRoles(...roles) {
|
|
217
|
+
return (req, res, next) => {
|
|
218
|
+
const userRoles = req.user?.roles || [];
|
|
219
|
+
if (!roles.some((r) => userRoles.includes(r))) {
|
|
220
|
+
res.status(403).json({ message: "Forbidden" });
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
next();
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
function authorizePermissions(...perms) {
|
|
227
|
+
return (req, res, next) => {
|
|
228
|
+
const userPerms = req.user?.permissions || [];
|
|
229
|
+
if (!perms.some((p) => userPerms.includes(p))) {
|
|
230
|
+
res.status(403).json({ message: "Forbidden" });
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
next();
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
const asyncContextMiddleware = new AsyncContextMiddleware();
|
|
237
|
+
const requestLoggerMiddleware = new RequestLoggerMiddleware();
|
|
238
|
+
const validatorMiddleware = new ValidatorMiddleware();
|
|
239
|
+
const responseExtenderMiddleware = new ResponseExtenderMiddleware();
|
|
240
|
+
const authorizeByStatusMiddleware = new AuthorizeByStatusMiddleware();
|
|
241
|
+
const errorHandlerMiddleware = new ErrorHandlerMiddleware();
|
|
242
|
+
const asyncContext = (req, res, next) => asyncContextMiddleware.handle(req, res, next);
|
|
243
|
+
const requestLogger = (req, res, next) => requestLoggerMiddleware.handle(req, res, next);
|
|
244
|
+
const validatorAttach = (req, res, next) => validatorMiddleware.handle(req, res, next);
|
|
245
|
+
const responseExtender = (req, res, next) => responseExtenderMiddleware.handle(req, res, next);
|
|
246
|
+
const authorizeByStatus = (req, res, next) => authorizeByStatusMiddleware.handle(req, res, next);
|
|
247
|
+
const errorHandler = (err, req, res, next) => errorHandlerMiddleware.handle(err, req, res, next);
|
|
248
|
+
//#endregion
|
|
249
|
+
exports.AsyncContextMiddleware = AsyncContextMiddleware;
|
|
250
|
+
exports.AuthMiddleware = AuthMiddleware;
|
|
251
|
+
exports.AuthorizeByStatusMiddleware = AuthorizeByStatusMiddleware;
|
|
252
|
+
exports.ErrorHandlerMiddleware = ErrorHandlerMiddleware;
|
|
253
|
+
exports.RequestLoggerMiddleware = RequestLoggerMiddleware;
|
|
254
|
+
exports.ResponseExtenderMiddleware = ResponseExtenderMiddleware;
|
|
255
|
+
exports.ValidatorMiddleware = ValidatorMiddleware;
|
|
256
|
+
exports.asyncContext = asyncContext;
|
|
257
|
+
exports.asyncContextMiddleware = asyncContextMiddleware;
|
|
258
|
+
exports.asyncLocalStorage = asyncLocalStorage;
|
|
259
|
+
exports.authorizeByStatus = authorizeByStatus;
|
|
260
|
+
exports.authorizeByStatusMiddleware = authorizeByStatusMiddleware;
|
|
261
|
+
exports.authorizePermissions = authorizePermissions;
|
|
262
|
+
exports.authorizeRoles = authorizeRoles;
|
|
263
|
+
exports.errorHandler = errorHandler;
|
|
264
|
+
exports.errorHandlerMiddleware = errorHandlerMiddleware;
|
|
265
|
+
exports.requestLogger = requestLogger;
|
|
266
|
+
exports.requestLoggerMiddleware = requestLoggerMiddleware;
|
|
267
|
+
exports.responseExtender = responseExtender;
|
|
268
|
+
exports.responseExtenderMiddleware = responseExtenderMiddleware;
|
|
269
|
+
exports.validatorAttach = validatorAttach;
|
|
270
|
+
exports.validatorMiddleware = validatorMiddleware;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
2
|
+
import { Request, Response, NextFunction } from "express";
|
|
3
|
+
import { RuleFn, RuleSpec } from "@lara-node/validator";
|
|
4
|
+
export declare const asyncLocalStorage: AsyncLocalStorage<Record<string, any>>;
|
|
5
|
+
declare global {
|
|
6
|
+
namespace Express {
|
|
7
|
+
interface Request {
|
|
8
|
+
user?: {
|
|
9
|
+
id: number | string;
|
|
10
|
+
email?: string;
|
|
11
|
+
name?: string;
|
|
12
|
+
roles?: string[];
|
|
13
|
+
permissions?: string[];
|
|
14
|
+
[key: string]: any;
|
|
15
|
+
};
|
|
16
|
+
validate: <T extends Record<string, any>>(payloadOrRules?: any, rulesMaybe?: Record<string, RuleSpec> | Record<string, string | RuleFn>, customMessages?: Record<string, string>) => Promise<T>;
|
|
17
|
+
}
|
|
18
|
+
interface Response {
|
|
19
|
+
jsonAsync: <T>(data: T) => Promise<Response>;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export declare class AsyncContextMiddleware {
|
|
24
|
+
handle(req: Request, _res: Response, next: NextFunction): void;
|
|
25
|
+
}
|
|
26
|
+
export declare class RequestLoggerMiddleware {
|
|
27
|
+
handle(req: Request, res: Response, next: NextFunction): void;
|
|
28
|
+
}
|
|
29
|
+
export declare class ValidatorMiddleware {
|
|
30
|
+
handle(req: Request & {
|
|
31
|
+
validate?: any;
|
|
32
|
+
}, _res: Response, next: NextFunction): void;
|
|
33
|
+
}
|
|
34
|
+
export declare class ResponseExtenderMiddleware {
|
|
35
|
+
handle(_req: Request, res: Response, next: NextFunction): void;
|
|
36
|
+
}
|
|
37
|
+
export interface AuthMiddlewareOptions {
|
|
38
|
+
userLoader?: (uid: string | number) => Promise<{
|
|
39
|
+
id: number | string;
|
|
40
|
+
roles?: string[];
|
|
41
|
+
permissions?: string[];
|
|
42
|
+
[key: string]: any;
|
|
43
|
+
} | null>;
|
|
44
|
+
decryptToken?: (token: string) => string;
|
|
45
|
+
}
|
|
46
|
+
export declare class AuthMiddleware {
|
|
47
|
+
private userLoader?;
|
|
48
|
+
private decryptFn?;
|
|
49
|
+
constructor(options?: AuthMiddlewareOptions);
|
|
50
|
+
handle(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
51
|
+
toHandler(): (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
52
|
+
}
|
|
53
|
+
export declare class AuthorizeByStatusMiddleware {
|
|
54
|
+
handle(req: Request, res: Response, next: NextFunction): void;
|
|
55
|
+
}
|
|
56
|
+
export declare class ErrorHandlerMiddleware {
|
|
57
|
+
handle(err: any, _req: Request, res: Response, _next: NextFunction): void;
|
|
58
|
+
toHandler(): (err: any, req: Request, res: Response, next: NextFunction) => void;
|
|
59
|
+
}
|
|
60
|
+
export declare function authorizeRoles(...roles: string[]): (req: Request, res: Response, next: NextFunction) => void;
|
|
61
|
+
export declare function authorizePermissions(...perms: string[]): (req: Request, res: Response, next: NextFunction) => void;
|
|
62
|
+
export declare const asyncContextMiddleware: AsyncContextMiddleware;
|
|
63
|
+
export declare const requestLoggerMiddleware: RequestLoggerMiddleware;
|
|
64
|
+
export declare const validatorMiddleware: ValidatorMiddleware;
|
|
65
|
+
export declare const responseExtenderMiddleware: ResponseExtenderMiddleware;
|
|
66
|
+
export declare const authorizeByStatusMiddleware: AuthorizeByStatusMiddleware;
|
|
67
|
+
export declare const errorHandlerMiddleware: ErrorHandlerMiddleware;
|
|
68
|
+
export declare const asyncContext: (req: Request, res: Response, next: NextFunction) => void;
|
|
69
|
+
export declare const requestLogger: (req: Request, res: Response, next: NextFunction) => void;
|
|
70
|
+
export declare const validatorAttach: (req: Request, res: Response, next: NextFunction) => void;
|
|
71
|
+
export declare const responseExtender: (req: Request, res: Response, next: NextFunction) => void;
|
|
72
|
+
export declare const authorizeByStatus: (req: Request, res: Response, next: NextFunction) => void;
|
|
73
|
+
export declare const errorHandler: (err: any, req: Request, res: Response, next: NextFunction) => void;
|
|
74
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lara-node/middlewares",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Predefined class-based middleware for Lara-Node applications",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./dist/index.
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
7
9
|
"exports": {
|
|
8
|
-
".":
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.cjs",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
}
|
|
9
15
|
},
|
|
10
16
|
"files": [
|
|
11
17
|
"dist",
|
|
@@ -14,10 +20,16 @@
|
|
|
14
20
|
"publishConfig": {
|
|
15
21
|
"access": "public"
|
|
16
22
|
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsdown src/index.ts --format esm,cjs --out-dir dist && tsc --emitDeclarationOnly",
|
|
25
|
+
"dev": "tsdown src/index.ts --format esm,cjs --out-dir dist --watch",
|
|
26
|
+
"clean": "rimraf dist",
|
|
27
|
+
"typecheck": "tsc --noEmit"
|
|
28
|
+
},
|
|
17
29
|
"dependencies": {
|
|
18
|
-
"
|
|
19
|
-
"@lara-node/
|
|
20
|
-
"
|
|
30
|
+
"@lara-node/validator": "workspace:*",
|
|
31
|
+
"@lara-node/db": "workspace:*",
|
|
32
|
+
"jsonwebtoken": "^9.0.2"
|
|
21
33
|
},
|
|
22
34
|
"devDependencies": {
|
|
23
35
|
"@types/express": "^5.0.6",
|
|
@@ -29,11 +41,5 @@
|
|
|
29
41
|
},
|
|
30
42
|
"peerDependencies": {
|
|
31
43
|
"express": "^5.2.1"
|
|
32
|
-
},
|
|
33
|
-
"scripts": {
|
|
34
|
-
"build": "tsdown src/index.ts --format esm --out-dir dist --dts",
|
|
35
|
-
"dev": "tsdown src/index.ts --format esm --out-dir dist --dts --watch",
|
|
36
|
-
"clean": "rimraf dist",
|
|
37
|
-
"typecheck": "tsc --noEmit"
|
|
38
44
|
}
|
|
39
|
-
}
|
|
45
|
+
}
|