mirror of
https://github.com/nestriness/nestri.git
synced 2026-09-19 17:25:19 +03:00
125 lines
2.7 KiB
TypeScript
125 lines
2.7 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
export const ErrorResponse = z
|
|
.object({
|
|
type: z
|
|
.enum([
|
|
'validation',
|
|
'authentication',
|
|
'forbidden',
|
|
'not_found',
|
|
'already_exists',
|
|
'rate_limit',
|
|
'internal'
|
|
])
|
|
.meta({
|
|
description: 'The error type category',
|
|
examples: ['validation', 'authentication']
|
|
}),
|
|
code: z.string().meta({
|
|
description: 'Machine-readable error code identifier',
|
|
examples: ['invalid_parameter', 'missing_required_field', 'unauthorized']
|
|
}),
|
|
message: z.string().meta({
|
|
description: 'Human-readable error message',
|
|
examples: ['The request was invalid', 'Authentication required']
|
|
}),
|
|
param: z
|
|
.string()
|
|
.optional()
|
|
.meta({
|
|
description: 'The parameter that caused the error (if applicable)',
|
|
examples: ['email', 'user_id', 'team_id']
|
|
}),
|
|
details: z.any().optional().meta({
|
|
description: 'Additional error context information'
|
|
})
|
|
})
|
|
.meta({ ref: 'ErrorResponse' });
|
|
|
|
export type ErrorResponseType = z.infer<typeof ErrorResponse>;
|
|
|
|
export const ErrorCodes = {
|
|
Validation: {
|
|
MISSING_REQUIRED_FIELD: 'missing_required_field',
|
|
ALREADY_EXISTS: 'resource_already_exists',
|
|
TEAM_ALREADY_EXISTS: 'team_already_exists',
|
|
INVALID_PARAMETER: 'invalid_parameter',
|
|
INVALID_FORMAT: 'invalid_format',
|
|
INVALID_STATE: 'invalid_state',
|
|
IN_USE: 'resource_in_use'
|
|
},
|
|
|
|
Authentication: {
|
|
UNAUTHORIZED: 'unauthorized',
|
|
INVALID_TOKEN: 'invalid_token',
|
|
EXPIRED_TOKEN: 'expired_token',
|
|
INVALID_CREDENTIALS: 'invalid_credentials'
|
|
},
|
|
|
|
Permission: {
|
|
FORBIDDEN: 'forbidden',
|
|
INSUFFICIENT_PERMISSIONS: 'insufficient_permissions',
|
|
ACCOUNT_RESTRICTED: 'account_restricted'
|
|
},
|
|
|
|
NotFound: {
|
|
RESOURCE_NOT_FOUND: 'resource_not_found'
|
|
},
|
|
|
|
RateLimit: {
|
|
TOO_MANY_REQUESTS: 'too_many_requests',
|
|
QUOTA_EXCEEDED: 'quota_exceeded'
|
|
},
|
|
|
|
Server: {
|
|
INTERNAL_ERROR: 'internal_error',
|
|
SERVICE_UNAVAILABLE: 'service_unavailable',
|
|
DEPENDENCY_FAILURE: 'dependency_failure'
|
|
}
|
|
};
|
|
|
|
export class VisibleError extends Error {
|
|
constructor(
|
|
public type: ErrorResponseType['type'],
|
|
public code: string,
|
|
public override message: string,
|
|
public param?: string,
|
|
public details?: any
|
|
) {
|
|
super(message);
|
|
}
|
|
|
|
public statusCode(): number {
|
|
switch (this.type) {
|
|
case 'validation':
|
|
return 400;
|
|
case 'authentication':
|
|
return 401;
|
|
case 'forbidden':
|
|
return 403;
|
|
case 'not_found':
|
|
return 404;
|
|
case 'already_exists':
|
|
return 409;
|
|
case 'rate_limit':
|
|
return 429;
|
|
case 'internal':
|
|
return 500;
|
|
}
|
|
}
|
|
|
|
public toResponse(): ErrorResponseType {
|
|
const response: ErrorResponseType = {
|
|
type: this.type,
|
|
code: this.code,
|
|
message: this.message
|
|
};
|
|
|
|
if (this.param) response.param = this.param;
|
|
if (this.details) response.details = this.details;
|
|
|
|
return response;
|
|
}
|
|
}
|