@mohasinac/errors 0.1.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/dist/index.cjs +269 -0
- package/dist/index.d.cts +96 -0
- package/dist/index.d.ts +96 -0
- package/dist/index.js +234 -0
- package/dist/index.mjs +234 -0
- package/package.json +36 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defProps = Object.defineProperties;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
10
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
11
|
+
var __spreadValues = (a, b) => {
|
|
12
|
+
for (var prop in b || (b = {}))
|
|
13
|
+
if (__hasOwnProp.call(b, prop))
|
|
14
|
+
__defNormalProp(a, prop, b[prop]);
|
|
15
|
+
if (__getOwnPropSymbols)
|
|
16
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
17
|
+
if (__propIsEnum.call(b, prop))
|
|
18
|
+
__defNormalProp(a, prop, b[prop]);
|
|
19
|
+
}
|
|
20
|
+
return a;
|
|
21
|
+
};
|
|
22
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
23
|
+
var __export = (target, all) => {
|
|
24
|
+
for (var name in all)
|
|
25
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
26
|
+
};
|
|
27
|
+
var __copyProps = (to, from, except, desc) => {
|
|
28
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
29
|
+
for (let key of __getOwnPropNames(from))
|
|
30
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
31
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
32
|
+
}
|
|
33
|
+
return to;
|
|
34
|
+
};
|
|
35
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
36
|
+
|
|
37
|
+
// src/index.ts
|
|
38
|
+
var index_exports = {};
|
|
39
|
+
__export(index_exports, {
|
|
40
|
+
ApiError: () => ApiError,
|
|
41
|
+
AppError: () => AppError,
|
|
42
|
+
AuthenticationError: () => AuthenticationError,
|
|
43
|
+
AuthorizationError: () => AuthorizationError,
|
|
44
|
+
DatabaseError: () => DatabaseError,
|
|
45
|
+
ERROR_CODES: () => ERROR_CODES,
|
|
46
|
+
ERROR_MESSAGES: () => ERROR_MESSAGES,
|
|
47
|
+
NotFoundError: () => NotFoundError,
|
|
48
|
+
ValidationError: () => ValidationError,
|
|
49
|
+
handleApiError: () => handleApiError,
|
|
50
|
+
isAppError: () => isAppError,
|
|
51
|
+
logError: () => logError
|
|
52
|
+
});
|
|
53
|
+
module.exports = __toCommonJS(index_exports);
|
|
54
|
+
|
|
55
|
+
// src/base-error.ts
|
|
56
|
+
var AppError = class extends Error {
|
|
57
|
+
constructor(statusCode, message, code, data) {
|
|
58
|
+
super(message);
|
|
59
|
+
this.statusCode = statusCode;
|
|
60
|
+
this.message = message;
|
|
61
|
+
this.code = code;
|
|
62
|
+
this.data = data;
|
|
63
|
+
this.name = this.constructor.name;
|
|
64
|
+
if (Error.captureStackTrace) {
|
|
65
|
+
Error.captureStackTrace(this, this.constructor);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
toJSON() {
|
|
69
|
+
return __spreadValues({
|
|
70
|
+
success: false,
|
|
71
|
+
error: this.message,
|
|
72
|
+
code: this.code,
|
|
73
|
+
statusCode: this.statusCode
|
|
74
|
+
}, this.data !== void 0 && { data: this.data });
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// src/error-codes.ts
|
|
79
|
+
var ERROR_CODES = {
|
|
80
|
+
// Authentication
|
|
81
|
+
AUTH_INVALID_CREDENTIALS: "AUTH_001",
|
|
82
|
+
AUTH_TOKEN_EXPIRED: "AUTH_002",
|
|
83
|
+
AUTH_TOKEN_INVALID: "AUTH_003",
|
|
84
|
+
AUTH_SESSION_EXPIRED: "AUTH_004",
|
|
85
|
+
AUTH_EMAIL_NOT_VERIFIED: "AUTH_005",
|
|
86
|
+
// Validation
|
|
87
|
+
VALIDATION_REQUIRED_FIELD: "VAL_001",
|
|
88
|
+
VALIDATION_INVALID_INPUT: "VAL_002",
|
|
89
|
+
VALIDATION_INVALID_EMAIL: "VAL_003",
|
|
90
|
+
VALIDATION_INVALID_PASSWORD: "VAL_004",
|
|
91
|
+
VALIDATION_INVALID_PHONE: "VAL_005",
|
|
92
|
+
// User
|
|
93
|
+
USER_NOT_FOUND: "USER_001",
|
|
94
|
+
USER_ALREADY_EXISTS: "USER_002",
|
|
95
|
+
USER_NOT_AUTHENTICATED: "USER_003",
|
|
96
|
+
USER_ACCOUNT_DISABLED: "USER_004",
|
|
97
|
+
// Database
|
|
98
|
+
DB_OPERATION_FAILED: "DB_001",
|
|
99
|
+
DB_NOT_FOUND: "DB_002",
|
|
100
|
+
DB_DUPLICATE_ENTRY: "DB_003",
|
|
101
|
+
// Email
|
|
102
|
+
EMAIL_SEND_FAILED: "EMAIL_001",
|
|
103
|
+
EMAIL_INVALID_TEMPLATE: "EMAIL_002",
|
|
104
|
+
EMAIL_RATE_LIMITED: "EMAIL_003",
|
|
105
|
+
EMAIL_DELIVERY_FAILED: "EMAIL_004",
|
|
106
|
+
// Password
|
|
107
|
+
PWD_RESET_TOKEN_EXPIRED: "PWD_001",
|
|
108
|
+
PWD_RESET_TOKEN_INVALID: "PWD_002",
|
|
109
|
+
PWD_TOO_WEAK: "PWD_003",
|
|
110
|
+
PWD_HISTORY_REUSE: "PWD_004",
|
|
111
|
+
PWD_SAME_AS_CURRENT: "PWD_005",
|
|
112
|
+
// Authorization
|
|
113
|
+
AUTHZ_FORBIDDEN: "AUTHZ_001",
|
|
114
|
+
AUTHZ_INSUFFICIENT_ROLE: "AUTHZ_002",
|
|
115
|
+
// General
|
|
116
|
+
GEN_BAD_REQUEST: "GEN_001",
|
|
117
|
+
GEN_NOT_FOUND: "GEN_002",
|
|
118
|
+
GEN_INTERNAL_ERROR: "GEN_003",
|
|
119
|
+
GEN_SERVICE_UNAVAILABLE: "GEN_004",
|
|
120
|
+
GEN_RATE_LIMITED: "GEN_005",
|
|
121
|
+
GEN_UNKNOWN: "GEN_999"
|
|
122
|
+
};
|
|
123
|
+
var ERROR_MESSAGES = {
|
|
124
|
+
// Authentication
|
|
125
|
+
AUTH_001: "Invalid email or password",
|
|
126
|
+
AUTH_002: "Your session has expired. Please log in again",
|
|
127
|
+
AUTH_003: "Invalid authentication token",
|
|
128
|
+
AUTH_004: "Your session has expired. Please log in again",
|
|
129
|
+
AUTH_005: "Please verify your email address before logging in",
|
|
130
|
+
// Validation
|
|
131
|
+
VAL_001: "This field is required",
|
|
132
|
+
VAL_002: "Invalid input provided",
|
|
133
|
+
VAL_003: "Please enter a valid email address",
|
|
134
|
+
VAL_004: "Password must be at least 12 characters with uppercase, lowercase, number and special character",
|
|
135
|
+
VAL_005: "Please enter a valid phone number",
|
|
136
|
+
// User
|
|
137
|
+
USER_001: "User not found",
|
|
138
|
+
USER_002: "An account with this email already exists",
|
|
139
|
+
USER_003: "Please log in to continue",
|
|
140
|
+
USER_004: "Your account has been disabled. Please contact support",
|
|
141
|
+
// Database
|
|
142
|
+
DB_001: "A database error occurred. Please try again",
|
|
143
|
+
DB_002: "The requested resource was not found",
|
|
144
|
+
DB_003: "This record already exists",
|
|
145
|
+
// Email
|
|
146
|
+
EMAIL_001: "Failed to send email. Please try again",
|
|
147
|
+
EMAIL_002: "Invalid email template",
|
|
148
|
+
EMAIL_003: "Too many emails sent. Please wait before trying again",
|
|
149
|
+
EMAIL_004: "Email delivery failed. Please check the address and try again",
|
|
150
|
+
// Password
|
|
151
|
+
PWD_001: "Password reset link has expired. Please request a new one",
|
|
152
|
+
PWD_002: "Invalid password reset link",
|
|
153
|
+
PWD_003: "Password does not meet security requirements",
|
|
154
|
+
PWD_004: "Cannot reuse a recent password",
|
|
155
|
+
PWD_005: "New password must be different from your current password",
|
|
156
|
+
// Authorization
|
|
157
|
+
AUTHZ_001: "You do not have permission to perform this action",
|
|
158
|
+
AUTHZ_002: "Insufficient role to perform this action",
|
|
159
|
+
// General
|
|
160
|
+
GEN_001: "Bad request",
|
|
161
|
+
GEN_002: "The requested resource was not found",
|
|
162
|
+
GEN_003: "An internal server error occurred",
|
|
163
|
+
GEN_004: "Service temporarily unavailable",
|
|
164
|
+
GEN_005: "Too many requests. Please slow down",
|
|
165
|
+
GEN_999: "An unknown error occurred"
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
// src/api-error.ts
|
|
169
|
+
var ApiError = class extends AppError {
|
|
170
|
+
constructor(statusCode, message, data) {
|
|
171
|
+
super(statusCode, message, "API_ERROR", data);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
// src/validation-error.ts
|
|
176
|
+
var ValidationError = class extends AppError {
|
|
177
|
+
constructor(message, fields) {
|
|
178
|
+
super(400, message, "VALIDATION_ERROR", fields);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// src/authentication-error.ts
|
|
183
|
+
var AuthenticationError = class extends AppError {
|
|
184
|
+
constructor(message, data) {
|
|
185
|
+
super(401, message, "AUTHENTICATION_ERROR", data);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// src/authorization-error.ts
|
|
190
|
+
var AuthorizationError = class extends AppError {
|
|
191
|
+
constructor(message, data) {
|
|
192
|
+
super(403, message, "AUTHORIZATION_ERROR", data);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
// src/not-found-error.ts
|
|
197
|
+
var NotFoundError = class extends AppError {
|
|
198
|
+
constructor(message, data) {
|
|
199
|
+
super(404, message, "NOT_FOUND", data);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
// src/database-error.ts
|
|
204
|
+
var DatabaseError = class extends AppError {
|
|
205
|
+
constructor(message, data) {
|
|
206
|
+
super(500, message, "DATABASE_ERROR", data);
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
// src/error-handler.ts
|
|
211
|
+
var import_server = require("next/server");
|
|
212
|
+
function handleApiError(error) {
|
|
213
|
+
if (error instanceof AppError) {
|
|
214
|
+
if (error.statusCode >= 500) {
|
|
215
|
+
console.error("[API Error]", {
|
|
216
|
+
code: error.code,
|
|
217
|
+
message: error.message,
|
|
218
|
+
statusCode: error.statusCode,
|
|
219
|
+
data: error.data
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
return import_server.NextResponse.json(error.toJSON(), { status: error.statusCode });
|
|
223
|
+
}
|
|
224
|
+
if (error && typeof error === "object" && "issues" in error) {
|
|
225
|
+
return import_server.NextResponse.json(
|
|
226
|
+
{
|
|
227
|
+
success: false,
|
|
228
|
+
error: "Validation failed",
|
|
229
|
+
code: ERROR_CODES.VALIDATION_INVALID_INPUT,
|
|
230
|
+
data: error
|
|
231
|
+
},
|
|
232
|
+
{ status: 400 }
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
console.error("[Unexpected API Error]", {
|
|
236
|
+
error: error instanceof Error ? { name: error.name, message: error.message, stack: error.stack } : error
|
|
237
|
+
});
|
|
238
|
+
return import_server.NextResponse.json(
|
|
239
|
+
{
|
|
240
|
+
success: false,
|
|
241
|
+
error: ERROR_MESSAGES[ERROR_CODES.GEN_INTERNAL_ERROR],
|
|
242
|
+
code: ERROR_CODES.GEN_INTERNAL_ERROR
|
|
243
|
+
},
|
|
244
|
+
{ status: 500 }
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
function logError(error, context) {
|
|
248
|
+
console.error("[Application Error]", __spreadProps(__spreadValues({}, context && { context }), {
|
|
249
|
+
error: error instanceof Error ? { name: error.name, message: error.message, stack: error.stack } : error
|
|
250
|
+
}));
|
|
251
|
+
}
|
|
252
|
+
function isAppError(error) {
|
|
253
|
+
return error instanceof AppError;
|
|
254
|
+
}
|
|
255
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
256
|
+
0 && (module.exports = {
|
|
257
|
+
ApiError,
|
|
258
|
+
AppError,
|
|
259
|
+
AuthenticationError,
|
|
260
|
+
AuthorizationError,
|
|
261
|
+
DatabaseError,
|
|
262
|
+
ERROR_CODES,
|
|
263
|
+
ERROR_MESSAGES,
|
|
264
|
+
NotFoundError,
|
|
265
|
+
ValidationError,
|
|
266
|
+
handleApiError,
|
|
267
|
+
isAppError,
|
|
268
|
+
logError
|
|
269
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
|
|
3
|
+
declare class AppError extends Error {
|
|
4
|
+
statusCode: number;
|
|
5
|
+
message: string;
|
|
6
|
+
code: string;
|
|
7
|
+
data?: unknown | undefined;
|
|
8
|
+
constructor(statusCode: number, message: string, code: string, data?: unknown | undefined);
|
|
9
|
+
toJSON(): {
|
|
10
|
+
success: false;
|
|
11
|
+
error: string;
|
|
12
|
+
code: string;
|
|
13
|
+
statusCode: number;
|
|
14
|
+
data?: unknown;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
declare const ERROR_CODES: {
|
|
19
|
+
readonly AUTH_INVALID_CREDENTIALS: "AUTH_001";
|
|
20
|
+
readonly AUTH_TOKEN_EXPIRED: "AUTH_002";
|
|
21
|
+
readonly AUTH_TOKEN_INVALID: "AUTH_003";
|
|
22
|
+
readonly AUTH_SESSION_EXPIRED: "AUTH_004";
|
|
23
|
+
readonly AUTH_EMAIL_NOT_VERIFIED: "AUTH_005";
|
|
24
|
+
readonly VALIDATION_REQUIRED_FIELD: "VAL_001";
|
|
25
|
+
readonly VALIDATION_INVALID_INPUT: "VAL_002";
|
|
26
|
+
readonly VALIDATION_INVALID_EMAIL: "VAL_003";
|
|
27
|
+
readonly VALIDATION_INVALID_PASSWORD: "VAL_004";
|
|
28
|
+
readonly VALIDATION_INVALID_PHONE: "VAL_005";
|
|
29
|
+
readonly USER_NOT_FOUND: "USER_001";
|
|
30
|
+
readonly USER_ALREADY_EXISTS: "USER_002";
|
|
31
|
+
readonly USER_NOT_AUTHENTICATED: "USER_003";
|
|
32
|
+
readonly USER_ACCOUNT_DISABLED: "USER_004";
|
|
33
|
+
readonly DB_OPERATION_FAILED: "DB_001";
|
|
34
|
+
readonly DB_NOT_FOUND: "DB_002";
|
|
35
|
+
readonly DB_DUPLICATE_ENTRY: "DB_003";
|
|
36
|
+
readonly EMAIL_SEND_FAILED: "EMAIL_001";
|
|
37
|
+
readonly EMAIL_INVALID_TEMPLATE: "EMAIL_002";
|
|
38
|
+
readonly EMAIL_RATE_LIMITED: "EMAIL_003";
|
|
39
|
+
readonly EMAIL_DELIVERY_FAILED: "EMAIL_004";
|
|
40
|
+
readonly PWD_RESET_TOKEN_EXPIRED: "PWD_001";
|
|
41
|
+
readonly PWD_RESET_TOKEN_INVALID: "PWD_002";
|
|
42
|
+
readonly PWD_TOO_WEAK: "PWD_003";
|
|
43
|
+
readonly PWD_HISTORY_REUSE: "PWD_004";
|
|
44
|
+
readonly PWD_SAME_AS_CURRENT: "PWD_005";
|
|
45
|
+
readonly AUTHZ_FORBIDDEN: "AUTHZ_001";
|
|
46
|
+
readonly AUTHZ_INSUFFICIENT_ROLE: "AUTHZ_002";
|
|
47
|
+
readonly GEN_BAD_REQUEST: "GEN_001";
|
|
48
|
+
readonly GEN_NOT_FOUND: "GEN_002";
|
|
49
|
+
readonly GEN_INTERNAL_ERROR: "GEN_003";
|
|
50
|
+
readonly GEN_SERVICE_UNAVAILABLE: "GEN_004";
|
|
51
|
+
readonly GEN_RATE_LIMITED: "GEN_005";
|
|
52
|
+
readonly GEN_UNKNOWN: "GEN_999";
|
|
53
|
+
};
|
|
54
|
+
type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];
|
|
55
|
+
declare const ERROR_MESSAGES: Record<ErrorCode, string>;
|
|
56
|
+
|
|
57
|
+
declare class ApiError extends AppError {
|
|
58
|
+
constructor(statusCode: number, message: string, data?: unknown);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
declare class ValidationError extends AppError {
|
|
62
|
+
constructor(message: string, fields?: unknown);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
declare class AuthenticationError extends AppError {
|
|
66
|
+
constructor(message: string, data?: unknown);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
declare class AuthorizationError extends AppError {
|
|
70
|
+
constructor(message: string, data?: unknown);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
declare class NotFoundError extends AppError {
|
|
74
|
+
constructor(message: string, data?: unknown);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
declare class DatabaseError extends AppError {
|
|
78
|
+
constructor(message: string, data?: unknown);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Handle API errors with consistent response format.
|
|
83
|
+
* Use in Next.js API route catch blocks.
|
|
84
|
+
*/
|
|
85
|
+
declare function handleApiError(error: unknown): NextResponse;
|
|
86
|
+
/**
|
|
87
|
+
* Log an error with optional context. Wraps console.error for package portability;
|
|
88
|
+
* replace with your structured logger if needed.
|
|
89
|
+
*/
|
|
90
|
+
declare function logError(error: unknown, context?: Record<string, unknown>): void;
|
|
91
|
+
/**
|
|
92
|
+
* Type guard — check if a value is an AppError instance.
|
|
93
|
+
*/
|
|
94
|
+
declare function isAppError(error: unknown): error is AppError;
|
|
95
|
+
|
|
96
|
+
export { ApiError, AppError, AuthenticationError, AuthorizationError, DatabaseError, ERROR_CODES, ERROR_MESSAGES, type ErrorCode, NotFoundError, ValidationError, handleApiError, isAppError, logError };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
|
|
3
|
+
declare class AppError extends Error {
|
|
4
|
+
statusCode: number;
|
|
5
|
+
message: string;
|
|
6
|
+
code: string;
|
|
7
|
+
data?: unknown | undefined;
|
|
8
|
+
constructor(statusCode: number, message: string, code: string, data?: unknown | undefined);
|
|
9
|
+
toJSON(): {
|
|
10
|
+
success: false;
|
|
11
|
+
error: string;
|
|
12
|
+
code: string;
|
|
13
|
+
statusCode: number;
|
|
14
|
+
data?: unknown;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
declare const ERROR_CODES: {
|
|
19
|
+
readonly AUTH_INVALID_CREDENTIALS: "AUTH_001";
|
|
20
|
+
readonly AUTH_TOKEN_EXPIRED: "AUTH_002";
|
|
21
|
+
readonly AUTH_TOKEN_INVALID: "AUTH_003";
|
|
22
|
+
readonly AUTH_SESSION_EXPIRED: "AUTH_004";
|
|
23
|
+
readonly AUTH_EMAIL_NOT_VERIFIED: "AUTH_005";
|
|
24
|
+
readonly VALIDATION_REQUIRED_FIELD: "VAL_001";
|
|
25
|
+
readonly VALIDATION_INVALID_INPUT: "VAL_002";
|
|
26
|
+
readonly VALIDATION_INVALID_EMAIL: "VAL_003";
|
|
27
|
+
readonly VALIDATION_INVALID_PASSWORD: "VAL_004";
|
|
28
|
+
readonly VALIDATION_INVALID_PHONE: "VAL_005";
|
|
29
|
+
readonly USER_NOT_FOUND: "USER_001";
|
|
30
|
+
readonly USER_ALREADY_EXISTS: "USER_002";
|
|
31
|
+
readonly USER_NOT_AUTHENTICATED: "USER_003";
|
|
32
|
+
readonly USER_ACCOUNT_DISABLED: "USER_004";
|
|
33
|
+
readonly DB_OPERATION_FAILED: "DB_001";
|
|
34
|
+
readonly DB_NOT_FOUND: "DB_002";
|
|
35
|
+
readonly DB_DUPLICATE_ENTRY: "DB_003";
|
|
36
|
+
readonly EMAIL_SEND_FAILED: "EMAIL_001";
|
|
37
|
+
readonly EMAIL_INVALID_TEMPLATE: "EMAIL_002";
|
|
38
|
+
readonly EMAIL_RATE_LIMITED: "EMAIL_003";
|
|
39
|
+
readonly EMAIL_DELIVERY_FAILED: "EMAIL_004";
|
|
40
|
+
readonly PWD_RESET_TOKEN_EXPIRED: "PWD_001";
|
|
41
|
+
readonly PWD_RESET_TOKEN_INVALID: "PWD_002";
|
|
42
|
+
readonly PWD_TOO_WEAK: "PWD_003";
|
|
43
|
+
readonly PWD_HISTORY_REUSE: "PWD_004";
|
|
44
|
+
readonly PWD_SAME_AS_CURRENT: "PWD_005";
|
|
45
|
+
readonly AUTHZ_FORBIDDEN: "AUTHZ_001";
|
|
46
|
+
readonly AUTHZ_INSUFFICIENT_ROLE: "AUTHZ_002";
|
|
47
|
+
readonly GEN_BAD_REQUEST: "GEN_001";
|
|
48
|
+
readonly GEN_NOT_FOUND: "GEN_002";
|
|
49
|
+
readonly GEN_INTERNAL_ERROR: "GEN_003";
|
|
50
|
+
readonly GEN_SERVICE_UNAVAILABLE: "GEN_004";
|
|
51
|
+
readonly GEN_RATE_LIMITED: "GEN_005";
|
|
52
|
+
readonly GEN_UNKNOWN: "GEN_999";
|
|
53
|
+
};
|
|
54
|
+
type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];
|
|
55
|
+
declare const ERROR_MESSAGES: Record<ErrorCode, string>;
|
|
56
|
+
|
|
57
|
+
declare class ApiError extends AppError {
|
|
58
|
+
constructor(statusCode: number, message: string, data?: unknown);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
declare class ValidationError extends AppError {
|
|
62
|
+
constructor(message: string, fields?: unknown);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
declare class AuthenticationError extends AppError {
|
|
66
|
+
constructor(message: string, data?: unknown);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
declare class AuthorizationError extends AppError {
|
|
70
|
+
constructor(message: string, data?: unknown);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
declare class NotFoundError extends AppError {
|
|
74
|
+
constructor(message: string, data?: unknown);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
declare class DatabaseError extends AppError {
|
|
78
|
+
constructor(message: string, data?: unknown);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Handle API errors with consistent response format.
|
|
83
|
+
* Use in Next.js API route catch blocks.
|
|
84
|
+
*/
|
|
85
|
+
declare function handleApiError(error: unknown): NextResponse;
|
|
86
|
+
/**
|
|
87
|
+
* Log an error with optional context. Wraps console.error for package portability;
|
|
88
|
+
* replace with your structured logger if needed.
|
|
89
|
+
*/
|
|
90
|
+
declare function logError(error: unknown, context?: Record<string, unknown>): void;
|
|
91
|
+
/**
|
|
92
|
+
* Type guard — check if a value is an AppError instance.
|
|
93
|
+
*/
|
|
94
|
+
declare function isAppError(error: unknown): error is AppError;
|
|
95
|
+
|
|
96
|
+
export { ApiError, AppError, AuthenticationError, AuthorizationError, DatabaseError, ERROR_CODES, ERROR_MESSAGES, type ErrorCode, NotFoundError, ValidationError, handleApiError, isAppError, logError };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
|
|
21
|
+
// src/base-error.ts
|
|
22
|
+
var AppError = class extends Error {
|
|
23
|
+
constructor(statusCode, message, code, data) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.statusCode = statusCode;
|
|
26
|
+
this.message = message;
|
|
27
|
+
this.code = code;
|
|
28
|
+
this.data = data;
|
|
29
|
+
this.name = this.constructor.name;
|
|
30
|
+
if (Error.captureStackTrace) {
|
|
31
|
+
Error.captureStackTrace(this, this.constructor);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
toJSON() {
|
|
35
|
+
return __spreadValues({
|
|
36
|
+
success: false,
|
|
37
|
+
error: this.message,
|
|
38
|
+
code: this.code,
|
|
39
|
+
statusCode: this.statusCode
|
|
40
|
+
}, this.data !== void 0 && { data: this.data });
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// src/error-codes.ts
|
|
45
|
+
var ERROR_CODES = {
|
|
46
|
+
// Authentication
|
|
47
|
+
AUTH_INVALID_CREDENTIALS: "AUTH_001",
|
|
48
|
+
AUTH_TOKEN_EXPIRED: "AUTH_002",
|
|
49
|
+
AUTH_TOKEN_INVALID: "AUTH_003",
|
|
50
|
+
AUTH_SESSION_EXPIRED: "AUTH_004",
|
|
51
|
+
AUTH_EMAIL_NOT_VERIFIED: "AUTH_005",
|
|
52
|
+
// Validation
|
|
53
|
+
VALIDATION_REQUIRED_FIELD: "VAL_001",
|
|
54
|
+
VALIDATION_INVALID_INPUT: "VAL_002",
|
|
55
|
+
VALIDATION_INVALID_EMAIL: "VAL_003",
|
|
56
|
+
VALIDATION_INVALID_PASSWORD: "VAL_004",
|
|
57
|
+
VALIDATION_INVALID_PHONE: "VAL_005",
|
|
58
|
+
// User
|
|
59
|
+
USER_NOT_FOUND: "USER_001",
|
|
60
|
+
USER_ALREADY_EXISTS: "USER_002",
|
|
61
|
+
USER_NOT_AUTHENTICATED: "USER_003",
|
|
62
|
+
USER_ACCOUNT_DISABLED: "USER_004",
|
|
63
|
+
// Database
|
|
64
|
+
DB_OPERATION_FAILED: "DB_001",
|
|
65
|
+
DB_NOT_FOUND: "DB_002",
|
|
66
|
+
DB_DUPLICATE_ENTRY: "DB_003",
|
|
67
|
+
// Email
|
|
68
|
+
EMAIL_SEND_FAILED: "EMAIL_001",
|
|
69
|
+
EMAIL_INVALID_TEMPLATE: "EMAIL_002",
|
|
70
|
+
EMAIL_RATE_LIMITED: "EMAIL_003",
|
|
71
|
+
EMAIL_DELIVERY_FAILED: "EMAIL_004",
|
|
72
|
+
// Password
|
|
73
|
+
PWD_RESET_TOKEN_EXPIRED: "PWD_001",
|
|
74
|
+
PWD_RESET_TOKEN_INVALID: "PWD_002",
|
|
75
|
+
PWD_TOO_WEAK: "PWD_003",
|
|
76
|
+
PWD_HISTORY_REUSE: "PWD_004",
|
|
77
|
+
PWD_SAME_AS_CURRENT: "PWD_005",
|
|
78
|
+
// Authorization
|
|
79
|
+
AUTHZ_FORBIDDEN: "AUTHZ_001",
|
|
80
|
+
AUTHZ_INSUFFICIENT_ROLE: "AUTHZ_002",
|
|
81
|
+
// General
|
|
82
|
+
GEN_BAD_REQUEST: "GEN_001",
|
|
83
|
+
GEN_NOT_FOUND: "GEN_002",
|
|
84
|
+
GEN_INTERNAL_ERROR: "GEN_003",
|
|
85
|
+
GEN_SERVICE_UNAVAILABLE: "GEN_004",
|
|
86
|
+
GEN_RATE_LIMITED: "GEN_005",
|
|
87
|
+
GEN_UNKNOWN: "GEN_999"
|
|
88
|
+
};
|
|
89
|
+
var ERROR_MESSAGES = {
|
|
90
|
+
// Authentication
|
|
91
|
+
AUTH_001: "Invalid email or password",
|
|
92
|
+
AUTH_002: "Your session has expired. Please log in again",
|
|
93
|
+
AUTH_003: "Invalid authentication token",
|
|
94
|
+
AUTH_004: "Your session has expired. Please log in again",
|
|
95
|
+
AUTH_005: "Please verify your email address before logging in",
|
|
96
|
+
// Validation
|
|
97
|
+
VAL_001: "This field is required",
|
|
98
|
+
VAL_002: "Invalid input provided",
|
|
99
|
+
VAL_003: "Please enter a valid email address",
|
|
100
|
+
VAL_004: "Password must be at least 12 characters with uppercase, lowercase, number and special character",
|
|
101
|
+
VAL_005: "Please enter a valid phone number",
|
|
102
|
+
// User
|
|
103
|
+
USER_001: "User not found",
|
|
104
|
+
USER_002: "An account with this email already exists",
|
|
105
|
+
USER_003: "Please log in to continue",
|
|
106
|
+
USER_004: "Your account has been disabled. Please contact support",
|
|
107
|
+
// Database
|
|
108
|
+
DB_001: "A database error occurred. Please try again",
|
|
109
|
+
DB_002: "The requested resource was not found",
|
|
110
|
+
DB_003: "This record already exists",
|
|
111
|
+
// Email
|
|
112
|
+
EMAIL_001: "Failed to send email. Please try again",
|
|
113
|
+
EMAIL_002: "Invalid email template",
|
|
114
|
+
EMAIL_003: "Too many emails sent. Please wait before trying again",
|
|
115
|
+
EMAIL_004: "Email delivery failed. Please check the address and try again",
|
|
116
|
+
// Password
|
|
117
|
+
PWD_001: "Password reset link has expired. Please request a new one",
|
|
118
|
+
PWD_002: "Invalid password reset link",
|
|
119
|
+
PWD_003: "Password does not meet security requirements",
|
|
120
|
+
PWD_004: "Cannot reuse a recent password",
|
|
121
|
+
PWD_005: "New password must be different from your current password",
|
|
122
|
+
// Authorization
|
|
123
|
+
AUTHZ_001: "You do not have permission to perform this action",
|
|
124
|
+
AUTHZ_002: "Insufficient role to perform this action",
|
|
125
|
+
// General
|
|
126
|
+
GEN_001: "Bad request",
|
|
127
|
+
GEN_002: "The requested resource was not found",
|
|
128
|
+
GEN_003: "An internal server error occurred",
|
|
129
|
+
GEN_004: "Service temporarily unavailable",
|
|
130
|
+
GEN_005: "Too many requests. Please slow down",
|
|
131
|
+
GEN_999: "An unknown error occurred"
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// src/api-error.ts
|
|
135
|
+
var ApiError = class extends AppError {
|
|
136
|
+
constructor(statusCode, message, data) {
|
|
137
|
+
super(statusCode, message, "API_ERROR", data);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// src/validation-error.ts
|
|
142
|
+
var ValidationError = class extends AppError {
|
|
143
|
+
constructor(message, fields) {
|
|
144
|
+
super(400, message, "VALIDATION_ERROR", fields);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// src/authentication-error.ts
|
|
149
|
+
var AuthenticationError = class extends AppError {
|
|
150
|
+
constructor(message, data) {
|
|
151
|
+
super(401, message, "AUTHENTICATION_ERROR", data);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// src/authorization-error.ts
|
|
156
|
+
var AuthorizationError = class extends AppError {
|
|
157
|
+
constructor(message, data) {
|
|
158
|
+
super(403, message, "AUTHORIZATION_ERROR", data);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// src/not-found-error.ts
|
|
163
|
+
var NotFoundError = class extends AppError {
|
|
164
|
+
constructor(message, data) {
|
|
165
|
+
super(404, message, "NOT_FOUND", data);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// src/database-error.ts
|
|
170
|
+
var DatabaseError = class extends AppError {
|
|
171
|
+
constructor(message, data) {
|
|
172
|
+
super(500, message, "DATABASE_ERROR", data);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// src/error-handler.ts
|
|
177
|
+
import { NextResponse } from "next/server";
|
|
178
|
+
function handleApiError(error) {
|
|
179
|
+
if (error instanceof AppError) {
|
|
180
|
+
if (error.statusCode >= 500) {
|
|
181
|
+
console.error("[API Error]", {
|
|
182
|
+
code: error.code,
|
|
183
|
+
message: error.message,
|
|
184
|
+
statusCode: error.statusCode,
|
|
185
|
+
data: error.data
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
return NextResponse.json(error.toJSON(), { status: error.statusCode });
|
|
189
|
+
}
|
|
190
|
+
if (error && typeof error === "object" && "issues" in error) {
|
|
191
|
+
return NextResponse.json(
|
|
192
|
+
{
|
|
193
|
+
success: false,
|
|
194
|
+
error: "Validation failed",
|
|
195
|
+
code: ERROR_CODES.VALIDATION_INVALID_INPUT,
|
|
196
|
+
data: error
|
|
197
|
+
},
|
|
198
|
+
{ status: 400 }
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
console.error("[Unexpected API Error]", {
|
|
202
|
+
error: error instanceof Error ? { name: error.name, message: error.message, stack: error.stack } : error
|
|
203
|
+
});
|
|
204
|
+
return NextResponse.json(
|
|
205
|
+
{
|
|
206
|
+
success: false,
|
|
207
|
+
error: ERROR_MESSAGES[ERROR_CODES.GEN_INTERNAL_ERROR],
|
|
208
|
+
code: ERROR_CODES.GEN_INTERNAL_ERROR
|
|
209
|
+
},
|
|
210
|
+
{ status: 500 }
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
function logError(error, context) {
|
|
214
|
+
console.error("[Application Error]", __spreadProps(__spreadValues({}, context && { context }), {
|
|
215
|
+
error: error instanceof Error ? { name: error.name, message: error.message, stack: error.stack } : error
|
|
216
|
+
}));
|
|
217
|
+
}
|
|
218
|
+
function isAppError(error) {
|
|
219
|
+
return error instanceof AppError;
|
|
220
|
+
}
|
|
221
|
+
export {
|
|
222
|
+
ApiError,
|
|
223
|
+
AppError,
|
|
224
|
+
AuthenticationError,
|
|
225
|
+
AuthorizationError,
|
|
226
|
+
DatabaseError,
|
|
227
|
+
ERROR_CODES,
|
|
228
|
+
ERROR_MESSAGES,
|
|
229
|
+
NotFoundError,
|
|
230
|
+
ValidationError,
|
|
231
|
+
handleApiError,
|
|
232
|
+
isAppError,
|
|
233
|
+
logError
|
|
234
|
+
};
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
|
|
21
|
+
// src/base-error.ts
|
|
22
|
+
var AppError = class extends Error {
|
|
23
|
+
constructor(statusCode, message, code, data) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.statusCode = statusCode;
|
|
26
|
+
this.message = message;
|
|
27
|
+
this.code = code;
|
|
28
|
+
this.data = data;
|
|
29
|
+
this.name = this.constructor.name;
|
|
30
|
+
if (Error.captureStackTrace) {
|
|
31
|
+
Error.captureStackTrace(this, this.constructor);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
toJSON() {
|
|
35
|
+
return __spreadValues({
|
|
36
|
+
success: false,
|
|
37
|
+
error: this.message,
|
|
38
|
+
code: this.code,
|
|
39
|
+
statusCode: this.statusCode
|
|
40
|
+
}, this.data !== void 0 && { data: this.data });
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// src/error-codes.ts
|
|
45
|
+
var ERROR_CODES = {
|
|
46
|
+
// Authentication
|
|
47
|
+
AUTH_INVALID_CREDENTIALS: "AUTH_001",
|
|
48
|
+
AUTH_TOKEN_EXPIRED: "AUTH_002",
|
|
49
|
+
AUTH_TOKEN_INVALID: "AUTH_003",
|
|
50
|
+
AUTH_SESSION_EXPIRED: "AUTH_004",
|
|
51
|
+
AUTH_EMAIL_NOT_VERIFIED: "AUTH_005",
|
|
52
|
+
// Validation
|
|
53
|
+
VALIDATION_REQUIRED_FIELD: "VAL_001",
|
|
54
|
+
VALIDATION_INVALID_INPUT: "VAL_002",
|
|
55
|
+
VALIDATION_INVALID_EMAIL: "VAL_003",
|
|
56
|
+
VALIDATION_INVALID_PASSWORD: "VAL_004",
|
|
57
|
+
VALIDATION_INVALID_PHONE: "VAL_005",
|
|
58
|
+
// User
|
|
59
|
+
USER_NOT_FOUND: "USER_001",
|
|
60
|
+
USER_ALREADY_EXISTS: "USER_002",
|
|
61
|
+
USER_NOT_AUTHENTICATED: "USER_003",
|
|
62
|
+
USER_ACCOUNT_DISABLED: "USER_004",
|
|
63
|
+
// Database
|
|
64
|
+
DB_OPERATION_FAILED: "DB_001",
|
|
65
|
+
DB_NOT_FOUND: "DB_002",
|
|
66
|
+
DB_DUPLICATE_ENTRY: "DB_003",
|
|
67
|
+
// Email
|
|
68
|
+
EMAIL_SEND_FAILED: "EMAIL_001",
|
|
69
|
+
EMAIL_INVALID_TEMPLATE: "EMAIL_002",
|
|
70
|
+
EMAIL_RATE_LIMITED: "EMAIL_003",
|
|
71
|
+
EMAIL_DELIVERY_FAILED: "EMAIL_004",
|
|
72
|
+
// Password
|
|
73
|
+
PWD_RESET_TOKEN_EXPIRED: "PWD_001",
|
|
74
|
+
PWD_RESET_TOKEN_INVALID: "PWD_002",
|
|
75
|
+
PWD_TOO_WEAK: "PWD_003",
|
|
76
|
+
PWD_HISTORY_REUSE: "PWD_004",
|
|
77
|
+
PWD_SAME_AS_CURRENT: "PWD_005",
|
|
78
|
+
// Authorization
|
|
79
|
+
AUTHZ_FORBIDDEN: "AUTHZ_001",
|
|
80
|
+
AUTHZ_INSUFFICIENT_ROLE: "AUTHZ_002",
|
|
81
|
+
// General
|
|
82
|
+
GEN_BAD_REQUEST: "GEN_001",
|
|
83
|
+
GEN_NOT_FOUND: "GEN_002",
|
|
84
|
+
GEN_INTERNAL_ERROR: "GEN_003",
|
|
85
|
+
GEN_SERVICE_UNAVAILABLE: "GEN_004",
|
|
86
|
+
GEN_RATE_LIMITED: "GEN_005",
|
|
87
|
+
GEN_UNKNOWN: "GEN_999"
|
|
88
|
+
};
|
|
89
|
+
var ERROR_MESSAGES = {
|
|
90
|
+
// Authentication
|
|
91
|
+
AUTH_001: "Invalid email or password",
|
|
92
|
+
AUTH_002: "Your session has expired. Please log in again",
|
|
93
|
+
AUTH_003: "Invalid authentication token",
|
|
94
|
+
AUTH_004: "Your session has expired. Please log in again",
|
|
95
|
+
AUTH_005: "Please verify your email address before logging in",
|
|
96
|
+
// Validation
|
|
97
|
+
VAL_001: "This field is required",
|
|
98
|
+
VAL_002: "Invalid input provided",
|
|
99
|
+
VAL_003: "Please enter a valid email address",
|
|
100
|
+
VAL_004: "Password must be at least 12 characters with uppercase, lowercase, number and special character",
|
|
101
|
+
VAL_005: "Please enter a valid phone number",
|
|
102
|
+
// User
|
|
103
|
+
USER_001: "User not found",
|
|
104
|
+
USER_002: "An account with this email already exists",
|
|
105
|
+
USER_003: "Please log in to continue",
|
|
106
|
+
USER_004: "Your account has been disabled. Please contact support",
|
|
107
|
+
// Database
|
|
108
|
+
DB_001: "A database error occurred. Please try again",
|
|
109
|
+
DB_002: "The requested resource was not found",
|
|
110
|
+
DB_003: "This record already exists",
|
|
111
|
+
// Email
|
|
112
|
+
EMAIL_001: "Failed to send email. Please try again",
|
|
113
|
+
EMAIL_002: "Invalid email template",
|
|
114
|
+
EMAIL_003: "Too many emails sent. Please wait before trying again",
|
|
115
|
+
EMAIL_004: "Email delivery failed. Please check the address and try again",
|
|
116
|
+
// Password
|
|
117
|
+
PWD_001: "Password reset link has expired. Please request a new one",
|
|
118
|
+
PWD_002: "Invalid password reset link",
|
|
119
|
+
PWD_003: "Password does not meet security requirements",
|
|
120
|
+
PWD_004: "Cannot reuse a recent password",
|
|
121
|
+
PWD_005: "New password must be different from your current password",
|
|
122
|
+
// Authorization
|
|
123
|
+
AUTHZ_001: "You do not have permission to perform this action",
|
|
124
|
+
AUTHZ_002: "Insufficient role to perform this action",
|
|
125
|
+
// General
|
|
126
|
+
GEN_001: "Bad request",
|
|
127
|
+
GEN_002: "The requested resource was not found",
|
|
128
|
+
GEN_003: "An internal server error occurred",
|
|
129
|
+
GEN_004: "Service temporarily unavailable",
|
|
130
|
+
GEN_005: "Too many requests. Please slow down",
|
|
131
|
+
GEN_999: "An unknown error occurred"
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// src/api-error.ts
|
|
135
|
+
var ApiError = class extends AppError {
|
|
136
|
+
constructor(statusCode, message, data) {
|
|
137
|
+
super(statusCode, message, "API_ERROR", data);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// src/validation-error.ts
|
|
142
|
+
var ValidationError = class extends AppError {
|
|
143
|
+
constructor(message, fields) {
|
|
144
|
+
super(400, message, "VALIDATION_ERROR", fields);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// src/authentication-error.ts
|
|
149
|
+
var AuthenticationError = class extends AppError {
|
|
150
|
+
constructor(message, data) {
|
|
151
|
+
super(401, message, "AUTHENTICATION_ERROR", data);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// src/authorization-error.ts
|
|
156
|
+
var AuthorizationError = class extends AppError {
|
|
157
|
+
constructor(message, data) {
|
|
158
|
+
super(403, message, "AUTHORIZATION_ERROR", data);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// src/not-found-error.ts
|
|
163
|
+
var NotFoundError = class extends AppError {
|
|
164
|
+
constructor(message, data) {
|
|
165
|
+
super(404, message, "NOT_FOUND", data);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// src/database-error.ts
|
|
170
|
+
var DatabaseError = class extends AppError {
|
|
171
|
+
constructor(message, data) {
|
|
172
|
+
super(500, message, "DATABASE_ERROR", data);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// src/error-handler.ts
|
|
177
|
+
import { NextResponse } from "next/server";
|
|
178
|
+
function handleApiError(error) {
|
|
179
|
+
if (error instanceof AppError) {
|
|
180
|
+
if (error.statusCode >= 500) {
|
|
181
|
+
console.error("[API Error]", {
|
|
182
|
+
code: error.code,
|
|
183
|
+
message: error.message,
|
|
184
|
+
statusCode: error.statusCode,
|
|
185
|
+
data: error.data
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
return NextResponse.json(error.toJSON(), { status: error.statusCode });
|
|
189
|
+
}
|
|
190
|
+
if (error && typeof error === "object" && "issues" in error) {
|
|
191
|
+
return NextResponse.json(
|
|
192
|
+
{
|
|
193
|
+
success: false,
|
|
194
|
+
error: "Validation failed",
|
|
195
|
+
code: ERROR_CODES.VALIDATION_INVALID_INPUT,
|
|
196
|
+
data: error
|
|
197
|
+
},
|
|
198
|
+
{ status: 400 }
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
console.error("[Unexpected API Error]", {
|
|
202
|
+
error: error instanceof Error ? { name: error.name, message: error.message, stack: error.stack } : error
|
|
203
|
+
});
|
|
204
|
+
return NextResponse.json(
|
|
205
|
+
{
|
|
206
|
+
success: false,
|
|
207
|
+
error: ERROR_MESSAGES[ERROR_CODES.GEN_INTERNAL_ERROR],
|
|
208
|
+
code: ERROR_CODES.GEN_INTERNAL_ERROR
|
|
209
|
+
},
|
|
210
|
+
{ status: 500 }
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
function logError(error, context) {
|
|
214
|
+
console.error("[Application Error]", __spreadProps(__spreadValues({}, context && { context }), {
|
|
215
|
+
error: error instanceof Error ? { name: error.name, message: error.message, stack: error.stack } : error
|
|
216
|
+
}));
|
|
217
|
+
}
|
|
218
|
+
function isAppError(error) {
|
|
219
|
+
return error instanceof AppError;
|
|
220
|
+
}
|
|
221
|
+
export {
|
|
222
|
+
ApiError,
|
|
223
|
+
AppError,
|
|
224
|
+
AuthenticationError,
|
|
225
|
+
AuthorizationError,
|
|
226
|
+
DatabaseError,
|
|
227
|
+
ERROR_CODES,
|
|
228
|
+
ERROR_MESSAGES,
|
|
229
|
+
NotFoundError,
|
|
230
|
+
ValidationError,
|
|
231
|
+
handleApiError,
|
|
232
|
+
isAppError,
|
|
233
|
+
logError
|
|
234
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mohasinac/errors",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"private": false,
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"description": "Application error classes, error codes, and API error handler",
|
|
10
|
+
"main": "./dist/index.cjs",
|
|
11
|
+
"module": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js",
|
|
17
|
+
"require": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsup src/index.ts --format esm,cjs --dts",
|
|
25
|
+
"dev": "tsup --watch",
|
|
26
|
+
"typecheck": "tsc --noEmit"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"next": ">=14.0.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^22.0.0",
|
|
33
|
+
"tsup": "^8.5.0",
|
|
34
|
+
"typescript": "^5.9.3"
|
|
35
|
+
}
|
|
36
|
+
}
|