express-resforge 1.0.0
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/CHANGELOG.md +27 -0
- package/LICENSE +21 -0
- package/README.md +309 -0
- package/dist/constants/defaultMessages.d.ts +5 -0
- package/dist/constants/defaultMessages.js +29 -0
- package/dist/constants/httpStatus.d.ts +28 -0
- package/dist/constants/httpStatus.js +33 -0
- package/dist/constants/responseCodes.d.ts +22 -0
- package/dist/constants/responseCodes.js +25 -0
- package/dist/core/context.d.ts +36 -0
- package/dist/core/context.js +45 -0
- package/dist/core/formatter.d.ts +7 -0
- package/dist/core/formatter.js +17 -0
- package/dist/core/pluginManager.d.ts +27 -0
- package/dist/core/pluginManager.js +37 -0
- package/dist/core/responseBuilder.d.ts +32 -0
- package/dist/core/responseBuilder.js +107 -0
- package/dist/core/responseFactory.d.ts +12 -0
- package/dist/core/responseFactory.js +52 -0
- package/dist/formatter/axiosFormatter.d.ts +8 -0
- package/dist/formatter/axiosFormatter.js +12 -0
- package/dist/formatter/firebaseFormatter.d.ts +6 -0
- package/dist/formatter/firebaseFormatter.js +19 -0
- package/dist/formatter/joiFormatter.d.ts +8 -0
- package/dist/formatter/joiFormatter.js +26 -0
- package/dist/formatter/mongooseFormatter.d.ts +2 -0
- package/dist/formatter/mongooseFormatter.js +20 -0
- package/dist/formatter/prismaFormatter.d.ts +15 -0
- package/dist/formatter/prismaFormatter.js +49 -0
- package/dist/formatter/zodFormatter.d.ts +9 -0
- package/dist/formatter/zodFormatter.js +27 -0
- package/dist/helpers/cache.d.ts +2 -0
- package/dist/helpers/cache.js +6 -0
- package/dist/helpers/cookies.d.ts +2 -0
- package/dist/helpers/cookies.js +6 -0
- package/dist/helpers/download.d.ts +2 -0
- package/dist/helpers/download.js +6 -0
- package/dist/helpers/errors.d.ts +10 -0
- package/dist/helpers/errors.js +21 -0
- package/dist/helpers/headers.d.ts +2 -0
- package/dist/helpers/headers.js +7 -0
- package/dist/helpers/health.d.ts +2 -0
- package/dist/helpers/health.js +10 -0
- package/dist/helpers/meta.d.ts +2 -0
- package/dist/helpers/meta.js +11 -0
- package/dist/helpers/pagination.d.ts +9 -0
- package/dist/helpers/pagination.js +14 -0
- package/dist/helpers/redirect.d.ts +2 -0
- package/dist/helpers/redirect.js +6 -0
- package/dist/helpers/success.d.ts +3 -0
- package/dist/helpers/success.js +7 -0
- package/dist/helpers/validation.d.ts +2 -0
- package/dist/helpers/validation.js +6 -0
- package/dist/index.d.ts +90 -0
- package/dist/index.js +74 -0
- package/dist/middleware/errorHandler.d.ts +9 -0
- package/dist/middleware/errorHandler.js +90 -0
- package/dist/middleware/requestId.d.ts +16 -0
- package/dist/middleware/requestId.js +18 -0
- package/dist/middleware/requestTimer.d.ts +6 -0
- package/dist/middleware/requestTimer.js +26 -0
- package/dist/middleware/responseMiddleware.d.ts +7 -0
- package/dist/middleware/responseMiddleware.js +93 -0
- package/dist/plugins/pluginAPI.d.ts +7 -0
- package/dist/plugins/pluginAPI.js +12 -0
- package/dist/types/config.d.ts +52 -0
- package/dist/types/config.js +22 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.js +19 -0
- package/dist/types/plugin.d.ts +11 -0
- package/dist/types/plugin.js +2 -0
- package/dist/types/responses.d.ts +72 -0
- package/dist/types/responses.js +6 -0
- package/dist/utils/cleanObject.d.ts +11 -0
- package/dist/utils/cleanObject.js +26 -0
- package/dist/utils/deepMerge.d.ts +12 -0
- package/dist/utils/deepMerge.js +43 -0
- package/dist/utils/helpers.d.ts +4 -0
- package/dist/utils/helpers.js +15 -0
- package/dist/utils/time.d.ts +4 -0
- package/dist/utils/time.js +11 -0
- package/dist/utils/uuid.d.ts +9 -0
- package/dist/utils/uuid.js +24 -0
- package/dist/version.d.ts +4 -0
- package/dist/version.js +7 -0
- package/package.json +68 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.globalPluginManager = exports.PluginManager = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Orchestration engine managing registration and execution lifecycle of custom plugins.
|
|
6
|
+
*/
|
|
7
|
+
class PluginManager {
|
|
8
|
+
plugins = [];
|
|
9
|
+
/**
|
|
10
|
+
* Registers a global plugin hook into the internal pipeline.
|
|
11
|
+
* @param plugin The execution interceptor function block.
|
|
12
|
+
*/
|
|
13
|
+
use(plugin) {
|
|
14
|
+
if (typeof plugin === 'function') {
|
|
15
|
+
this.plugins.push(plugin);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Executes all registered plugins sequentially over the payload using a flat loop
|
|
20
|
+
* to guarantee zero-allocation performance overhead.
|
|
21
|
+
*
|
|
22
|
+
* @param payload The generated standard API response object.
|
|
23
|
+
* @param req The raw incoming Express request context.
|
|
24
|
+
* @param res The raw active Express response context.
|
|
25
|
+
* @returns The fully decorated or mutated API payload structure.
|
|
26
|
+
*/
|
|
27
|
+
execute(payload, req, res) {
|
|
28
|
+
let activePayload = payload;
|
|
29
|
+
const length = this.plugins.length;
|
|
30
|
+
for (let i = 0; i < length; i++) {
|
|
31
|
+
activePayload = this.plugins[i](activePayload, req, res) || activePayload;
|
|
32
|
+
}
|
|
33
|
+
return activePayload;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.PluginManager = PluginManager;
|
|
37
|
+
exports.globalPluginManager = new PluginManager();
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Response } from 'express';
|
|
2
|
+
import { ApiResponsePagination, ValidationErrorItem } from '../types/responses';
|
|
3
|
+
/**
|
|
4
|
+
* High-performance fluent response orchestrator supporting dynamic chained configurations.
|
|
5
|
+
* @template T Type of the payload data data-set container.
|
|
6
|
+
*/
|
|
7
|
+
export declare class ResponseBuilder<T = unknown> {
|
|
8
|
+
private readonly _res;
|
|
9
|
+
private readonly _statusCode;
|
|
10
|
+
private readonly _success;
|
|
11
|
+
private readonly _data;
|
|
12
|
+
private _message;
|
|
13
|
+
private _responseCode;
|
|
14
|
+
private _meta;
|
|
15
|
+
private _pagination?;
|
|
16
|
+
private _errors?;
|
|
17
|
+
private readonly _headers;
|
|
18
|
+
private readonly _cookies;
|
|
19
|
+
constructor(_res: Response, _statusCode: number, _success: boolean, _data?: T | null);
|
|
20
|
+
message(msg: string): this;
|
|
21
|
+
code(code: string): this;
|
|
22
|
+
meta(metadata: Record<string, unknown>): this;
|
|
23
|
+
pagination(pag: ApiResponsePagination): this;
|
|
24
|
+
errors(errs: ValidationErrorItem[] | unknown): this;
|
|
25
|
+
header(name: string, value: string): this;
|
|
26
|
+
cookie(name: string, value: string, options?: any): this;
|
|
27
|
+
/**
|
|
28
|
+
* Finalizes the response envelope, triggers cookie/header updates,
|
|
29
|
+
* applies external plugins, and flushes the data down the Express HTTP channel.
|
|
30
|
+
*/
|
|
31
|
+
send(): Response;
|
|
32
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ResponseBuilder = void 0;
|
|
4
|
+
const context_1 = require("./context");
|
|
5
|
+
const cleanObject_1 = require("../utils/cleanObject");
|
|
6
|
+
const deepMerge_1 = require("../utils/deepMerge");
|
|
7
|
+
const pluginManager_1 = require("./pluginManager");
|
|
8
|
+
/**
|
|
9
|
+
* High-performance fluent response orchestrator supporting dynamic chained configurations.
|
|
10
|
+
* @template T Type of the payload data data-set container.
|
|
11
|
+
*/
|
|
12
|
+
class ResponseBuilder {
|
|
13
|
+
_res;
|
|
14
|
+
_statusCode;
|
|
15
|
+
_success;
|
|
16
|
+
_data;
|
|
17
|
+
_message = '';
|
|
18
|
+
_responseCode = 'SUCCESS';
|
|
19
|
+
_meta = {};
|
|
20
|
+
_pagination;
|
|
21
|
+
_errors;
|
|
22
|
+
_headers = {};
|
|
23
|
+
_cookies = [];
|
|
24
|
+
constructor(_res, _statusCode, _success, _data = null) {
|
|
25
|
+
this._res = _res;
|
|
26
|
+
this._statusCode = _statusCode;
|
|
27
|
+
this._success = _success;
|
|
28
|
+
this._data = _data;
|
|
29
|
+
}
|
|
30
|
+
message(msg) {
|
|
31
|
+
this._message = msg;
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
code(code) {
|
|
35
|
+
this._responseCode = code;
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
meta(metadata) {
|
|
39
|
+
this._meta = (0, deepMerge_1.deepMerge)(this._meta, metadata);
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
pagination(pag) {
|
|
43
|
+
this._pagination = pag;
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
errors(errs) {
|
|
47
|
+
this._errors = errs;
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
header(name, value) {
|
|
51
|
+
this._headers[name] = value;
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
cookie(name, value, options) {
|
|
55
|
+
this._cookies.push({ name, value, options });
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Finalizes the response envelope, triggers cookie/header updates,
|
|
60
|
+
* applies external plugins, and flushes the data down the Express HTTP channel.
|
|
61
|
+
*/
|
|
62
|
+
send() {
|
|
63
|
+
// 1. Process custom headers smoothly
|
|
64
|
+
const headerKeys = Object.keys(this._headers);
|
|
65
|
+
for (let i = 0; i < headerKeys.length; i++) {
|
|
66
|
+
this._res.setHeader(headerKeys[i], this._headers[headerKeys[i]]);
|
|
67
|
+
}
|
|
68
|
+
// 2. Inject pending cookies
|
|
69
|
+
const cookieLength = this._cookies.length;
|
|
70
|
+
for (let i = 0; i < cookieLength; i++) {
|
|
71
|
+
const c = this._cookies[i];
|
|
72
|
+
this._res.cookie(c.name, c.value, c.options);
|
|
73
|
+
}
|
|
74
|
+
// 3. Resolve request context variables out-of-band safely
|
|
75
|
+
const reqId = context_1.requestContext.getRequestId();
|
|
76
|
+
const execTime = context_1.requestContext.getExecutionTimeMs();
|
|
77
|
+
const config = this._res.__apiKitConfig;
|
|
78
|
+
// 4. Construct the standard enterprise envelope skeleton
|
|
79
|
+
let payload = {
|
|
80
|
+
success: this._success,
|
|
81
|
+
statusCode: this._statusCode,
|
|
82
|
+
responseCode: this._responseCode,
|
|
83
|
+
message: this._message || (this._res.__apiKitDefaultMessage ?? ''),
|
|
84
|
+
data: this._data,
|
|
85
|
+
meta: (0, cleanObject_1.cleanObject)({
|
|
86
|
+
requestId: reqId,
|
|
87
|
+
timestamp: context_1.requestContext.getStore()?.timestamp ?? new Date().toISOString(),
|
|
88
|
+
executionTimeMs: execTime,
|
|
89
|
+
apiVersion: config?.apiVersion,
|
|
90
|
+
...this._meta
|
|
91
|
+
})
|
|
92
|
+
};
|
|
93
|
+
if (this._pagination)
|
|
94
|
+
payload.pagination = this._pagination;
|
|
95
|
+
if (this._errors)
|
|
96
|
+
payload.errors = this._errors;
|
|
97
|
+
// 5. Execute internal pipeline filters and global plugins
|
|
98
|
+
if (config?.plugins && Array.isArray(config.plugins)) {
|
|
99
|
+
for (let i = 0; i < config.plugins.length; i++) {
|
|
100
|
+
payload = config.plugins[i](payload, this._res.req, this._res) || payload;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
payload = pluginManager_1.globalPluginManager.execute(payload, this._res.req, this._res);
|
|
104
|
+
return this._res.status(this._statusCode).json(payload);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
exports.ResponseBuilder = ResponseBuilder;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Response } from 'express';
|
|
2
|
+
import { ResponseBuilder } from './responseBuilder';
|
|
3
|
+
import { ResponseOptions } from '../types/responses';
|
|
4
|
+
/**
|
|
5
|
+
* Core engine constructing finalized structural responses across all standard HTTP states.
|
|
6
|
+
*/
|
|
7
|
+
export declare class ResponseFactory {
|
|
8
|
+
/**
|
|
9
|
+
* Generates a fully configured, fluent ResponseBuilder wrapper instance.
|
|
10
|
+
*/
|
|
11
|
+
static create<T>(res: Response, statusCode: number, success: boolean, defaultCode: string, arg1?: unknown, arg2?: ResponseOptions): ResponseBuilder<T>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ResponseFactory = void 0;
|
|
4
|
+
const defaultMessages_1 = require("../constants/defaultMessages");
|
|
5
|
+
const responseBuilder_1 = require("./responseBuilder");
|
|
6
|
+
/**
|
|
7
|
+
* Normalizes polymorphic arguments passed to factory response helpers.
|
|
8
|
+
* Bypasses intensive allocation patterns to extract data and options efficiently.
|
|
9
|
+
*/
|
|
10
|
+
function parseArgs(arg1, arg2) {
|
|
11
|
+
if (arg1 === undefined && arg2 === undefined) {
|
|
12
|
+
return { data: null, options: {} };
|
|
13
|
+
}
|
|
14
|
+
// If the first argument matches an explicit options block layout, process as options override
|
|
15
|
+
if (arg1 && typeof arg1 === 'object' && !Array.isArray(arg1) && ('message' in arg1 || 'responseCode' in arg1 || 'meta' in arg1 || 'errors' in arg1 || 'pagination' in arg1)) {
|
|
16
|
+
return { data: null, options: arg1 };
|
|
17
|
+
}
|
|
18
|
+
return { data: arg1, options: arg2 || {} };
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Core engine constructing finalized structural responses across all standard HTTP states.
|
|
22
|
+
*/
|
|
23
|
+
class ResponseFactory {
|
|
24
|
+
/**
|
|
25
|
+
* Generates a fully configured, fluent ResponseBuilder wrapper instance.
|
|
26
|
+
*/
|
|
27
|
+
static create(res, statusCode, success, defaultCode, arg1, arg2) {
|
|
28
|
+
const { data, options } = parseArgs(arg1, arg2);
|
|
29
|
+
// Inject fallback localization message tags directly into the response instance
|
|
30
|
+
res.__apiKitDefaultMessage = options.message || defaultMessages_1.DefaultMessages[statusCode] || '';
|
|
31
|
+
const builder = new responseBuilder_1.ResponseBuilder(res, statusCode, success, data);
|
|
32
|
+
builder.code(options.responseCode || defaultCode);
|
|
33
|
+
if (options.meta)
|
|
34
|
+
builder.meta(options.meta);
|
|
35
|
+
if (options.errors)
|
|
36
|
+
builder.errors(options.errors);
|
|
37
|
+
if (options.pagination) {
|
|
38
|
+
const { page, limit, total } = options.pagination;
|
|
39
|
+
const totalPages = Math.ceil(total / limit) || 1;
|
|
40
|
+
builder.pagination({
|
|
41
|
+
page,
|
|
42
|
+
limit,
|
|
43
|
+
totalElements: total,
|
|
44
|
+
totalPages,
|
|
45
|
+
hasNextPage: page < totalPages,
|
|
46
|
+
hasPrevPage: page > 1,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return builder;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.ResponseFactory = ResponseFactory;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatAxiosError = formatAxiosError;
|
|
4
|
+
function formatAxiosError(err) {
|
|
5
|
+
return {
|
|
6
|
+
message: err.message || 'Upstream network request execution failed.',
|
|
7
|
+
url: err.config?.url,
|
|
8
|
+
method: err.config?.method?.toUpperCase(),
|
|
9
|
+
status: err.response?.status,
|
|
10
|
+
data: err.response?.data,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatFirebaseError = formatFirebaseError;
|
|
4
|
+
function formatFirebaseError(err) {
|
|
5
|
+
const code = err?.code || 'auth/unknown';
|
|
6
|
+
switch (code) {
|
|
7
|
+
case 'auth/user-not-found':
|
|
8
|
+
case 'auth/wrong-password':
|
|
9
|
+
return { statusCode: 401, message: 'Invalid authentication credentials provided.' };
|
|
10
|
+
case 'auth/email-already-in-use':
|
|
11
|
+
return {
|
|
12
|
+
statusCode: 409,
|
|
13
|
+
message: 'The email address provided is already registered.',
|
|
14
|
+
errors: [{ field: 'email', message: 'Email address already in use.', rule: 'unique' }]
|
|
15
|
+
};
|
|
16
|
+
default:
|
|
17
|
+
return { statusCode: 400, message: err.message || 'A cloud platform authentication error occurred.' };
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ValidationErrorItem } from '../types/responses';
|
|
2
|
+
/**
|
|
3
|
+
* Normalizes Joi validation error structures into the enterprise standard format.
|
|
4
|
+
*
|
|
5
|
+
* @param joiError The raw validation error object returned by Joi.
|
|
6
|
+
* @returns {ValidationErrorItem[]} Standardized validation error array.
|
|
7
|
+
*/
|
|
8
|
+
export declare function formatJoiError(joiError: any): ValidationErrorItem[];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatJoiError = formatJoiError;
|
|
4
|
+
/**
|
|
5
|
+
* Normalizes Joi validation error structures into the enterprise standard format.
|
|
6
|
+
*
|
|
7
|
+
* @param joiError The raw validation error object returned by Joi.
|
|
8
|
+
* @returns {ValidationErrorItem[]} Standardized validation error array.
|
|
9
|
+
*/
|
|
10
|
+
function formatJoiError(joiError) {
|
|
11
|
+
if (!joiError || !Array.isArray(joiError.details)) {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
const details = joiError.details;
|
|
15
|
+
const length = details.length;
|
|
16
|
+
const result = new Array(length);
|
|
17
|
+
for (let i = 0; i < length; i++) {
|
|
18
|
+
const detail = details[i];
|
|
19
|
+
result[i] = {
|
|
20
|
+
field: detail.path.join('.') || 'root',
|
|
21
|
+
message: detail.message.replace(/['"]/g, ''), // Cleans up awkward string escape notation from message text
|
|
22
|
+
rule: detail.type,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatMongooseError = formatMongooseError;
|
|
4
|
+
function formatMongooseError(err) {
|
|
5
|
+
if (!err || !err.errors)
|
|
6
|
+
return [];
|
|
7
|
+
const keys = Object.keys(err.errors);
|
|
8
|
+
const length = keys.length;
|
|
9
|
+
const result = new Array(length);
|
|
10
|
+
for (let i = 0; i < length; i++) {
|
|
11
|
+
const key = keys[i];
|
|
12
|
+
const errorItem = err.errors[key];
|
|
13
|
+
result[i] = {
|
|
14
|
+
field: key,
|
|
15
|
+
message: errorItem.message || 'Field validation failed.',
|
|
16
|
+
rule: errorItem.kind || 'mongoose_validation',
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ValidationErrorItem } from '../types/responses';
|
|
2
|
+
interface PrismaErrorResponse {
|
|
3
|
+
statusCode: number;
|
|
4
|
+
message: string;
|
|
5
|
+
errors?: ValidationErrorItem[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Formats Prisma ORM KnownRequestErrors into clean, client-ready responses.
|
|
9
|
+
* Maps cryptic database engine codes into clean HTTP state specifications.
|
|
10
|
+
*
|
|
11
|
+
* @param prismaError The raw exception caught from the Prisma database client layer.
|
|
12
|
+
* @returns {PrismaErrorResponse} Mapped status and safe, sanitized error tracking data.
|
|
13
|
+
*/
|
|
14
|
+
export declare function formatPrismaError(prismaError: any): PrismaErrorResponse;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatPrismaError = formatPrismaError;
|
|
4
|
+
/**
|
|
5
|
+
* Formats Prisma ORM KnownRequestErrors into clean, client-ready responses.
|
|
6
|
+
* Maps cryptic database engine codes into clean HTTP state specifications.
|
|
7
|
+
*
|
|
8
|
+
* @param prismaError The raw exception caught from the Prisma database client layer.
|
|
9
|
+
* @returns {PrismaErrorResponse} Mapped status and safe, sanitized error tracking data.
|
|
10
|
+
*/
|
|
11
|
+
function formatPrismaError(prismaError) {
|
|
12
|
+
const code = prismaError?.code;
|
|
13
|
+
const meta = prismaError?.meta;
|
|
14
|
+
switch (code) {
|
|
15
|
+
case 'P2002': {
|
|
16
|
+
// Unique constraint violation (e.g., trying to re-register an existing email)
|
|
17
|
+
const fields = Array.isArray(meta?.target) ? meta.target.join(', ') : 'field';
|
|
18
|
+
return {
|
|
19
|
+
statusCode: 409, // Conflict
|
|
20
|
+
message: `A resource with this unique value already exists.`,
|
|
21
|
+
errors: [{
|
|
22
|
+
field: fields,
|
|
23
|
+
message: `The value provided for ${fields} conflicts with an existing record.`,
|
|
24
|
+
rule: 'unique_constraint',
|
|
25
|
+
}],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
case 'P2025': // Record to update or delete not found
|
|
29
|
+
return {
|
|
30
|
+
statusCode: 404, // Not Found
|
|
31
|
+
message: meta?.cause || 'The requested database record could not be located.',
|
|
32
|
+
};
|
|
33
|
+
case 'P2003': // Foreign key constraint failed
|
|
34
|
+
return {
|
|
35
|
+
statusCode: 400, // Bad Request
|
|
36
|
+
message: `Database relational integrity check failed.`,
|
|
37
|
+
errors: [{
|
|
38
|
+
field: meta?.field || 'foreign_key',
|
|
39
|
+
message: `Provided foreign key reference does not map to a valid record.`,
|
|
40
|
+
rule: 'foreign_key_constraint',
|
|
41
|
+
}],
|
|
42
|
+
};
|
|
43
|
+
default:
|
|
44
|
+
return {
|
|
45
|
+
statusCode: 500, // Internal Server Error fallback
|
|
46
|
+
message: 'A database processing failure occurred.',
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ValidationErrorItem } from '../types/responses';
|
|
2
|
+
/**
|
|
3
|
+
* Transforms native Zod errors into a unified ValidationErrorItem payload format.
|
|
4
|
+
* Optimized via a single flat loop to prevent unnecessary object mapping allocations.
|
|
5
|
+
*
|
|
6
|
+
* @param zodError The raw error instance caught from Zod validation.
|
|
7
|
+
* @returns {ValidationErrorItem[]} Standardized validation error item collection.
|
|
8
|
+
*/
|
|
9
|
+
export declare function formatZodError(zodError: any): ValidationErrorItem[];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatZodError = formatZodError;
|
|
4
|
+
/**
|
|
5
|
+
* Transforms native Zod errors into a unified ValidationErrorItem payload format.
|
|
6
|
+
* Optimized via a single flat loop to prevent unnecessary object mapping allocations.
|
|
7
|
+
*
|
|
8
|
+
* @param zodError The raw error instance caught from Zod validation.
|
|
9
|
+
* @returns {ValidationErrorItem[]} Standardized validation error item collection.
|
|
10
|
+
*/
|
|
11
|
+
function formatZodError(zodError) {
|
|
12
|
+
if (!zodError || !Array.isArray(zodError.issues)) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
const issues = zodError.issues;
|
|
16
|
+
const length = issues.length;
|
|
17
|
+
const result = new Array(length);
|
|
18
|
+
for (let i = 0; i < length; i++) {
|
|
19
|
+
const issue = issues[i];
|
|
20
|
+
result[i] = {
|
|
21
|
+
field: issue.path.join('.') || 'root',
|
|
22
|
+
message: issue.message,
|
|
23
|
+
rule: issue.code,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.appendSecureCookie = appendSecureCookie;
|
|
4
|
+
function appendSecureCookie(res, name, value, maxAgeMs = 3600000) {
|
|
5
|
+
res.cookie(name, value, { httpOnly: true, secure: true, sameSite: 'strict', maxAge: maxAgeMs });
|
|
6
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Request, Response, NextFunction, RequestHandler } from 'express';
|
|
2
|
+
/**
|
|
3
|
+
* Higher-order async handler wrapper for Express routes.
|
|
4
|
+
* Eliminates the requirement for manual try/catch blocks across controllers.
|
|
5
|
+
* Fully compatible with Express v4 and Express v5 runtime paradigms.
|
|
6
|
+
*
|
|
7
|
+
* @param fn The asynchronous or synchronous target route handler function.
|
|
8
|
+
* @returns An optimized, safe Express RequestHandler.
|
|
9
|
+
*/
|
|
10
|
+
export declare function asyncWrapper(fn: (req: Request, res: Response, next: NextFunction) => Promise<unknown> | unknown): RequestHandler;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.asyncWrapper = asyncWrapper;
|
|
4
|
+
/**
|
|
5
|
+
* Higher-order async handler wrapper for Express routes.
|
|
6
|
+
* Eliminates the requirement for manual try/catch blocks across controllers.
|
|
7
|
+
* Fully compatible with Express v4 and Express v5 runtime paradigms.
|
|
8
|
+
*
|
|
9
|
+
* @param fn The asynchronous or synchronous target route handler function.
|
|
10
|
+
* @returns An optimized, safe Express RequestHandler.
|
|
11
|
+
*/
|
|
12
|
+
function asyncWrapper(fn) {
|
|
13
|
+
return (req, res, next) => {
|
|
14
|
+
// Resolve the handler function call instantly
|
|
15
|
+
const result = fn(req, res, next);
|
|
16
|
+
// Programmatically catch promise rejections without allocating extra promise chains
|
|
17
|
+
if (result && typeof result.catch === 'function') {
|
|
18
|
+
result.catch(next);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.populateSecurityHeaders = populateSecurityHeaders;
|
|
4
|
+
function populateSecurityHeaders(res) {
|
|
5
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
6
|
+
res.setHeader('X-Frame-Options', 'DENY');
|
|
7
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.systemHealthCheck = systemHealthCheck;
|
|
4
|
+
function systemHealthCheck(res) {
|
|
5
|
+
res.status(200).json({
|
|
6
|
+
status: 'UP',
|
|
7
|
+
timestamp: new Date().toISOString(),
|
|
8
|
+
uptimeSec: process.uptime()
|
|
9
|
+
});
|
|
10
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.constructBaseMeta = constructBaseMeta;
|
|
4
|
+
function constructBaseMeta(reqId, apiVersion) {
|
|
5
|
+
return {
|
|
6
|
+
requestId: reqId,
|
|
7
|
+
timestamp: new Date().toISOString(),
|
|
8
|
+
executionTimeMs: 0,
|
|
9
|
+
apiVersion
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { PaginationOptions } from '../types/responses';
|
|
2
|
+
export declare function buildPaginationMeta(options: PaginationOptions): {
|
|
3
|
+
page: number;
|
|
4
|
+
limit: number;
|
|
5
|
+
totalElements: number;
|
|
6
|
+
totalPages: number;
|
|
7
|
+
hasNextPage: boolean;
|
|
8
|
+
hasPrevPage: boolean;
|
|
9
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildPaginationMeta = buildPaginationMeta;
|
|
4
|
+
function buildPaginationMeta(options) {
|
|
5
|
+
const totalPages = Math.ceil(options.total / options.limit) || 1;
|
|
6
|
+
return {
|
|
7
|
+
page: options.page,
|
|
8
|
+
limit: options.limit,
|
|
9
|
+
totalElements: options.total,
|
|
10
|
+
totalPages,
|
|
11
|
+
hasNextPage: options.page < totalPages,
|
|
12
|
+
hasPrevPage: options.page > 1,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sendSuccessResponse = sendSuccessResponse;
|
|
4
|
+
const responseFactory_1 = require("../core/responseFactory");
|
|
5
|
+
function sendSuccessResponse(res, data, msg) {
|
|
6
|
+
return responseFactory_1.ResponseFactory.create(res, 200, true, 'SUCCESS', data, { message: msg });
|
|
7
|
+
}
|