@carecard/common-util 3.1.1 → 3.1.3

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/index.d.ts CHANGED
@@ -68,6 +68,19 @@ export function throwInputNotUuidError(params?: { userMessage?: string; details?
68
68
  export function throwFileTooLargeError(params?: { userMessage?: string; details?: any }): never;
69
69
  /** Throws an Invalid_Time_Value error. */
70
70
  export function throwInvalidTimeValueError(params?: { userMessage?: string; details?: any }): never;
71
+ /** Throws a Not_Found error. */
72
+ export function throwNotFoundError(params?: { userMessage?: string; details?: any }): never;
73
+ /** Throws a Record_Save_Failure error. */
74
+ export function throwRecordSaveFailureError(params?: {
75
+ userMessage?: string;
76
+ details?: any;
77
+ }): never;
78
+ /** Throws an Application_Error error. */
79
+ export function throwApplicationError(params?: { userMessage?: string; details?: any }): never;
80
+ /** Throws a Network_Error error. */
81
+ export function throwNetworkError(params?: { userMessage?: string; details?: any }): never;
82
+ /** Throws an Unexpected_Error error. */
83
+ export function throwUnexpectedError(params?: { userMessage?: string; details?: any }): never;
71
84
 
72
85
  /**
73
86
  * Application-level error handlers and throwers.
@@ -95,6 +108,11 @@ export const error: {
95
108
  throwInputNotUuidError: typeof throwInputNotUuidError;
96
109
  throwFileTooLargeError: typeof throwFileTooLargeError;
97
110
  throwInvalidTimeValueError: typeof throwInvalidTimeValueError;
111
+ throwNotFoundError: typeof throwNotFoundError;
112
+ throwRecordSaveFailureError: typeof throwRecordSaveFailureError;
113
+ throwApplicationError: typeof throwApplicationError;
114
+ throwNetworkError: typeof throwNetworkError;
115
+ throwUnexpectedError: typeof throwUnexpectedError;
98
116
  };
99
117
 
100
118
  /** Sets 200 OK status and optionally an ETag header. */
@@ -188,3 +206,38 @@ export function createError(params: {
188
206
  message?: string;
189
207
  fields?: Record<string, string>;
190
208
  }): ApiError;
209
+
210
+ /**
211
+ * Standard API error codes.
212
+ */
213
+ export enum ApiErrorType {
214
+ VALIDATION_FAILURE = 'VALIDATION_FAILURE',
215
+ WRONG_CREDENTIALS = 'WRONG_CREDENTIALS',
216
+ RECORD_NOT_FOUND = 'RECORD_NOT_FOUND',
217
+ RECORD_NOT_SAVED = 'RECORD_NOT_SAVED',
218
+ RECORD_SAVE_FAILURE = 'RECORD_SAVE_FAILURE',
219
+ APPLICATION_ERROR = 'APPLICATION_ERROR',
220
+ NOT_FOUND = 'NOT_FOUND',
221
+ LOGIN_REQUIRED = 'LOGIN_REQUIRED',
222
+ NETWORK_ERROR = 'NETWORK_ERROR',
223
+ UNEXPECTED_ERROR = 'UNEXPECTED_ERROR',
224
+ ACCOUNT_SUSPENDED = 'ACCOUNT_SUSPENDED',
225
+ ACCOUNT_BLOCKED = 'ACCOUNT_BLOCKED',
226
+ ACCOUNT_INACTIVE = 'ACCOUNT_INACTIVE',
227
+ RECORD_EXIST = 'RECORD_EXIST',
228
+ UPDATE_FAILED = 'UPDATE_FAILED',
229
+ TRANSACTION_FAILED = 'TRANSACTION_FAILED',
230
+ USED_TOKEN = 'USED_TOKEN',
231
+ BAD_VISITOR_TOKEN = 'BAD_VISITOR_TOKEN',
232
+ FILE_FORMAT_NOT_SUPPORTED = 'FILE_FORMAT_NOT_SUPPORTED',
233
+ NOT_AUTHORIZED = 'NOT_AUTHORIZED',
234
+ BAD_INPUT = 'BAD_INPUT',
235
+ INPUT_NOT_UUID = 'INPUT_NOT_UUID',
236
+ FILE_TOO_LARGE = 'FILE_TOO_LARGE',
237
+ INVALID_TIME_VALUE = 'INVALID_TIME_VALUE'
238
+ }
239
+
240
+ /**
241
+ * Extracts error message from standardized error data.
242
+ */
243
+ export function getApiErrorMessage(errorData: any, t: (key: string) => string): string;
package/index.mjs CHANGED
@@ -1,5 +1,55 @@
1
1
  import commonUtil from './index.js';
2
2
 
3
- export const { util, error, resCode, requestContext, sendResponse, createError } = commonUtil;
3
+ export const {
4
+ // Legacy objects
5
+ util,
6
+ error,
7
+ resCode,
8
+
9
+ // Top-level utility functions
10
+ extractObjectWithProperties,
11
+
12
+ // Top-level error handlers/throwers
13
+ throwAccountSuspendedError,
14
+ throwAccountBlockedError,
15
+ throwAccountInactiveError,
16
+ throwNotFoundError,
17
+ throwRecordSaveFailureError,
18
+ throwApplicationError,
19
+ throwNetworkError,
20
+ throwUnexpectedError,
21
+ notFound404,
22
+ appErrorHandler,
23
+ throwValidationFailureError,
24
+ throwRecordExistError,
25
+ throwWrongCredentialsError,
26
+ throwLoginRequiredError,
27
+ throwRecordNotFoundError,
28
+ throwRecordNotSavedError,
29
+ throwUpdateFailedError,
30
+ throwTransactionFailedError,
31
+ throwUsedTokenError,
32
+ throwBadVisitorTokenError,
33
+ throwFileFormatNotSupportedError,
34
+ throwNotAuthorizedError,
35
+ throwBadInputError,
36
+ throwInputNotUuidError,
37
+ throwFileTooLargeError,
38
+ throwInvalidTimeValueError,
39
+
40
+ // Top-level response status functions
41
+ setOk200,
42
+ setCreated201,
43
+ setBadRequest400ClientError,
44
+
45
+ // Core functions
46
+ requestContext,
47
+ sendResponse,
48
+ createError,
49
+
50
+ // Constants and utils
51
+ ApiErrorType,
52
+ getApiErrorMessage
53
+ } = commonUtil;
4
54
 
5
55
  export default commonUtil;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carecard/common-util",
3
- "version": "3.1.1",
3
+ "version": "3.1.3",
4
4
  "description": "Standardized API response and utility functions for Express.js and Next.js microservices",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",
@@ -28,10 +28,10 @@
28
28
  },
29
29
  "scripts": {
30
30
  "test": "export NODE_ENV=test && mocha --recursive",
31
- "test:types": "tsc --noEmit && mocha -r ts-node/register test/types.test.ts",
31
+ "test:types": "tsc --noEmit && mocha -r ts-node/register test/types.test.mts",
32
32
  "test:coverage": "export NODE_ENV=test && nyc mocha --recursive",
33
- "test:types:coverage": "tsc --noEmit && export NODE_ENV=test && nyc mocha -r ts-node/register 'test/**/*.{js,ts}'",
34
- "coverage": "export NODE_ENV=test && nyc mocha --recursive -r ts-node/register 'test/**/*.{js,ts}' && nyc check-coverage",
33
+ "test:types:coverage": "tsc --noEmit && export NODE_ENV=test && nyc mocha -r ts-node/register 'test/**/*.{js,ts,mts}'",
34
+ "coverage": "export NODE_ENV=test && nyc mocha --recursive -r ts-node/register 'test/**/*.{js,ts,mts}' && nyc check-coverage",
35
35
  "prettier": "prettier --write .",
36
36
  "prettier:check": "prettier --check .",
37
37
  "prepare": "husky"
package/src/index.js CHANGED
@@ -1,12 +1,29 @@
1
1
  const requestContext = require('./middleware/requestContext');
2
2
  const sendResponse = require('./utils/sendResponse');
3
3
  const createError = require('./utils/createError');
4
+ const utilityFunctions = require('./lib/utilityFunctions');
5
+ const appErrorHandlers = require('./lib/appErrorHandlers');
6
+ const responseStatus = require('./lib/responseStatus');
7
+ const errorConstants = require('./lib/errorConstants');
8
+ const errorUtils = require('./lib/errorUtils');
4
9
 
5
10
  module.exports = {
6
- util: require('./lib/utilityFunctions'),
7
- error: require('./lib/appErrorHandlers'),
8
- resCode: require('./lib/responseStatus'),
11
+ // Nested exports (Legacy/Deprecated)
12
+ util: utilityFunctions,
13
+ error: appErrorHandlers,
14
+ resCode: responseStatus,
15
+
16
+ // Direct top-level exports
17
+ ...utilityFunctions,
18
+ ...appErrorHandlers,
19
+ ...responseStatus,
20
+
21
+ // Core utilities
9
22
  requestContext,
10
23
  sendResponse,
11
- createError
24
+ createError,
25
+
26
+ // Error system
27
+ ApiErrorType: errorConstants.ApiErrorType,
28
+ getApiErrorMessage: errorUtils.getApiErrorMessage
12
29
  };
@@ -2,6 +2,7 @@
2
2
 
3
3
  const sendResponse = require('../utils/sendResponse');
4
4
  const createError = require('../utils/createError');
5
+ const { ApiErrorType } = require('./errorConstants');
5
6
 
6
7
  /**
7
8
  * These are application level error handlers. All error responses should be send using these functions.
@@ -11,6 +12,11 @@ module.exports = {
11
12
  throwAccountSuspendedError,
12
13
  throwAccountBlockedError,
13
14
  throwAccountInactiveError,
15
+ throwNotFoundError,
16
+ throwRecordSaveFailureError,
17
+ throwApplicationError,
18
+ throwNetworkError,
19
+ throwUnexpectedError,
14
20
  notFound404,
15
21
  appErrorHandler,
16
22
  throwValidationFailureError,
@@ -39,7 +45,7 @@ function notFound404(req, res, next) {
39
45
  success: false,
40
46
  message: 'Not found',
41
47
  error: createError({
42
- code: 'NOT_FOUND',
48
+ code: ApiErrorType.NOT_FOUND,
43
49
  message: 'Not found',
44
50
  details: null
45
51
  })
@@ -47,13 +53,19 @@ function notFound404(req, res, next) {
47
53
  }
48
54
 
49
55
  function appErrorHandler(err, req, res, next) {
50
- let statusCode = 500;
51
56
  const errorMessage = err?.message || 'Internal Server Error';
57
+ const errorCode = err?.code;
58
+ let statusCode;
52
59
 
53
- switch (err?.message) {
60
+ switch (errorCode || err?.message) {
54
61
  case 'Account_Suspended':
55
62
  case 'Account_Blocked':
56
63
  case 'Account_Inactive':
64
+ case ApiErrorType.ACCOUNT_SUSPENDED:
65
+ case ApiErrorType.ACCOUNT_BLOCKED:
66
+ case ApiErrorType.ACCOUNT_INACTIVE:
67
+ case 'Invalid time value':
68
+ case ApiErrorType.INVALID_TIME_VALUE:
57
69
  statusCode = 403;
58
70
  break;
59
71
 
@@ -63,6 +75,12 @@ function appErrorHandler(err, req, res, next) {
63
75
  case 'Bad_Visitor_Token':
64
76
  case 'Login_Required':
65
77
  case 'Not_Authorized':
78
+ case ApiErrorType.VALIDATION_FAILURE:
79
+ case ApiErrorType.USED_TOKEN:
80
+ case ApiErrorType.WRONG_CREDENTIALS:
81
+ case ApiErrorType.BAD_VISITOR_TOKEN:
82
+ case ApiErrorType.LOGIN_REQUIRED:
83
+ case ApiErrorType.NOT_AUTHORIZED:
66
84
  statusCode = 401;
67
85
  break;
68
86
 
@@ -71,27 +89,41 @@ function appErrorHandler(err, req, res, next) {
71
89
  case 'Transaction_Failed':
72
90
  case 'Bad_Input':
73
91
  case 'Input_Not_Uuid':
92
+ case ApiErrorType.RECORD_NOT_SAVED:
93
+ case ApiErrorType.UPDATE_FAILED:
94
+ case ApiErrorType.TRANSACTION_FAILED:
95
+ case ApiErrorType.BAD_INPUT:
96
+ case ApiErrorType.INPUT_NOT_UUID:
74
97
  statusCode = 400;
75
98
  break;
76
99
 
77
100
  case 'Record_Exist':
101
+ case ApiErrorType.RECORD_EXIST:
78
102
  statusCode = 409;
79
103
  break;
80
104
 
81
105
  case 'Record_NotFound':
106
+ case 'Not found':
107
+ case ApiErrorType.RECORD_NOT_FOUND:
108
+ case ApiErrorType.NOT_FOUND:
82
109
  statusCode = 404;
83
110
  break;
84
111
 
85
112
  case 'File_Format_Not_Supported':
113
+ case ApiErrorType.FILE_FORMAT_NOT_SUPPORTED:
86
114
  statusCode = 415;
87
115
  break;
88
116
 
89
117
  case 'File too large':
118
+ case ApiErrorType.FILE_TOO_LARGE:
90
119
  statusCode = 413;
91
120
  break;
92
121
 
93
- case 'Invalid time value':
94
- statusCode = 403;
122
+ case ApiErrorType.RECORD_SAVE_FAILURE:
123
+ case ApiErrorType.APPLICATION_ERROR:
124
+ case ApiErrorType.NETWORK_ERROR:
125
+ case ApiErrorType.UNEXPECTED_ERROR:
126
+ statusCode = 500;
95
127
  break;
96
128
 
97
129
  default:
@@ -114,7 +146,7 @@ function appErrorHandler(err, req, res, next) {
114
146
 
115
147
  function throwAccountSuspendedError(params = {}) {
116
148
  const error = new Error('Account_Suspended');
117
- error.code = 'ACCOUNT_SUSPENDED';
149
+ error.code = ApiErrorType.ACCOUNT_SUSPENDED;
118
150
  error.userMessage = params.userMessage ?? null;
119
151
  error.details = params.details ?? null;
120
152
  throw error;
@@ -122,7 +154,7 @@ function throwAccountSuspendedError(params = {}) {
122
154
 
123
155
  function throwAccountBlockedError(params = {}) {
124
156
  const error = new Error('Account_Blocked');
125
- error.code = 'ACCOUNT_BLOCKED';
157
+ error.code = ApiErrorType.ACCOUNT_BLOCKED;
126
158
  error.userMessage = params.userMessage ?? null;
127
159
  error.details = params.details ?? null;
128
160
  throw error;
@@ -130,7 +162,7 @@ function throwAccountBlockedError(params = {}) {
130
162
 
131
163
  function throwAccountInactiveError(params = {}) {
132
164
  const error = new Error('Account_Inactive');
133
- error.code = 'ACCOUNT_INACTIVE';
165
+ error.code = ApiErrorType.ACCOUNT_INACTIVE;
134
166
  error.userMessage = params.userMessage ?? null;
135
167
  error.details = params.details ?? null;
136
168
  throw error;
@@ -138,7 +170,7 @@ function throwAccountInactiveError(params = {}) {
138
170
 
139
171
  function throwValidationFailureError(params = {}) {
140
172
  const error = new Error('Validation_Failure');
141
- error.code = 'VALIDATION_FAILURE';
173
+ error.code = ApiErrorType.VALIDATION_FAILURE;
142
174
  error.userMessage = params.userMessage ?? null;
143
175
  error.details = params.details ?? null;
144
176
  throw error;
@@ -146,7 +178,7 @@ function throwValidationFailureError(params = {}) {
146
178
 
147
179
  function throwWrongCredentialsError(params = {}) {
148
180
  const error = new Error('Wrong_Credentials');
149
- error.code = 'WRONG_CREDENTIALS';
181
+ error.code = ApiErrorType.WRONG_CREDENTIALS;
150
182
  error.userMessage = params.userMessage ?? null;
151
183
  error.details = params.details ?? null;
152
184
  throw error;
@@ -154,7 +186,7 @@ function throwWrongCredentialsError(params = {}) {
154
186
 
155
187
  function throwRecordExistError(params = {}) {
156
188
  const error = new Error('Record_Exist');
157
- error.code = 'RECORD_EXIST';
189
+ error.code = ApiErrorType.RECORD_EXIST;
158
190
  error.userMessage = params.userMessage ?? null;
159
191
  error.details = params.details ?? null;
160
192
  throw error;
@@ -162,7 +194,7 @@ function throwRecordExistError(params = {}) {
162
194
 
163
195
  function throwRecordNotFoundError(params = {}) {
164
196
  const error = new Error('Record_NotFound');
165
- error.code = 'RECORD_NOT_FOUND';
197
+ error.code = ApiErrorType.RECORD_NOT_FOUND;
166
198
  error.userMessage = params.userMessage ?? null;
167
199
  error.details = params.details ?? null;
168
200
  throw error;
@@ -170,7 +202,7 @@ function throwRecordNotFoundError(params = {}) {
170
202
 
171
203
  function throwRecordNotSavedError(params = {}) {
172
204
  const error = new Error('Record_NotSaved');
173
- error.code = 'RECORD_NOT_SAVED';
205
+ error.code = ApiErrorType.RECORD_NOT_SAVED;
174
206
  error.userMessage = params.userMessage ?? null;
175
207
  error.details = params.details ?? null;
176
208
  throw error;
@@ -178,7 +210,7 @@ function throwRecordNotSavedError(params = {}) {
178
210
 
179
211
  function throwLoginRequiredError(params = {}) {
180
212
  const error = new Error('Login_Required');
181
- error.code = 'LOGIN_REQUIRED';
213
+ error.code = ApiErrorType.LOGIN_REQUIRED;
182
214
  error.userMessage = params.userMessage ?? null;
183
215
  error.details = params.details ?? null;
184
216
  throw error;
@@ -186,7 +218,7 @@ function throwLoginRequiredError(params = {}) {
186
218
 
187
219
  function throwUpdateFailedError(params = {}) {
188
220
  const error = new Error('Update_Failed');
189
- error.code = 'UPDATE_FAILED';
221
+ error.code = ApiErrorType.UPDATE_FAILED;
190
222
  error.userMessage = params.userMessage ?? null;
191
223
  error.details = params.details ?? null;
192
224
  throw error;
@@ -194,7 +226,7 @@ function throwUpdateFailedError(params = {}) {
194
226
 
195
227
  function throwTransactionFailedError(params = {}) {
196
228
  const error = new Error('Transaction_Failed');
197
- error.code = 'TRANSACTION_FAILED';
229
+ error.code = ApiErrorType.TRANSACTION_FAILED;
198
230
  error.userMessage = params.userMessage ?? null;
199
231
  error.details = params.details ?? null;
200
232
  throw error;
@@ -202,7 +234,7 @@ function throwTransactionFailedError(params = {}) {
202
234
 
203
235
  function throwUsedTokenError(params = {}) {
204
236
  const error = new Error('Used_Token');
205
- error.code = 'USED_TOKEN';
237
+ error.code = ApiErrorType.USED_TOKEN;
206
238
  error.userMessage = params.userMessage ?? null;
207
239
  error.details = params.details ?? null;
208
240
  throw error;
@@ -210,7 +242,7 @@ function throwUsedTokenError(params = {}) {
210
242
 
211
243
  function throwVisitorTokenError(params = {}) {
212
244
  const error = new Error('Bad_Visitor_Token');
213
- error.code = 'BAD_VISITOR_TOKEN';
245
+ error.code = ApiErrorType.BAD_VISITOR_TOKEN;
214
246
  error.userMessage = params.userMessage ?? null;
215
247
  error.details = params.details ?? null;
216
248
  throw error;
@@ -218,7 +250,7 @@ function throwVisitorTokenError(params = {}) {
218
250
 
219
251
  function throwFileFormatNotSupportedError(params = {}) {
220
252
  const error = new Error('File_Format_Not_Supported');
221
- error.code = 'FILE_FORMAT_NOT_SUPPORTED';
253
+ error.code = ApiErrorType.FILE_FORMAT_NOT_SUPPORTED;
222
254
  error.userMessage = params.userMessage ?? null;
223
255
  error.details = params.details ?? null;
224
256
  throw error;
@@ -226,7 +258,7 @@ function throwFileFormatNotSupportedError(params = {}) {
226
258
 
227
259
  function throwNotAuthorizedError(params = {}) {
228
260
  const error = new Error('Not_Authorized');
229
- error.code = 'NOT_AUTHORIZED';
261
+ error.code = ApiErrorType.NOT_AUTHORIZED;
230
262
  error.userMessage = params.userMessage ?? null;
231
263
  error.details = params.details ?? null;
232
264
  throw error;
@@ -234,7 +266,7 @@ function throwNotAuthorizedError(params = {}) {
234
266
 
235
267
  function throwBadInputError(params = {}) {
236
268
  const error = new Error('Bad_Input');
237
- error.code = 'BAD_INPUT';
269
+ error.code = ApiErrorType.BAD_INPUT;
238
270
  error.userMessage = params.userMessage ?? null;
239
271
  error.details = params.details ?? null;
240
272
  throw error;
@@ -242,7 +274,7 @@ function throwBadInputError(params = {}) {
242
274
 
243
275
  function throwInputNotUuidError(params = {}) {
244
276
  const error = new Error('Input_Not_Uuid');
245
- error.code = 'INPUT_NOT_UUID';
277
+ error.code = ApiErrorType.INPUT_NOT_UUID;
246
278
  error.userMessage = params.userMessage ?? null;
247
279
  error.details = params.details ?? null;
248
280
  throw error;
@@ -250,7 +282,7 @@ function throwInputNotUuidError(params = {}) {
250
282
 
251
283
  function throwFileTooLargeError(params = {}) {
252
284
  const error = new Error('File too large');
253
- error.code = 'FILE_TOO_LARGE';
285
+ error.code = ApiErrorType.FILE_TOO_LARGE;
254
286
  error.userMessage = params.userMessage ?? null;
255
287
  error.details = params.details ?? null;
256
288
  throw error;
@@ -258,7 +290,47 @@ function throwFileTooLargeError(params = {}) {
258
290
 
259
291
  function throwInvalidTimeValueError(params = {}) {
260
292
  const error = new Error('Invalid time value');
261
- error.code = 'INVALID_TIME_VALUE';
293
+ error.code = ApiErrorType.INVALID_TIME_VALUE;
294
+ error.userMessage = params.userMessage ?? null;
295
+ error.details = params.details ?? null;
296
+ throw error;
297
+ }
298
+
299
+ function throwNotFoundError(params = {}) {
300
+ const error = new Error('Not found');
301
+ error.code = ApiErrorType.NOT_FOUND;
302
+ error.userMessage = params.userMessage ?? null;
303
+ error.details = params.details ?? null;
304
+ throw error;
305
+ }
306
+
307
+ function throwRecordSaveFailureError(params = {}) {
308
+ const error = new Error('Record_Save_Failure');
309
+ error.code = ApiErrorType.RECORD_SAVE_FAILURE;
310
+ error.userMessage = params.userMessage ?? null;
311
+ error.details = params.details ?? null;
312
+ throw error;
313
+ }
314
+
315
+ function throwApplicationError(params = {}) {
316
+ const error = new Error('Application_Error');
317
+ error.code = ApiErrorType.APPLICATION_ERROR;
318
+ error.userMessage = params.userMessage ?? null;
319
+ error.details = params.details ?? null;
320
+ throw error;
321
+ }
322
+
323
+ function throwNetworkError(params = {}) {
324
+ const error = new Error('Network_Error');
325
+ error.code = ApiErrorType.NETWORK_ERROR;
326
+ error.userMessage = params.userMessage ?? null;
327
+ error.details = params.details ?? null;
328
+ throw error;
329
+ }
330
+
331
+ function throwUnexpectedError(params = {}) {
332
+ const error = new Error('Unexpected_Error');
333
+ error.code = ApiErrorType.UNEXPECTED_ERROR;
262
334
  error.userMessage = params.userMessage ?? null;
263
335
  error.details = params.details ?? null;
264
336
  throw error;
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Standard API error codes used across the system.
5
+ * This should be kept in sync between the backend and frontend.
6
+ */
7
+ const ApiErrorType = {
8
+ // Common codes
9
+ VALIDATION_FAILURE: 'VALIDATION_FAILURE',
10
+ WRONG_CREDENTIALS: 'WRONG_CREDENTIALS',
11
+ RECORD_NOT_FOUND: 'RECORD_NOT_FOUND',
12
+ RECORD_NOT_SAVED: 'RECORD_NOT_SAVED',
13
+ RECORD_SAVE_FAILURE: 'RECORD_SAVE_FAILURE',
14
+ APPLICATION_ERROR: 'APPLICATION_ERROR',
15
+ NOT_FOUND: 'NOT_FOUND',
16
+ LOGIN_REQUIRED: 'LOGIN_REQUIRED',
17
+ NETWORK_ERROR: 'NETWORK_ERROR',
18
+ UNEXPECTED_ERROR: 'UNEXPECTED_ERROR',
19
+ ACCOUNT_SUSPENDED: 'ACCOUNT_SUSPENDED',
20
+ ACCOUNT_BLOCKED: 'ACCOUNT_BLOCKED',
21
+ ACCOUNT_INACTIVE: 'ACCOUNT_INACTIVE',
22
+
23
+ // Additional codes from appErrorHandlers
24
+ RECORD_EXIST: 'RECORD_EXIST',
25
+ UPDATE_FAILED: 'UPDATE_FAILED',
26
+ TRANSACTION_FAILED: 'TRANSACTION_FAILED',
27
+ USED_TOKEN: 'USED_TOKEN',
28
+ BAD_VISITOR_TOKEN: 'BAD_VISITOR_TOKEN',
29
+ FILE_FORMAT_NOT_SUPPORTED: 'FILE_FORMAT_NOT_SUPPORTED',
30
+ NOT_AUTHORIZED: 'NOT_AUTHORIZED',
31
+ BAD_INPUT: 'BAD_INPUT',
32
+ INPUT_NOT_UUID: 'INPUT_NOT_UUID',
33
+ FILE_TOO_LARGE: 'FILE_TOO_LARGE',
34
+ INVALID_TIME_VALUE: 'INVALID_TIME_VALUE'
35
+ };
36
+
37
+ module.exports = {
38
+ ApiErrorType
39
+ };
@@ -0,0 +1,128 @@
1
+ 'use strict';
2
+
3
+ const { ApiErrorType } = require('./errorConstants');
4
+
5
+ /**
6
+ * Extracts error message from standardized error data.
7
+ *
8
+ * @param {Object} errorData - The error data from API or legacy source.
9
+ * @param {Function} t - Translation function (key => translated string).
10
+ * @returns {string} The formatted error message.
11
+ */
12
+ function getApiErrorMessage(errorData, t) {
13
+ if (!errorData) {
14
+ return t('errors.unexpected_error');
15
+ }
16
+
17
+ // Try to get message from direct field or nested error object
18
+ let message;
19
+
20
+ // Prefer nested error message if available
21
+ if (errorData.error && typeof errorData.error === 'object' && errorData.error.message) {
22
+ message = errorData.error.message;
23
+ }
24
+
25
+ // Fallback to top-level message
26
+ if (!message && typeof errorData.message === 'string' && errorData.message) {
27
+ message = errorData.message;
28
+ }
29
+
30
+ if (message) {
31
+ return message;
32
+ }
33
+
34
+ // Try to get error code
35
+ let errorCode;
36
+ if (errorData.error) {
37
+ if (typeof errorData.error === 'string') {
38
+ errorCode = errorData.error;
39
+ } else if (typeof errorData.error === 'object' && errorData.error.code) {
40
+ errorCode = errorData.error.code;
41
+ }
42
+ }
43
+
44
+ if (!errorCode) {
45
+ return t('errors.unexpected_error');
46
+ }
47
+
48
+ const code = errorCode.toLowerCase();
49
+
50
+ switch (code) {
51
+ case ApiErrorType.VALIDATION_FAILURE.toLowerCase():
52
+ return t('errors.validation_failure');
53
+
54
+ case ApiErrorType.WRONG_CREDENTIALS.toLowerCase():
55
+ return t('errors.wrong_credentials');
56
+
57
+ case ApiErrorType.RECORD_NOT_FOUND.toLowerCase():
58
+ return t('errors.record_not_found');
59
+
60
+ case ApiErrorType.RECORD_NOT_SAVED.toLowerCase():
61
+ return t('errors.record_not_saved');
62
+
63
+ case ApiErrorType.RECORD_SAVE_FAILURE.toLowerCase():
64
+ return t('errors.record_save_failure');
65
+
66
+ case ApiErrorType.APPLICATION_ERROR.toLowerCase():
67
+ return t('errors.application_error');
68
+
69
+ case ApiErrorType.NOT_FOUND.toLowerCase():
70
+ return t('errors.not_found');
71
+
72
+ case ApiErrorType.LOGIN_REQUIRED.toLowerCase():
73
+ return t('errors.login_required');
74
+
75
+ case ApiErrorType.NETWORK_ERROR.toLowerCase():
76
+ return t('errors.network_error');
77
+
78
+ case ApiErrorType.ACCOUNT_SUSPENDED.toLowerCase():
79
+ return t('errors.account_suspended');
80
+
81
+ case ApiErrorType.ACCOUNT_BLOCKED.toLowerCase():
82
+ return t('errors.account_blocked');
83
+
84
+ case ApiErrorType.ACCOUNT_INACTIVE.toLowerCase():
85
+ return t('errors.account_inactive');
86
+
87
+ case ApiErrorType.RECORD_EXIST.toLowerCase():
88
+ return t('errors.record_exist');
89
+
90
+ case ApiErrorType.UPDATE_FAILED.toLowerCase():
91
+ return t('errors.update_failed');
92
+
93
+ case ApiErrorType.TRANSACTION_FAILED.toLowerCase():
94
+ return t('errors.transaction_failed');
95
+
96
+ case ApiErrorType.USED_TOKEN.toLowerCase():
97
+ return t('errors.used_token');
98
+
99
+ case ApiErrorType.BAD_VISITOR_TOKEN.toLowerCase():
100
+ return t('errors.bad_visitor_token');
101
+
102
+ case ApiErrorType.FILE_FORMAT_NOT_SUPPORTED.toLowerCase():
103
+ return t('errors.file_format_not_supported');
104
+
105
+ case ApiErrorType.NOT_AUTHORIZED.toLowerCase():
106
+ return t('errors.not_authorized');
107
+
108
+ case ApiErrorType.BAD_INPUT.toLowerCase():
109
+ return t('errors.bad_input');
110
+
111
+ case ApiErrorType.INPUT_NOT_UUID.toLowerCase():
112
+ return t('errors.input_not_uuid');
113
+
114
+ case ApiErrorType.FILE_TOO_LARGE.toLowerCase():
115
+ return t('errors.file_too_large');
116
+
117
+ case ApiErrorType.INVALID_TIME_VALUE.toLowerCase():
118
+ return t('errors.invalid_time_value');
119
+
120
+ case ApiErrorType.UNEXPECTED_ERROR.toLowerCase():
121
+ default:
122
+ return t('errors.unexpected_error');
123
+ }
124
+ }
125
+
126
+ module.exports = {
127
+ getApiErrorMessage
128
+ };
@@ -1,4 +1,14 @@
1
- const { randomUUID } = require('node:crypto');
1
+ const getUuid = () => {
2
+ try {
3
+ const crypto = require('crypto');
4
+ if (crypto.randomUUID) {
5
+ return crypto.randomUUID();
6
+ }
7
+ return '00000000-0000-0000-0000-000000000000';
8
+ } catch (e) {
9
+ return '00000000-0000-0000-0000-000000000000';
10
+ }
11
+ };
2
12
 
3
13
  /**
4
14
  * Express middleware to generate and attach request context.
@@ -13,8 +23,9 @@ const { randomUUID } = require('node:crypto');
13
23
  * @param {import('express').NextFunction} next
14
24
  */
15
25
  const requestContext = (req, res, next) => {
16
- req.requestId = randomUUID();
17
- req.traceId = req.headers['x-trace-id'] || randomUUID();
26
+ const requestId = getUuid();
27
+ req.requestId = requestId;
28
+ req.traceId = req.headers['x-trace-id'] || requestId;
18
29
 
19
30
  const appId = req.headers['x-app-id'];
20
31
  const ip = req.ip || req.headers['x-forwarded-for'] || req.socket.remoteAddress;