response-standardizer 1.3.5 → 1.3.6

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
@@ -14,6 +14,7 @@ const initKeycloak = async (config) => {
14
14
  const realmUrl = `http://${KEYCLOAK_SERVICE}/realms/${KEYCLOAK_REALM}`;
15
15
  (0, exports.info)(`Keycloak PublicKey Url: ${realmUrl}`);
16
16
  const resp = await axios_1.default.get(realmUrl);
17
+ (0, exports.info)(`Keycloak: ${resp.data}`);
17
18
  const key = resp.data.public_key;
18
19
  KEYCLOAK_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----\n${key.match(/.{1,64}/g)?.join("\n")}\n-----END PUBLIC KEY-----`;
19
20
  };
package/package.json CHANGED
@@ -1,38 +1,38 @@
1
- {
2
- "name": "response-standardizer",
3
- "version": "1.3.5",
4
- "description": "Express middleware to standardize API responses",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "type": "commonjs",
8
- "scripts": {
9
- "build": "tsc",
10
- "prepare": "npm run build"
11
- },
12
- "repository": {
13
- "type": "git",
14
- "url": "git+https://gitlab.com/dezhnevesht-archive-software/response-standardizer.git"
15
- },
16
- "author": "Hamid Atyabi",
17
- "license": "ISC",
18
- "bugs": {
19
- "url": "https://gitlab.com/dezhnevesht-archive-software/response-standardizer/issues"
20
- },
21
- "homepage": "https://gitlab.com/dezhnevesht-archive-software/response-standardizer#readme",
22
- "peerDependencies": {
23
- "express": "^4 || ^5"
24
- },
25
- "dependencies": {
26
- "axios": "^1.13.2",
27
- "jsonwebtoken": "^9.0.2",
28
- "uuid": "^9.0.1",
29
- "zod": "^4.1.12"
30
- },
31
- "devDependencies": {
32
- "@types/express": "^5.0.5",
33
- "@types/jsonwebtoken": "^9.0.10",
34
- "@types/uuid": "^10.0.0",
35
- "ts-node-dev": "^2.0.0",
36
- "typescript": "^5.9.3"
37
- }
38
- }
1
+ {
2
+ "name": "response-standardizer",
3
+ "version": "1.3.6",
4
+ "description": "Express middleware to standardize API responses",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "commonjs",
8
+ "scripts": {
9
+ "build": "tsc",
10
+ "prepare": "npm run build"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://gitlab.com/dezhnevesht-archive-software/response-standardizer.git"
15
+ },
16
+ "author": "Hamid Atyabi",
17
+ "license": "ISC",
18
+ "bugs": {
19
+ "url": "https://gitlab.com/dezhnevesht-archive-software/response-standardizer/issues"
20
+ },
21
+ "homepage": "https://gitlab.com/dezhnevesht-archive-software/response-standardizer#readme",
22
+ "peerDependencies": {
23
+ "express": "^4 || ^5"
24
+ },
25
+ "dependencies": {
26
+ "axios": "^1.13.2",
27
+ "jsonwebtoken": "^9.0.2",
28
+ "uuid": "^9.0.1",
29
+ "zod": "^4.1.12"
30
+ },
31
+ "devDependencies": {
32
+ "@types/express": "^5.0.5",
33
+ "@types/jsonwebtoken": "^9.0.10",
34
+ "@types/uuid": "^10.0.0",
35
+ "ts-node-dev": "^2.0.0",
36
+ "typescript": "^5.9.3"
37
+ }
38
+ }
package/src/exceptions.ts CHANGED
@@ -1,65 +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);
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
65
  }
package/src/index.ts CHANGED
@@ -1,219 +1,220 @@
1
- import { Request, Response, NextFunction } from "express";
2
- import { ErrorFields, StandardResponse, RestResponseFunctions, RestMiddlewareFunctions, AuthRequest, Pagination } from "./types";
3
- import { generateRequestId, getTimestamp } from "./utils";
4
- import axios from "axios";
5
- import jwt, { TokenExpiredError } from "jsonwebtoken";
6
- import path from "path";
7
- import { ZodError } from "zod";
8
- declare global {
9
- namespace Express {
10
- interface Response {
11
- json: (data: any) => Response;
12
- send: (data?: any) => Response;
13
- locals: {
14
- requestId: string;
15
- [key: string]: any;
16
- };
17
- }
18
- }
19
- }
20
- let KEYCLOAK_PUBLIC_KEY: any = null;
21
- export const initKeycloak = async (config: { service?: string; realm?: string }) => {
22
- const KEYCLOAK_SERVICE = config.service ?? "localhost";
23
- const KEYCLOAK_REALM = config.realm ?? "master";
24
- const realmUrl = `http://${KEYCLOAK_SERVICE}/realms/${KEYCLOAK_REALM}`;
25
- info(`Keycloak PublicKey Url: ${realmUrl}`);
26
- const resp = await axios.get(realmUrl);
27
- const key = resp.data.public_key;
28
- KEYCLOAK_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----\n${key.match(/.{1,64}/g)?.join("\n")}\n-----END PUBLIC KEY-----`;
29
- };
30
-
31
- export const protect = (allowedRoles?: string[]) => {
32
- return (req: any, res: any, next: any) => {
33
- const authHeader = req.headers["authorization"];
34
- if (!authHeader)
35
- return RestResponse.unauthorized(req, res)
36
-
37
- const token = authHeader.split(" ")[1];
38
- if (!token)
39
- return RestResponse.unauthorized(req, res, "Token malformed")
40
-
41
- try {
42
- const decoded = jwt.verify(token, KEYCLOAK_PUBLIC_KEY, { algorithms: ["RS256"] });
43
- (req as AuthRequest).user = decoded;
44
- (req as AuthRequest).token = token;
45
- if(allowedRoles)
46
- return role(req, res, next, allowedRoles);
47
-
48
- next();
49
- } catch (err) {
50
- error((err as any)?.message)
51
- return RestResponse.unauthorized(req, res, "Token is not valid")
52
- }
53
- }
54
-
55
- }
56
- const role = (req: any, res: any, next: any, allowedRoles: string[]) => {
57
- const user = req.user;
58
- if (!user) {
59
- return RestResponse.unauthorized(req, res);
60
- }
61
- const realmRoles: string[] = (user?.realm_access?.roles ?? []).map((r: string) => r.toUpperCase());
62
- const clientRoles: string[] = Object.values(user?.resource_access ?? {})
63
- .flatMap((r: any) => r.roles ?? [])
64
- .map((r: string) => r.toUpperCase());
65
- const allowedUpper = allowedRoles.map(r => r === "super-admin"?"ADMIN":`DEZH-${r.toUpperCase()}`);
66
- const allRoles = [...realmRoles, ...clientRoles];
67
- const hasAccess: boolean = allowedUpper.some((role: string) =>
68
- allRoles.includes(role)
69
- );
70
- if (!hasAccess) {
71
- return RestResponse.accessDenied(req, res)
72
- }
73
- next()
74
- }
75
- const success = <T>(req: Request, res: Response, data: T) => {
76
- res.status(200).json(data);
77
- };
78
-
79
- const paginate = <T>(
80
- req: Request,
81
- res: Response,
82
- data: Pagination<T>
83
- ) => {
84
- res.status(200).json(data);
85
- };
86
-
87
- const created = <T>(req: Request, res: Response, data: T) => {
88
- res.status(201).json(data);
89
- };
90
-
91
- const deleted = (req: Request, res: Response) => {
92
- res.status(204).send();
93
- };
94
- const noContent = (req: Request, res: Response) => {
95
- res.status(204).send();
96
- };
97
-
98
- const validationError = (
99
- req: Request,
100
- res: Response,
101
- errors?: ErrorFields,
102
- message = "Validation error"
103
- ) => {
104
- res.status(400).json({ errors, message });
105
- };
106
-
107
- const exceptionError = (
108
- req: Request,
109
- res: Response,
110
- errors: any,
111
- message = "Internal server error"
112
- ) => {
113
- res.status(500).json({
114
- message,
115
- errors
116
- });
117
- };
118
-
119
- const unauthorized = (req: Request, res: Response, message = "Unauthorized") => {
120
- res.status(401).json({ message });
121
- };
122
-
123
- const accessDenied = (req: Request, res: Response, message = "Access denied") => {
124
- res.status(403).json({ message });
125
- };
126
-
127
- const notFound = (req: Request, res: Response, message = "Not found") => {
128
- res.status(404).json({ message });
129
- };
130
-
131
- export const RestResponse: RestResponseFunctions = {
132
- success,
133
- paginate,
134
- created,
135
- deleted,
136
- noContent,
137
- validationError,
138
- exceptionError,
139
- unauthorized,
140
- accessDenied,
141
- notFound
142
- };
143
-
144
-
145
- const responseHandlerMiddleware = (
146
- req: Request,
147
- res: Response,
148
- next: NextFunction
149
- ) => {
150
-
151
- const oldJson = res.json.bind(res);
152
- const oldSend = res.send.bind(res);
153
-
154
- res.json = function (data: any) {
155
- if(res.statusCode > 204){
156
- const response: StandardResponse = {
157
- code: res.statusCode,
158
- message: data?.message || res.locals.message || (res.statusCode < 300 ? "OK" : "Error"),
159
- errors: data?.errors ?? null,
160
- meta: {
161
- requestId: res.locals.requestId || generateRequestId(),
162
- timestamp: getTimestamp()
163
- }
164
- };
165
-
166
- return oldJson(response);
167
- }
168
- return oldJson(data);
169
- };
170
-
171
- res.send = function (data: any) {
172
- if (res.statusCode === 204) {
173
- return oldSend();
174
- }
175
- return oldSend(data);
176
- };
177
-
178
- res.locals.requestId = generateRequestId();
179
- next();
180
- };
181
-
182
-
183
- export const RestMiddleware: RestMiddlewareFunctions = {
184
- responseHandlerMiddleware
185
- }
186
-
187
-
188
- const colors = {
189
- RESET: "\x1b[0m",
190
- RED: "\x1b[31m",
191
- GREEN: "\x1b[32m",
192
- YELLOW: "\x1b[33m"
193
- };
194
-
195
- const isProduction = process.env.NODE_ENV === "production";
196
- export const error = (message: string, meta?: any) => {
197
- log("ERROR", message, meta)
198
- }
199
- export const warn = (message: string, meta?: any) => {
200
- log("WARN", message, meta)
201
- }
202
- export const info = (message: string, meta?: any) => {
203
- log("INFO", message, meta)
204
- }
205
- export const log = (level: "INFO" | "WARN" | "ERROR", message: string, meta?: any) => {
206
- const timestamp = new Date().toISOString();
207
-
208
- // انتخاب رنگ فقط در dev
209
- let color = colors.RESET;
210
- if (!isProduction) {
211
- if (level === "INFO") color = colors.GREEN;
212
- if (level === "WARN") color = colors.YELLOW;
213
- if (level === "ERROR") color = colors.RED;
214
- }
215
- const metaStr = meta ? `. ${JSON.stringify(meta)}` : "";
216
-
217
- // چاپ لاگ
218
- console.log(`${color}[${timestamp}][${level}] ${message}${metaStr}${colors.RESET}`);
1
+ import { Request, Response, NextFunction } from "express";
2
+ import { ErrorFields, StandardResponse, RestResponseFunctions, RestMiddlewareFunctions, AuthRequest, Pagination } from "./types";
3
+ import { generateRequestId, getTimestamp } from "./utils";
4
+ import axios from "axios";
5
+ import jwt, { TokenExpiredError } from "jsonwebtoken";
6
+ import path from "path";
7
+ import { ZodError } from "zod";
8
+ declare global {
9
+ namespace Express {
10
+ interface Response {
11
+ json: (data: any) => Response;
12
+ send: (data?: any) => Response;
13
+ locals: {
14
+ requestId: string;
15
+ [key: string]: any;
16
+ };
17
+ }
18
+ }
19
+ }
20
+ let KEYCLOAK_PUBLIC_KEY: any = null;
21
+ export const initKeycloak = async (config: { service?: string; realm?: string }) => {
22
+ const KEYCLOAK_SERVICE = config.service ?? "localhost";
23
+ const KEYCLOAK_REALM = config.realm ?? "master";
24
+ const realmUrl = `http://${KEYCLOAK_SERVICE}/realms/${KEYCLOAK_REALM}`;
25
+ info(`Keycloak PublicKey Url: ${realmUrl}`);
26
+ const resp = await axios.get(realmUrl);
27
+ info(`Keycloak: ${resp.data}`);
28
+ const key = resp.data.public_key;
29
+ KEYCLOAK_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----\n${key.match(/.{1,64}/g)?.join("\n")}\n-----END PUBLIC KEY-----`;
30
+ };
31
+
32
+ export const protect = (allowedRoles?: string[]) => {
33
+ return (req: any, res: any, next: any) => {
34
+ const authHeader = req.headers["authorization"];
35
+ if (!authHeader)
36
+ return RestResponse.unauthorized(req, res)
37
+
38
+ const token = authHeader.split(" ")[1];
39
+ if (!token)
40
+ return RestResponse.unauthorized(req, res, "Token malformed")
41
+
42
+ try {
43
+ const decoded = jwt.verify(token, KEYCLOAK_PUBLIC_KEY, { algorithms: ["RS256"] });
44
+ (req as AuthRequest).user = decoded;
45
+ (req as AuthRequest).token = token;
46
+ if(allowedRoles)
47
+ return role(req, res, next, allowedRoles);
48
+
49
+ next();
50
+ } catch (err) {
51
+ error((err as any)?.message)
52
+ return RestResponse.unauthorized(req, res, "Token is not valid")
53
+ }
54
+ }
55
+
56
+ }
57
+ const role = (req: any, res: any, next: any, allowedRoles: string[]) => {
58
+ const user = req.user;
59
+ if (!user) {
60
+ return RestResponse.unauthorized(req, res);
61
+ }
62
+ const realmRoles: string[] = (user?.realm_access?.roles ?? []).map((r: string) => r.toUpperCase());
63
+ const clientRoles: string[] = Object.values(user?.resource_access ?? {})
64
+ .flatMap((r: any) => r.roles ?? [])
65
+ .map((r: string) => r.toUpperCase());
66
+ const allowedUpper = allowedRoles.map(r => r === "super-admin"?"ADMIN":`DEZH-${r.toUpperCase()}`);
67
+ const allRoles = [...realmRoles, ...clientRoles];
68
+ const hasAccess: boolean = allowedUpper.some((role: string) =>
69
+ allRoles.includes(role)
70
+ );
71
+ if (!hasAccess) {
72
+ return RestResponse.accessDenied(req, res)
73
+ }
74
+ next()
75
+ }
76
+ const success = <T>(req: Request, res: Response, data: T) => {
77
+ res.status(200).json(data);
78
+ };
79
+
80
+ const paginate = <T>(
81
+ req: Request,
82
+ res: Response,
83
+ data: Pagination<T>
84
+ ) => {
85
+ res.status(200).json(data);
86
+ };
87
+
88
+ const created = <T>(req: Request, res: Response, data: T) => {
89
+ res.status(201).json(data);
90
+ };
91
+
92
+ const deleted = (req: Request, res: Response) => {
93
+ res.status(204).send();
94
+ };
95
+ const noContent = (req: Request, res: Response) => {
96
+ res.status(204).send();
97
+ };
98
+
99
+ const validationError = (
100
+ req: Request,
101
+ res: Response,
102
+ errors?: ErrorFields,
103
+ message = "Validation error"
104
+ ) => {
105
+ res.status(400).json({ errors, message });
106
+ };
107
+
108
+ const exceptionError = (
109
+ req: Request,
110
+ res: Response,
111
+ errors: any,
112
+ message = "Internal server error"
113
+ ) => {
114
+ res.status(500).json({
115
+ message,
116
+ errors
117
+ });
118
+ };
119
+
120
+ const unauthorized = (req: Request, res: Response, message = "Unauthorized") => {
121
+ res.status(401).json({ message });
122
+ };
123
+
124
+ const accessDenied = (req: Request, res: Response, message = "Access denied") => {
125
+ res.status(403).json({ message });
126
+ };
127
+
128
+ const notFound = (req: Request, res: Response, message = "Not found") => {
129
+ res.status(404).json({ message });
130
+ };
131
+
132
+ export const RestResponse: RestResponseFunctions = {
133
+ success,
134
+ paginate,
135
+ created,
136
+ deleted,
137
+ noContent,
138
+ validationError,
139
+ exceptionError,
140
+ unauthorized,
141
+ accessDenied,
142
+ notFound
143
+ };
144
+
145
+
146
+ const responseHandlerMiddleware = (
147
+ req: Request,
148
+ res: Response,
149
+ next: NextFunction
150
+ ) => {
151
+
152
+ const oldJson = res.json.bind(res);
153
+ const oldSend = res.send.bind(res);
154
+
155
+ res.json = function (data: any) {
156
+ if(res.statusCode > 204){
157
+ const response: StandardResponse = {
158
+ code: res.statusCode,
159
+ message: data?.message || res.locals.message || (res.statusCode < 300 ? "OK" : "Error"),
160
+ errors: data?.errors ?? null,
161
+ meta: {
162
+ requestId: res.locals.requestId || generateRequestId(),
163
+ timestamp: getTimestamp()
164
+ }
165
+ };
166
+
167
+ return oldJson(response);
168
+ }
169
+ return oldJson(data);
170
+ };
171
+
172
+ res.send = function (data: any) {
173
+ if (res.statusCode === 204) {
174
+ return oldSend();
175
+ }
176
+ return oldSend(data);
177
+ };
178
+
179
+ res.locals.requestId = generateRequestId();
180
+ next();
181
+ };
182
+
183
+
184
+ export const RestMiddleware: RestMiddlewareFunctions = {
185
+ responseHandlerMiddleware
186
+ }
187
+
188
+
189
+ const colors = {
190
+ RESET: "\x1b[0m",
191
+ RED: "\x1b[31m",
192
+ GREEN: "\x1b[32m",
193
+ YELLOW: "\x1b[33m"
194
+ };
195
+
196
+ const isProduction = process.env.NODE_ENV === "production";
197
+ export const error = (message: string, meta?: any) => {
198
+ log("ERROR", message, meta)
199
+ }
200
+ export const warn = (message: string, meta?: any) => {
201
+ log("WARN", message, meta)
202
+ }
203
+ export const info = (message: string, meta?: any) => {
204
+ log("INFO", message, meta)
205
+ }
206
+ export const log = (level: "INFO" | "WARN" | "ERROR", message: string, meta?: any) => {
207
+ const timestamp = new Date().toISOString();
208
+
209
+ // انتخاب رنگ فقط در dev
210
+ let color = colors.RESET;
211
+ if (!isProduction) {
212
+ if (level === "INFO") color = colors.GREEN;
213
+ if (level === "WARN") color = colors.YELLOW;
214
+ if (level === "ERROR") color = colors.RED;
215
+ }
216
+ const metaStr = meta ? `. ${JSON.stringify(meta)}` : "";
217
+
218
+ // چاپ لاگ
219
+ console.log(`${color}[${timestamp}][${level}] ${message}${metaStr}${colors.RESET}`);
219
220
  };
package/src/types.ts CHANGED
@@ -1,61 +1,61 @@
1
- import { Request, Response, NextFunction } from "express";
2
-
3
- export interface StandardResponse<T = any> {
4
- code: number;
5
- message: string;
6
- errors: Record<string, string[]> | null;
7
- meta: {
8
- requestId: string;
9
- timestamp: string;
10
- };
11
- }
12
- export interface PaginationMeta{
13
- total: number;
14
- page: number;
15
- limit: number;
16
- totalPages: number;
17
- }
18
- export interface Pagination<T>{
19
- data: T[];
20
- meta: PaginationMeta
21
- }
22
-
23
-
24
- export type ErrorFields = Record<string, string[]>;
25
-
26
- export type Middleware = (req: Request, res: Response, next: NextFunction) => void;
27
-
28
- export interface RestMiddlewareFunctions {
29
- responseHandlerMiddleware: <T>(req: Request, res: Response, next: NextFunction) => void
30
- }
31
- export interface RestResponseFunctions {
32
- success: <T>(req: Request, res: Response, data: T) => void;
33
- paginate: <T>(
34
- req: Request,
35
- res: Response,
36
- data: Pagination<T>
37
- ) => void;
38
- created: <T>(req: Request, res: Response, data: T) => void;
39
- deleted: (req: Request, res: Response) => void;
40
- noContent: (req: Request, res: Response) => void;
41
- validationError: (
42
- req: Request,
43
- res: Response,
44
- errors?: ErrorFields,
45
- message?: string
46
- ) => void;
47
- exceptionError: (
48
- req: Request,
49
- res: Response,
50
- errors: any,
51
- message?: string
52
- ) => void;
53
- unauthorized: (req: Request, res: Response, message?: string) => void;
54
- accessDenied: (req: Request, res: Response, message?: string) => void;
55
- notFound: (req: Request, res: Response, message?: string) => void;
56
- }
57
-
58
- export interface AuthRequest extends Request {
59
- user?: any;
60
- token?: string
1
+ import { Request, Response, NextFunction } from "express";
2
+
3
+ export interface StandardResponse<T = any> {
4
+ code: number;
5
+ message: string;
6
+ errors: Record<string, string[]> | null;
7
+ meta: {
8
+ requestId: string;
9
+ timestamp: string;
10
+ };
11
+ }
12
+ export interface PaginationMeta{
13
+ total: number;
14
+ page: number;
15
+ limit: number;
16
+ totalPages: number;
17
+ }
18
+ export interface Pagination<T>{
19
+ data: T[];
20
+ meta: PaginationMeta
21
+ }
22
+
23
+
24
+ export type ErrorFields = Record<string, string[]>;
25
+
26
+ export type Middleware = (req: Request, res: Response, next: NextFunction) => void;
27
+
28
+ export interface RestMiddlewareFunctions {
29
+ responseHandlerMiddleware: <T>(req: Request, res: Response, next: NextFunction) => void
30
+ }
31
+ export interface RestResponseFunctions {
32
+ success: <T>(req: Request, res: Response, data: T) => void;
33
+ paginate: <T>(
34
+ req: Request,
35
+ res: Response,
36
+ data: Pagination<T>
37
+ ) => void;
38
+ created: <T>(req: Request, res: Response, data: T) => void;
39
+ deleted: (req: Request, res: Response) => void;
40
+ noContent: (req: Request, res: Response) => void;
41
+ validationError: (
42
+ req: Request,
43
+ res: Response,
44
+ errors?: ErrorFields,
45
+ message?: string
46
+ ) => void;
47
+ exceptionError: (
48
+ req: Request,
49
+ res: Response,
50
+ errors: any,
51
+ message?: string
52
+ ) => void;
53
+ unauthorized: (req: Request, res: Response, message?: string) => void;
54
+ accessDenied: (req: Request, res: Response, message?: string) => void;
55
+ notFound: (req: Request, res: Response, message?: string) => void;
56
+ }
57
+
58
+ export interface AuthRequest extends Request {
59
+ user?: any;
60
+ token?: string
61
61
  }
package/src/utils.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { v4 as uuidv4 } from "uuid";
2
-
3
- export const generateRequestId = () => {
4
- return uuidv4();
5
- }
6
-
7
- export const getTimestamp = () => {
8
- return new Date().toISOString();
9
- }
1
+ import { v4 as uuidv4 } from "uuid";
2
+
3
+ export const generateRequestId = () => {
4
+ return uuidv4();
5
+ }
6
+
7
+ export const getTimestamp = () => {
8
+ return new Date().toISOString();
9
+ }
package/tsconfig.json CHANGED
@@ -1,15 +1,15 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "CommonJS",
5
- "moduleResolution": "Node",
6
- "rootDir": "src",
7
- "outDir": "dist",
8
- "strict": true,
9
- "declaration": true,
10
- "esModuleInterop": true,
11
- "forceConsistentCasingInFileNames": true,
12
- "skipLibCheck": true
13
- },
14
- "include": ["src/**/*"]
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "CommonJS",
5
+ "moduleResolution": "Node",
6
+ "rootDir": "src",
7
+ "outDir": "dist",
8
+ "strict": true,
9
+ "declaration": true,
10
+ "esModuleInterop": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "skipLibCheck": true
13
+ },
14
+ "include": ["src/**/*"]
15
15
  }