response-standardizer 1.3.2 → 1.3.4
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/exceptions.d.ts +26 -0
- package/dist/exceptions.js +73 -0
- package/dist/index.d.ts +1 -16
- package/dist/index.js +3 -82
- package/package.json +1 -1
- package/src/exceptions.ts +65 -0
- package/src/index.ts +3 -74
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Request, Response } from "express";
|
|
2
|
+
import { ErrorFields } from "./types";
|
|
3
|
+
export declare class ServiceException extends Error {
|
|
4
|
+
statusCode: number;
|
|
5
|
+
constructor(statusCode: number, message: string);
|
|
6
|
+
}
|
|
7
|
+
export declare class UnknownException extends ServiceException {
|
|
8
|
+
constructor(statusCode: number, message: string);
|
|
9
|
+
}
|
|
10
|
+
export declare class NotFoundException extends ServiceException {
|
|
11
|
+
constructor(message: string);
|
|
12
|
+
}
|
|
13
|
+
export declare class UnauthorizedException extends ServiceException {
|
|
14
|
+
constructor(message: string);
|
|
15
|
+
}
|
|
16
|
+
export declare class AccessDeniedException extends ServiceException {
|
|
17
|
+
constructor(message: string);
|
|
18
|
+
}
|
|
19
|
+
export declare class InternalServerException extends ServiceException {
|
|
20
|
+
constructor(message: string);
|
|
21
|
+
}
|
|
22
|
+
export declare class ValidationException extends ServiceException {
|
|
23
|
+
errors?: ErrorFields;
|
|
24
|
+
constructor(message: string, errors?: ErrorFields);
|
|
25
|
+
}
|
|
26
|
+
export declare const handleControllerException: (req: Request, res: Response, err: Error) => void;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleControllerException = exports.ValidationException = exports.InternalServerException = exports.AccessDeniedException = exports.UnauthorizedException = exports.NotFoundException = exports.UnknownException = exports.ServiceException = void 0;
|
|
4
|
+
const _1 = require(".");
|
|
5
|
+
class ServiceException extends Error {
|
|
6
|
+
constructor(statusCode, message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.statusCode = statusCode;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.ServiceException = ServiceException;
|
|
12
|
+
class UnknownException extends ServiceException {
|
|
13
|
+
constructor(statusCode, message) {
|
|
14
|
+
super(statusCode, message);
|
|
15
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.UnknownException = UnknownException;
|
|
19
|
+
class NotFoundException extends ServiceException {
|
|
20
|
+
constructor(message) {
|
|
21
|
+
super(404, message);
|
|
22
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.NotFoundException = NotFoundException;
|
|
26
|
+
class UnauthorizedException extends ServiceException {
|
|
27
|
+
constructor(message) {
|
|
28
|
+
super(401, message);
|
|
29
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.UnauthorizedException = UnauthorizedException;
|
|
33
|
+
class AccessDeniedException extends ServiceException {
|
|
34
|
+
constructor(message) {
|
|
35
|
+
super(403, message);
|
|
36
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.AccessDeniedException = AccessDeniedException;
|
|
40
|
+
class InternalServerException extends ServiceException {
|
|
41
|
+
constructor(message) {
|
|
42
|
+
super(500, message);
|
|
43
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.InternalServerException = InternalServerException;
|
|
47
|
+
class ValidationException extends ServiceException {
|
|
48
|
+
constructor(message, errors) {
|
|
49
|
+
super(400, message);
|
|
50
|
+
this.errors = errors;
|
|
51
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.ValidationException = ValidationException;
|
|
55
|
+
const handleControllerException = (req, res, err) => {
|
|
56
|
+
if (err instanceof UnauthorizedException) {
|
|
57
|
+
return _1.RestResponse.unauthorized(req, res, err.message);
|
|
58
|
+
}
|
|
59
|
+
else if (err instanceof AccessDeniedException) {
|
|
60
|
+
return _1.RestResponse.accessDenied(req, res, err.message);
|
|
61
|
+
}
|
|
62
|
+
else if (err instanceof ValidationException) {
|
|
63
|
+
return _1.RestResponse.validationError(req, res, err?.errors, err?.message);
|
|
64
|
+
}
|
|
65
|
+
else if (err instanceof InternalServerException) {
|
|
66
|
+
return _1.RestResponse.exceptionError(req, res, err.message);
|
|
67
|
+
}
|
|
68
|
+
else if (err instanceof NotFoundException) {
|
|
69
|
+
return _1.RestResponse.notFound(req, res, err.message);
|
|
70
|
+
}
|
|
71
|
+
return _1.RestResponse.exceptionError(req, res, err.message);
|
|
72
|
+
};
|
|
73
|
+
exports.handleControllerException = handleControllerException;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ErrorFields, RestResponseFunctions, RestMiddlewareFunctions } from "./types";
|
|
1
|
+
import { RestResponseFunctions, RestMiddlewareFunctions } from "./types";
|
|
3
2
|
declare global {
|
|
4
3
|
namespace Express {
|
|
5
4
|
interface Response {
|
|
@@ -23,17 +22,3 @@ export declare const error: (message: string, meta?: any) => void;
|
|
|
23
22
|
export declare const warn: (message: string, meta?: any) => void;
|
|
24
23
|
export declare const info: (message: string, meta?: any) => void;
|
|
25
24
|
export declare const log: (level: "INFO" | "WARN" | "ERROR", message: string, meta?: any) => void;
|
|
26
|
-
export declare const response: (req: Request, res: Response, response: ServiceResponse, handler?: (eq: Request, res: Response, data?: any) => void) => void;
|
|
27
|
-
export declare const handleServiceException: (message: string, err: any) => ServiceResponse;
|
|
28
|
-
export interface ServiceResponse {
|
|
29
|
-
}
|
|
30
|
-
export declare class ServiceException implements ServiceResponse {
|
|
31
|
-
code: number;
|
|
32
|
-
message: string;
|
|
33
|
-
errors?: ErrorFields | undefined;
|
|
34
|
-
constructor(code: number, message: string, errors?: ErrorFields | undefined);
|
|
35
|
-
}
|
|
36
|
-
export declare class ServiceResponseSuccess implements ServiceResponse {
|
|
37
|
-
entity: any;
|
|
38
|
-
constructor(entity?: any);
|
|
39
|
-
}
|
package/dist/index.js
CHANGED
|
@@ -3,12 +3,10 @@ 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.
|
|
6
|
+
exports.log = exports.info = exports.warn = exports.error = exports.RestMiddleware = exports.RestResponse = exports.protect = exports.initKeycloak = void 0;
|
|
7
7
|
const utils_1 = require("./utils");
|
|
8
8
|
const axios_1 = __importDefault(require("axios"));
|
|
9
9
|
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
10
|
-
const path_1 = __importDefault(require("path"));
|
|
11
|
-
const zod_1 = require("zod");
|
|
12
10
|
let KEYCLOAK_PUBLIC_KEY = null;
|
|
13
11
|
const initKeycloak = async (config) => {
|
|
14
12
|
const KEYCLOAK_SERVICE = config.service ?? "localhost";
|
|
@@ -52,7 +50,7 @@ const role = (req, res, next, allowedRoles) => {
|
|
|
52
50
|
const clientRoles = Object.values(user?.resource_access ?? {})
|
|
53
51
|
.flatMap((r) => r.roles ?? [])
|
|
54
52
|
.map((r) => r.toUpperCase());
|
|
55
|
-
const allowedUpper = allowedRoles.map(r => r.toUpperCase());
|
|
53
|
+
const allowedUpper = allowedRoles.map(r => r === "super-admin" ? "ADMIN" : `DEZH-${r.toUpperCase()}`);
|
|
56
54
|
const allRoles = [...realmRoles, ...clientRoles];
|
|
57
55
|
const hasAccess = allowedUpper.some((role) => allRoles.includes(role));
|
|
58
56
|
if (!hasAccess) {
|
|
@@ -162,85 +160,8 @@ const log = (level, message, meta) => {
|
|
|
162
160
|
if (level === "ERROR")
|
|
163
161
|
color = colors.RED;
|
|
164
162
|
}
|
|
165
|
-
// گرفتن stack trace
|
|
166
|
-
const stack = new Error().stack?.split("\n")[2]; // خط Caller
|
|
167
|
-
let location = "";
|
|
168
|
-
if (stack) {
|
|
169
|
-
const match = stack.match(/\((.*):(\d+):(\d+)\)/);
|
|
170
|
-
if (match) {
|
|
171
|
-
const fileName = path_1.default.basename(match[1]);
|
|
172
|
-
const line = match[2];
|
|
173
|
-
const column = match[3];
|
|
174
|
-
location = `${fileName}:${line}:${column}`;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
163
|
const metaStr = meta ? `. ${JSON.stringify(meta)}` : "";
|
|
178
164
|
// چاپ لاگ
|
|
179
|
-
console.log(`${color}[${timestamp}][${
|
|
165
|
+
console.log(`${color}[${timestamp}][${level}] ${message}${metaStr}${colors.RESET}`);
|
|
180
166
|
};
|
|
181
167
|
exports.log = log;
|
|
182
|
-
const response = (req, res, response, handler = (eq, res, data = null) => { }) => {
|
|
183
|
-
if (response instanceof ServiceException) {
|
|
184
|
-
if (response?.code === 401) {
|
|
185
|
-
return exports.RestResponse.unauthorized(req, res, response?.message);
|
|
186
|
-
}
|
|
187
|
-
else if (response?.code === 403) {
|
|
188
|
-
return exports.RestResponse.accessDenied(req, res, response?.message);
|
|
189
|
-
}
|
|
190
|
-
else if (response?.code === 400) {
|
|
191
|
-
return exports.RestResponse.validationError(req, res, response?.errors);
|
|
192
|
-
}
|
|
193
|
-
else if (response?.code === 500) {
|
|
194
|
-
return exports.RestResponse.exceptionError(req, res, response.message);
|
|
195
|
-
}
|
|
196
|
-
else if (response?.code === 404) {
|
|
197
|
-
return exports.RestResponse.notFound(req, res, response.message);
|
|
198
|
-
}
|
|
199
|
-
return exports.RestResponse.exceptionError(req, res, response.message);
|
|
200
|
-
}
|
|
201
|
-
return handler(req, res, response.entity);
|
|
202
|
-
};
|
|
203
|
-
exports.response = response;
|
|
204
|
-
const handleServiceException = (message, err) => {
|
|
205
|
-
if (err instanceof zod_1.ZodError) {
|
|
206
|
-
const zodError = err;
|
|
207
|
-
if (zodError.issues) {
|
|
208
|
-
const validationErrors = {};
|
|
209
|
-
zodError.issues.forEach((i) => {
|
|
210
|
-
const key = i.path[0];
|
|
211
|
-
if (!validationErrors[key])
|
|
212
|
-
validationErrors[key] = [];
|
|
213
|
-
validationErrors[key].push(i.message);
|
|
214
|
-
});
|
|
215
|
-
return new ServiceException(400, "Validation error", validationErrors);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
else if (err?.isAxiosError && err?.response && err.response.status) {
|
|
219
|
-
(0, exports.error)(message, {
|
|
220
|
-
status: err.response.status,
|
|
221
|
-
statusText: err.response.statusText,
|
|
222
|
-
error: err.response.data
|
|
223
|
-
});
|
|
224
|
-
return new ServiceException(err.response.status, err.response.data?.error_description);
|
|
225
|
-
}
|
|
226
|
-
else if (err instanceof Error) {
|
|
227
|
-
(0, exports.error)(message, { error: err });
|
|
228
|
-
return new ServiceException(500, err?.message);
|
|
229
|
-
}
|
|
230
|
-
return new ServiceException(500, "Internal server error");
|
|
231
|
-
};
|
|
232
|
-
exports.handleServiceException = handleServiceException;
|
|
233
|
-
class ServiceException {
|
|
234
|
-
constructor(code, message, errors) {
|
|
235
|
-
this.code = code;
|
|
236
|
-
this.message = message;
|
|
237
|
-
this.errors = errors;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
exports.ServiceException = ServiceException;
|
|
241
|
-
class ServiceResponseSuccess {
|
|
242
|
-
constructor(entity = null) {
|
|
243
|
-
this.entity = entity;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
exports.ServiceResponseSuccess = ServiceResponseSuccess;
|
package/package.json
CHANGED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Request, Response } from "express";
|
|
2
|
+
import { RestResponse } from ".";
|
|
3
|
+
import { ErrorFields } from "./types";
|
|
4
|
+
export class ServiceException extends Error{
|
|
5
|
+
statusCode: number;
|
|
6
|
+
constructor(statusCode: number, message: string) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.statusCode = statusCode;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export class UnknownException extends ServiceException {
|
|
12
|
+
constructor(statusCode: number, message: string) {
|
|
13
|
+
super(statusCode, message);
|
|
14
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export class NotFoundException extends ServiceException {
|
|
18
|
+
constructor(message: string) {
|
|
19
|
+
super(404, message);
|
|
20
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export class UnauthorizedException extends ServiceException {
|
|
24
|
+
constructor(message: string) {
|
|
25
|
+
super(401, message);
|
|
26
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export class AccessDeniedException extends ServiceException {
|
|
30
|
+
constructor(message: string) {
|
|
31
|
+
super(403, message);
|
|
32
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export class InternalServerException extends ServiceException {
|
|
36
|
+
constructor(message: string) {
|
|
37
|
+
super(500, message);
|
|
38
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export class ValidationException extends ServiceException {
|
|
42
|
+
errors?: ErrorFields
|
|
43
|
+
|
|
44
|
+
constructor(message: string, errors?: ErrorFields) {
|
|
45
|
+
super(400, message);
|
|
46
|
+
this.errors = errors;
|
|
47
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const handleControllerException = (req: Request, res: Response, err: Error) => {
|
|
52
|
+
if(err instanceof UnauthorizedException){
|
|
53
|
+
return RestResponse.unauthorized(req, res, err.message);
|
|
54
|
+
}else if(err instanceof AccessDeniedException){
|
|
55
|
+
return RestResponse.accessDenied(req, res, err.message);
|
|
56
|
+
}else if(err instanceof ValidationException){
|
|
57
|
+
return RestResponse.validationError(req, res, (err as any)?.errors, (err as any)?.message);
|
|
58
|
+
}else if(err instanceof InternalServerException){
|
|
59
|
+
return RestResponse.exceptionError(req, res, err.message);
|
|
60
|
+
}else if(err instanceof NotFoundException){
|
|
61
|
+
return RestResponse.notFound(req, res, err.message);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return RestResponse.exceptionError(req, res, err.message);
|
|
65
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -62,7 +62,7 @@ const role = (req: any, res: any, next: any, allowedRoles: string[]) => {
|
|
|
62
62
|
const clientRoles: string[] = Object.values(user?.resource_access ?? {})
|
|
63
63
|
.flatMap((r: any) => r.roles ?? [])
|
|
64
64
|
.map((r: string) => r.toUpperCase());
|
|
65
|
-
const allowedUpper = allowedRoles.map(r => r.toUpperCase());
|
|
65
|
+
const allowedUpper = allowedRoles.map(r => r === "super-admin"?"ADMIN":`DEZH-${r.toUpperCase()}`);
|
|
66
66
|
const allRoles = [...realmRoles, ...clientRoles];
|
|
67
67
|
const hasAccess: boolean = allowedUpper.some((role: string) =>
|
|
68
68
|
allRoles.includes(role)
|
|
@@ -208,79 +208,8 @@ export const log = (level: "INFO" | "WARN" | "ERROR", message: string, meta?: an
|
|
|
208
208
|
if (level === "WARN") color = colors.YELLOW;
|
|
209
209
|
if (level === "ERROR") color = colors.RED;
|
|
210
210
|
}
|
|
211
|
-
|
|
212
|
-
// گرفتن stack trace
|
|
213
|
-
const stack = new Error().stack?.split("\n")[2]; // خط Caller
|
|
214
|
-
let location = "";
|
|
215
|
-
if (stack) {
|
|
216
|
-
const match = stack.match(/\((.*):(\d+):(\d+)\)/);
|
|
217
|
-
if (match) {
|
|
218
|
-
const fileName = path.basename(match[1]);
|
|
219
|
-
const line = match[2];
|
|
220
|
-
const column = match[3];
|
|
221
|
-
location = `${fileName}:${line}:${column}`;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
211
|
const metaStr = meta ? `. ${JSON.stringify(meta)}` : "";
|
|
226
212
|
|
|
227
213
|
// چاپ لاگ
|
|
228
|
-
console.log(`${color}[${timestamp}][${
|
|
229
|
-
};
|
|
230
|
-
export const response = (
|
|
231
|
-
req: Request,
|
|
232
|
-
res: Response,
|
|
233
|
-
response: ServiceResponse,
|
|
234
|
-
handler = (eq: Request, res: Response, data: any = null) => {}
|
|
235
|
-
) => {
|
|
236
|
-
if(response instanceof ServiceException){
|
|
237
|
-
if(response?.code === 401){
|
|
238
|
-
return RestResponse.unauthorized(req, res, response?.message)
|
|
239
|
-
}else if(response?.code === 403){
|
|
240
|
-
return RestResponse.accessDenied(req, res, response?.message)
|
|
241
|
-
}else if(response?.code === 400){
|
|
242
|
-
return RestResponse.validationError(req, res, response?.errors)
|
|
243
|
-
}else if(response?.code === 500){
|
|
244
|
-
return RestResponse.exceptionError(req, res, response.message)
|
|
245
|
-
}else if(response?.code === 404){
|
|
246
|
-
return RestResponse.notFound(req, res, response.message)
|
|
247
|
-
}
|
|
248
|
-
return RestResponse.exceptionError(req, res, response.message)
|
|
249
|
-
}
|
|
250
|
-
return handler(req, res, (response as ServiceResponseSuccess).entity)
|
|
251
|
-
}
|
|
252
|
-
export const handleServiceException = (message: string, err: any) : ServiceResponse => {
|
|
253
|
-
if(err instanceof ZodError){
|
|
254
|
-
const zodError = err as ZodError;
|
|
255
|
-
if (zodError.issues) {
|
|
256
|
-
const validationErrors: any = {};
|
|
257
|
-
zodError.issues.forEach((i) => {
|
|
258
|
-
const key = i.path[0];
|
|
259
|
-
if (!validationErrors[key]) validationErrors[key] = [];
|
|
260
|
-
validationErrors[key].push(i.message);
|
|
261
|
-
});
|
|
262
|
-
return new ServiceException(400, "Validation error", validationErrors)
|
|
263
|
-
}
|
|
264
|
-
}else if((err as any)?.isAxiosError && (err as any)?.response && (err as any).response.status){
|
|
265
|
-
error(message, {
|
|
266
|
-
status: (err as any).response.status,
|
|
267
|
-
statusText: (err as any).response.statusText,
|
|
268
|
-
error: (err as any).response.data
|
|
269
|
-
})
|
|
270
|
-
return new ServiceException((err as any).response.status, (err as any).response.data?.error_description);
|
|
271
|
-
}else if(err instanceof Error){
|
|
272
|
-
error(message, { error: err })
|
|
273
|
-
return new ServiceException(500, err?.message);
|
|
274
|
-
}
|
|
275
|
-
return new ServiceException(500, "Internal server error");
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
export interface ServiceResponse{
|
|
279
|
-
|
|
280
|
-
}
|
|
281
|
-
export class ServiceException implements ServiceResponse {
|
|
282
|
-
constructor(public code: number, public message: string, public errors?: ErrorFields) {}
|
|
283
|
-
}
|
|
284
|
-
export class ServiceResponseSuccess implements ServiceResponse {
|
|
285
|
-
constructor(public entity: any = null) {}
|
|
286
|
-
}
|
|
214
|
+
console.log(`${color}[${timestamp}][${level}] ${message}${metaStr}${colors.RESET}`);
|
|
215
|
+
};
|