@valentine-efagene/qshelter-common 2.0.149 → 2.0.150

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.
@@ -1,6 +1,6 @@
1
1
  import { Request, Response, NextFunction } from 'express';
2
2
  /**
3
3
  * Global error handler middleware for Express applications.
4
- * Handles ZodError, AppError, and generic errors with appropriate responses.
4
+ * Handles ZodError, AppError, Prisma errors, and generic errors with appropriate responses.
5
5
  */
6
6
  export declare function errorHandler(err: Error, req: Request, res: Response, next: NextFunction): Response<any, Record<string, any>>;
@@ -1,10 +1,83 @@
1
1
  import { ZodError } from 'zod';
2
2
  import { AppError } from '../utils/errors';
3
+ /**
4
+ * Extract a user-friendly field name from Prisma's target array.
5
+ * Handles composite unique constraints like `tenantId_cacNumber`.
6
+ */
7
+ function extractFieldName(target) {
8
+ // Filter out common fields that are not user-facing
9
+ const userFacingFields = target.filter((f) => !['tenantId', 'id', 'createdAt', 'updatedAt'].includes(f));
10
+ if (userFacingFields.length === 0) {
11
+ // Fallback: use the last target field and make it readable
12
+ const lastField = target[target.length - 1];
13
+ return lastField.replace(/([A-Z])/g, ' $1').trim().toLowerCase();
14
+ }
15
+ // Convert camelCase to readable format
16
+ return userFacingFields
17
+ .map((f) => f.replace(/([A-Z])/g, ' $1').trim().toLowerCase())
18
+ .join(', ');
19
+ }
20
+ /**
21
+ * Handle Prisma-specific errors with user-friendly messages.
22
+ */
23
+ function handlePrismaError(err) {
24
+ // Check if this is a Prisma error (has code property)
25
+ if (!err.code || typeof err.code !== 'string' || !err.code.startsWith('P')) {
26
+ return null;
27
+ }
28
+ switch (err.code) {
29
+ case 'P2002': {
30
+ // Unique constraint violation
31
+ const target = err.meta?.target;
32
+ const modelName = err.meta?.modelName;
33
+ if (target && target.length > 0) {
34
+ const fieldName = extractFieldName(target);
35
+ const entity = modelName || 'Record';
36
+ return {
37
+ statusCode: 409,
38
+ message: `A ${entity.toLowerCase()} with this ${fieldName} already exists`,
39
+ };
40
+ }
41
+ return {
42
+ statusCode: 409,
43
+ message: 'A record with these values already exists',
44
+ };
45
+ }
46
+ case 'P2003': {
47
+ // Foreign key constraint violation
48
+ const field = err.meta?.field_name;
49
+ return {
50
+ statusCode: 400,
51
+ message: field
52
+ ? `Referenced ${field.replace(/([A-Z])/g, ' $1').trim().toLowerCase()} does not exist`
53
+ : 'Referenced record does not exist',
54
+ };
55
+ }
56
+ case 'P2025': {
57
+ // Record not found for update/delete
58
+ return {
59
+ statusCode: 404,
60
+ message: 'Record not found',
61
+ };
62
+ }
63
+ case 'P2014': {
64
+ // Required relation violation
65
+ return {
66
+ statusCode: 400,
67
+ message: 'This operation would violate a required relation',
68
+ };
69
+ }
70
+ default:
71
+ // Unknown Prisma error - log it but return generic message
72
+ return null;
73
+ }
74
+ }
3
75
  /**
4
76
  * Global error handler middleware for Express applications.
5
- * Handles ZodError, AppError, and generic errors with appropriate responses.
77
+ * Handles ZodError, AppError, Prisma errors, and generic errors with appropriate responses.
6
78
  */
7
79
  export function errorHandler(err, req, res, next) {
80
+ // Handle Zod validation errors
8
81
  if (err instanceof ZodError) {
9
82
  return res.status(400).json({
10
83
  success: false,
@@ -13,6 +86,7 @@ export function errorHandler(err, req, res, next) {
13
86
  details: err.issues,
14
87
  });
15
88
  }
89
+ // Handle custom application errors
16
90
  if (err instanceof AppError) {
17
91
  return res.status(err.statusCode).json({
18
92
  success: false,
@@ -20,6 +94,16 @@ export function errorHandler(err, req, res, next) {
20
94
  error: err.message,
21
95
  });
22
96
  }
97
+ // Handle Prisma errors
98
+ const prismaError = handlePrismaError(err);
99
+ if (prismaError) {
100
+ return res.status(prismaError.statusCode).json({
101
+ success: false,
102
+ message: prismaError.message,
103
+ error: prismaError.message,
104
+ });
105
+ }
106
+ // Unhandled error - log and return generic message
23
107
  console.error('Unhandled error:', err);
24
108
  return res.status(500).json({
25
109
  success: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valentine-efagene/qshelter-common",
3
- "version": "2.0.149",
3
+ "version": "2.0.150",
4
4
  "description": "Shared database schemas and utilities for QShelter services",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",