response-standardizer 1.2.0 → 1.2.2

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.js CHANGED
@@ -1,28 +1,34 @@
1
- import { generateRequestId, getTimestamp } from "./utils.js";
2
- import axios from "axios";
3
- import jwt from "jsonwebtoken";
4
- import path from "path";
5
- import { ServiceException } from "./service.exception.js";
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ServiceException = exports.handleValidationException = exports.handleRestException = exports.log = exports.info = exports.warn = exports.error = exports.RestMiddleware = exports.RestResponse = exports.protect = exports.initKeycloak = void 0;
7
+ const utils_1 = require("./utils");
8
+ const axios_1 = __importDefault(require("axios"));
9
+ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
10
+ const path_1 = __importDefault(require("path"));
6
11
  let KEYCLOAK_PUBLIC_KEY = null;
7
- export const initKeycloak = async (config) => {
12
+ const initKeycloak = async (config) => {
8
13
  const KEYCLOAK_SERVICE = config.service ?? "localhost";
9
14
  const KEYCLOAK_REALM = config.realm ?? "master";
10
15
  const realmUrl = `http://${KEYCLOAK_SERVICE}/realms/${KEYCLOAK_REALM}`;
11
- info(`Keycloak PublicKey Url: ${realmUrl}`);
12
- const resp = await axios.get(realmUrl);
16
+ (0, exports.info)(`Keycloak PublicKey Url: ${realmUrl}`);
17
+ const resp = await axios_1.default.get(realmUrl);
13
18
  const key = resp.data.public_key;
14
19
  KEYCLOAK_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----\n${key.match(/.{1,64}/g)?.join("\n")}\n-----END PUBLIC KEY-----`;
15
20
  };
16
- export const protect = (allowedRoles) => {
21
+ exports.initKeycloak = initKeycloak;
22
+ const protect = (allowedRoles) => {
17
23
  return (req, res, next) => {
18
24
  const authHeader = req.headers["authorization"];
19
25
  if (!authHeader)
20
- return RestResponse.unauthorized(req, res);
26
+ return exports.RestResponse.unauthorized(req, res);
21
27
  const token = authHeader.split(" ")[1];
22
28
  if (!token)
23
- return RestResponse.unauthorized(req, res, "Token malformed");
29
+ return exports.RestResponse.unauthorized(req, res, "Token malformed");
24
30
  try {
25
- const decoded = jwt.verify(token, KEYCLOAK_PUBLIC_KEY, { algorithms: ["RS256"] });
31
+ const decoded = jsonwebtoken_1.default.verify(token, KEYCLOAK_PUBLIC_KEY, { algorithms: ["RS256"] });
26
32
  req.user = decoded;
27
33
  req.token = token;
28
34
  if (allowedRoles)
@@ -30,15 +36,16 @@ export const protect = (allowedRoles) => {
30
36
  next();
31
37
  }
32
38
  catch (err) {
33
- error(err?.message);
34
- return RestResponse.unauthorized(req, res, "Token is not valid");
39
+ (0, exports.error)(err?.message);
40
+ return exports.RestResponse.unauthorized(req, res, "Token is not valid");
35
41
  }
36
42
  };
37
43
  };
44
+ exports.protect = protect;
38
45
  const role = (req, res, next, allowedRoles) => {
39
46
  const user = req.user;
40
47
  if (!user) {
41
- return RestResponse.unauthorized(req, res);
48
+ return exports.RestResponse.unauthorized(req, res);
42
49
  }
43
50
  const realmRoles = (user?.realm_access?.roles ?? []).map((r) => r.toUpperCase());
44
51
  const clientRoles = Object.values(user?.resource_access ?? {})
@@ -48,7 +55,7 @@ const role = (req, res, next, allowedRoles) => {
48
55
  const allRoles = [...realmRoles, ...clientRoles];
49
56
  const hasAccess = allowedUpper.some((role) => allRoles.includes(role));
50
57
  if (!hasAccess) {
51
- return RestResponse.accessDenied(req, res);
58
+ return exports.RestResponse.accessDenied(req, res);
52
59
  }
53
60
  next();
54
61
  };
@@ -82,7 +89,7 @@ const accessDenied = (req, res, message = "Access denied") => {
82
89
  const notFound = (req, res, message = "Not found") => {
83
90
  res.status(404).json({ message });
84
91
  };
85
- export const RestResponse = {
92
+ exports.RestResponse = {
86
93
  success,
87
94
  paginate,
88
95
  created,
@@ -103,8 +110,8 @@ const responseHandlerMiddleware = (req, res, next) => {
103
110
  message: data?.message || res.locals.message || (res.statusCode < 300 ? "OK" : "Error"),
104
111
  errors: data?.errors ?? null,
105
112
  meta: {
106
- requestId: res.locals.requestId || generateRequestId(),
107
- timestamp: getTimestamp()
113
+ requestId: res.locals.requestId || (0, utils_1.generateRequestId)(),
114
+ timestamp: (0, utils_1.getTimestamp)()
108
115
  }
109
116
  };
110
117
  return oldJson(response);
@@ -117,10 +124,10 @@ const responseHandlerMiddleware = (req, res, next) => {
117
124
  }
118
125
  return oldSend(data);
119
126
  };
120
- res.locals.requestId = generateRequestId();
127
+ res.locals.requestId = (0, utils_1.generateRequestId)();
121
128
  next();
122
129
  };
123
- export const RestMiddleware = {
130
+ exports.RestMiddleware = {
124
131
  responseHandlerMiddleware
125
132
  };
126
133
  const colors = {
@@ -130,16 +137,19 @@ const colors = {
130
137
  YELLOW: "\x1b[33m"
131
138
  };
132
139
  const isProduction = process.env.NODE_ENV === "production";
133
- export const error = (message, meta) => {
134
- log("ERROR", message, meta);
140
+ const error = (message, meta) => {
141
+ (0, exports.log)("ERROR", message, meta);
135
142
  };
136
- export const warn = (message, meta) => {
137
- log("WARN", message, meta);
143
+ exports.error = error;
144
+ const warn = (message, meta) => {
145
+ (0, exports.log)("WARN", message, meta);
138
146
  };
139
- export const info = (message, meta) => {
140
- log("INFO", message, meta);
147
+ exports.warn = warn;
148
+ const info = (message, meta) => {
149
+ (0, exports.log)("INFO", message, meta);
141
150
  };
142
- export const log = (level, message, meta) => {
151
+ exports.info = info;
152
+ const log = (level, message, meta) => {
143
153
  const timestamp = new Date().toISOString();
144
154
  // انتخاب رنگ فقط در dev
145
155
  let color = colors.RESET;
@@ -157,7 +167,7 @@ export const log = (level, message, meta) => {
157
167
  if (stack) {
158
168
  const match = stack.match(/\((.*):(\d+):(\d+)\)/);
159
169
  if (match) {
160
- const fileName = path.basename(match[1]);
170
+ const fileName = path_1.default.basename(match[1]);
161
171
  const line = match[2];
162
172
  const column = match[3];
163
173
  location = `${fileName}:${line}:${column}`;
@@ -167,29 +177,31 @@ export const log = (level, message, meta) => {
167
177
  // چاپ لاگ
168
178
  console.log(`${color}[${timestamp}][${location}][${level}] ${message}${metaStr}${colors.RESET}`);
169
179
  };
170
- export const handleRestException = (req, res, err) => {
180
+ exports.log = log;
181
+ const handleRestException = (req, res, err) => {
171
182
  if (err instanceof ServiceException) {
172
183
  if (err?.status === 401) {
173
- RestResponse.unauthorized(req, res, err.message);
184
+ exports.RestResponse.unauthorized(req, res, err.message);
174
185
  }
175
186
  else if (err?.status === 403) {
176
- RestResponse.accessDenied(req, res, err.message);
187
+ exports.RestResponse.accessDenied(req, res, err.message);
177
188
  }
178
189
  else if (err?.status === 400) {
179
- RestResponse.validationError(req, res, err.errors);
190
+ exports.RestResponse.validationError(req, res, err.errors);
180
191
  }
181
192
  else if (err?.status === 500) {
182
- RestResponse.exceptionError(req, res, err.message);
193
+ exports.RestResponse.exceptionError(req, res, err.message);
183
194
  }
184
195
  else if (err?.status === 404) {
185
- RestResponse.notFound(req, res, err.message);
196
+ exports.RestResponse.notFound(req, res, err.message);
186
197
  }
187
198
  }
188
199
  else if (err instanceof Error) {
189
- RestResponse.exceptionError(req, res, err.message);
200
+ exports.RestResponse.exceptionError(req, res, err.message);
190
201
  }
191
202
  };
192
- export const handleValidationException = (error) => {
203
+ exports.handleRestException = handleRestException;
204
+ const handleValidationException = (error) => {
193
205
  const zodError = error;
194
206
  if (zodError.issues) {
195
207
  const validationErrors = {};
@@ -203,3 +215,13 @@ export const handleValidationException = (error) => {
203
215
  }
204
216
  throw new ServiceException("Internal server error", 500, error);
205
217
  };
218
+ exports.handleValidationException = handleValidationException;
219
+ class ServiceException extends Error {
220
+ constructor(message, status = 400, errors = null) {
221
+ super(message);
222
+ this.name = "ServiceException";
223
+ this.status = status;
224
+ this.errors = errors;
225
+ }
226
+ }
227
+ exports.ServiceException = ServiceException;
package/dist/types.js CHANGED
@@ -1 +1,2 @@
1
- export {};
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/dist/utils.js CHANGED
@@ -1,7 +1,12 @@
1
- import { v4 as uuidv4 } from "uuid";
2
- export const generateRequestId = () => {
3
- return uuidv4();
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getTimestamp = exports.generateRequestId = void 0;
4
+ const uuid_1 = require("uuid");
5
+ const generateRequestId = () => {
6
+ return (0, uuid_1.v4)();
4
7
  };
5
- export const getTimestamp = () => {
8
+ exports.generateRequestId = generateRequestId;
9
+ const getTimestamp = () => {
6
10
  return new Date().toISOString();
7
11
  };
12
+ exports.getTimestamp = getTimestamp;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "response-standardizer",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "Express middleware to standardize API responses",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/index.ts CHANGED
@@ -1,11 +1,10 @@
1
1
  import { Request, Response, NextFunction } from "express";
2
- import { ErrorFields, StandardResponse, RestResponseFunctions, RestMiddlewareFunctions, AuthRequest, Pagination } from "./types.js";
3
- import { generateRequestId, getTimestamp } from "./utils.js";
2
+ import { ErrorFields, StandardResponse, RestResponseFunctions, RestMiddlewareFunctions, AuthRequest, Pagination } from "./types";
3
+ import { generateRequestId, getTimestamp } from "./utils";
4
4
  import axios from "axios";
5
5
  import jwt, { TokenExpiredError } from "jsonwebtoken";
6
6
  import path from "path";
7
7
  import { ZodError } from "zod";
8
- import { ServiceException } from "./service.exception.js";
9
8
  declare global {
10
9
  namespace Express {
11
10
  interface Response {
@@ -259,4 +258,15 @@ export const handleValidationException = (error: any) => {
259
258
  throw new ServiceException("Validation error", 400, validationErrors);
260
259
  }
261
260
  throw new ServiceException("Internal server error", 500, error);
261
+ }
262
+
263
+ export class ServiceException extends Error {
264
+ status: number;
265
+ errors: any
266
+ constructor(message: string, status: number = 400, errors: any = null) {
267
+ super(message);
268
+ this.name = "ServiceException";
269
+ this.status = status;
270
+ this.errors = errors;
271
+ }
262
272
  }
package/src/utils.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { v4 as uuidv4 } from "uuid";
2
- import { RestResponse } from ".";
3
2
 
4
3
  export const generateRequestId = () => {
5
4
  return uuidv4();
package/tsconfig.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "target": "ES2020",
4
- "module": "ESNext",
4
+ "module": "CommonJS",
5
5
  "moduleResolution": "Node",
6
- "declaration": true,
6
+ "rootDir": "src",
7
7
  "outDir": "dist",
8
8
  "strict": true,
9
9
  "esModuleInterop": true,
10
+ "forceConsistentCasingInFileNames": true,
10
11
  "skipLibCheck": true
11
12
  },
12
- "include": ["src/**/*.ts"]
13
+ "include": ["src/**/*"]
13
14
  }
package/dist/index.d.ts DELETED
@@ -1,27 +0,0 @@
1
- import { Request, Response } from "express";
2
- import { RestResponseFunctions, RestMiddlewareFunctions } from "./types.js";
3
- declare global {
4
- namespace Express {
5
- interface Response {
6
- json: (data: any) => Response;
7
- send: (data?: any) => Response;
8
- locals: {
9
- requestId: string;
10
- [key: string]: any;
11
- };
12
- }
13
- }
14
- }
15
- export declare const initKeycloak: (config: {
16
- service?: string;
17
- realm?: string;
18
- }) => Promise<void>;
19
- export declare const protect: (allowedRoles?: string[]) => (req: any, res: any, next: any) => void;
20
- export declare const RestResponse: RestResponseFunctions;
21
- export declare const RestMiddleware: RestMiddlewareFunctions;
22
- export declare const error: (message: string, meta?: any) => void;
23
- export declare const warn: (message: string, meta?: any) => void;
24
- export declare const info: (message: string, meta?: any) => void;
25
- export declare const log: (level: "INFO" | "WARN" | "ERROR", message: string, meta?: any) => void;
26
- export declare const handleRestException: (req: Request, res: Response, err: Error) => void;
27
- export declare const handleValidationException: (error: any) => never;
@@ -1,5 +0,0 @@
1
- export declare class ServiceException extends Error {
2
- status: number;
3
- errors: any;
4
- constructor(message: string, status?: number, errors?: any);
5
- }
@@ -1,8 +0,0 @@
1
- export class ServiceException extends Error {
2
- constructor(message, status = 400, errors = null) {
3
- super(message);
4
- this.name = "ServiceException";
5
- this.status = status;
6
- this.errors = errors;
7
- }
8
- }
package/dist/types.d.ts DELETED
@@ -1,40 +0,0 @@
1
- import { Request, Response, NextFunction } from "express";
2
- export interface StandardResponse<T = any> {
3
- code: number;
4
- message: string;
5
- errors: Record<string, string[]> | null;
6
- meta: {
7
- requestId: string;
8
- timestamp: string;
9
- };
10
- }
11
- export interface PaginationMeta {
12
- total: number;
13
- page: number;
14
- limit: number;
15
- totalPages: number;
16
- }
17
- export interface Pagination<T> {
18
- data: T[];
19
- meta: PaginationMeta;
20
- }
21
- export type ErrorFields = Record<string, string[]>;
22
- export type Middleware = (req: Request, res: Response, next: NextFunction) => void;
23
- export interface RestMiddlewareFunctions {
24
- responseHandlerMiddleware: <T>(req: Request, res: Response, next: NextFunction) => void;
25
- }
26
- export interface RestResponseFunctions {
27
- success: <T>(req: Request, res: Response, data: T) => void;
28
- paginate: <T>(req: Request, res: Response, data: Pagination<T>) => void;
29
- created: <T>(req: Request, res: Response, data: T) => void;
30
- deleted: (req: Request, res: Response) => void;
31
- validationError: (req: Request, res: Response, errors: ErrorFields, message?: string) => void;
32
- exceptionError: (req: Request, res: Response, errors: any, message?: string) => void;
33
- unauthorized: (req: Request, res: Response, message?: string) => void;
34
- accessDenied: (req: Request, res: Response, message?: string) => void;
35
- notFound: (req: Request, res: Response, message?: string) => void;
36
- }
37
- export interface AuthRequest extends Request {
38
- user?: any;
39
- token?: string;
40
- }
package/dist/utils.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export declare const generateRequestId: () => string;
2
- export declare const getTimestamp: () => string;
@@ -1,10 +0,0 @@
1
- export class ServiceException extends Error {
2
- status: number;
3
- errors: any
4
- constructor(message: string, status: number = 400, errors: any = null) {
5
- super(message);
6
- this.name = "ServiceException";
7
- this.status = status;
8
- this.errors = errors;
9
- }
10
- }