Initial push of Plunk Next

This commit is contained in:
Dries Augustyns
2025-12-01 09:56:56 +01:00
parent 07cea20262
commit ff1876d580
566 changed files with 89036 additions and 28423 deletions
+168
View File
@@ -0,0 +1,168 @@
/**
* Machine-readable error codes for programmatic error handling
* These codes allow API consumers to handle specific error types reliably
*/
export enum ErrorCode {
// Authentication & Authorization (401-403)
UNAUTHORIZED = 'UNAUTHORIZED',
INVALID_CREDENTIALS = 'INVALID_CREDENTIALS',
MISSING_AUTH = 'MISSING_AUTH',
INVALID_API_KEY = 'INVALID_API_KEY',
FORBIDDEN = 'FORBIDDEN',
PROJECT_ACCESS_DENIED = 'PROJECT_ACCESS_DENIED',
PROJECT_DISABLED = 'PROJECT_DISABLED',
// Resource Errors (404-409)
RESOURCE_NOT_FOUND = 'RESOURCE_NOT_FOUND',
CONTACT_NOT_FOUND = 'CONTACT_NOT_FOUND',
TEMPLATE_NOT_FOUND = 'TEMPLATE_NOT_FOUND',
CAMPAIGN_NOT_FOUND = 'CAMPAIGN_NOT_FOUND',
WORKFLOW_NOT_FOUND = 'WORKFLOW_NOT_FOUND',
CONFLICT = 'CONFLICT',
// Validation & Input Errors (400, 422)
BAD_REQUEST = 'BAD_REQUEST',
VALIDATION_ERROR = 'VALIDATION_ERROR',
INVALID_EMAIL = 'INVALID_EMAIL',
INVALID_REQUEST_BODY = 'INVALID_REQUEST_BODY',
MISSING_REQUIRED_FIELD = 'MISSING_REQUIRED_FIELD',
// Rate Limiting & Billing (429, 402)
RATE_LIMIT_EXCEEDED = 'RATE_LIMIT_EXCEEDED',
BILLING_LIMIT_EXCEEDED = 'BILLING_LIMIT_EXCEEDED',
UPGRADE_REQUIRED = 'UPGRADE_REQUIRED',
// Server Errors (500+)
INTERNAL_SERVER_ERROR = 'INTERNAL_SERVER_ERROR',
DATABASE_ERROR = 'DATABASE_ERROR',
EXTERNAL_SERVICE_ERROR = 'EXTERNAL_SERVICE_ERROR',
}
/**
* Structured field-level validation error
*/
export interface FieldError {
field: string; // Dot-notation path (e.g., "email", "data.firstName")
message: string; // Human-readable error message
code: string; // Validation error code (e.g., "invalid_email", "too_short")
received?: unknown; // The invalid value that was provided
}
/**
* Base HTTP exception with support for error codes and structured data
*/
export class HttpException extends Error {
public constructor(
public readonly code: number,
message: string,
public readonly errorCode?: ErrorCode,
public readonly details?: Record<string, unknown>,
) {
super(message);
this.name = this.constructor.name;
}
}
/**
* Resource not found (404)
*/
export class NotFound extends HttpException {
/**
* Construct a new NotFound exception
* @param resource The type of resource that was not found
* @param id Optional resource identifier to include in the message
*/
public constructor(resource: string, id?: string) {
const message = id
? `${resource} with ID "${id}" was not found`
: `That ${resource.toLowerCase()} was not found`;
// Map common resources to specific error codes
const errorCodeMap: Record<string, ErrorCode> = {
contact: ErrorCode.CONTACT_NOT_FOUND,
template: ErrorCode.TEMPLATE_NOT_FOUND,
campaign: ErrorCode.CAMPAIGN_NOT_FOUND,
workflow: ErrorCode.WORKFLOW_NOT_FOUND,
};
const errorCode = errorCodeMap[resource.toLowerCase()] || ErrorCode.RESOURCE_NOT_FOUND;
super(404, message, errorCode, {resource, id});
}
}
/**
* Forbidden - user is not allowed to perform this action (403)
*/
export class NotAllowed extends HttpException {
/**
* Construct a new NotAllowed exception
* @param msg Custom error message
* @param reason Optional reason for the forbidden action
*/
public constructor(msg = 'You are not allowed to perform this action', reason?: string) {
super(403, msg, ErrorCode.FORBIDDEN, reason ? {reason} : undefined);
}
}
/**
* Unauthorized - user needs to authenticate (401)
*/
export class NotAuthenticated extends HttpException {
public constructor(message = 'You need to be authenticated to do this', errorCode = ErrorCode.UNAUTHORIZED) {
super(401, message, errorCode);
}
}
/**
* Payment required - user needs to upgrade plan (402)
*/
export class NeedToUpgrade extends HttpException {
public constructor(msg = 'You need to upgrade your plan to do this') {
super(402, msg, ErrorCode.UPGRADE_REQUIRED);
}
}
/**
* Validation error with field-level details (422)
*/
export class ValidationError extends HttpException {
/**
* Construct a new ValidationError exception
* @param errors Array of field-level validation errors
* @param message Optional override for the main error message
*/
public constructor(
public readonly errors: FieldError[],
message = 'Validation failed',
) {
super(422, message, ErrorCode.VALIDATION_ERROR, {errors});
}
}
/**
* Conflict - resource already exists or state conflict (409)
*/
export class ConflictError extends HttpException {
public constructor(message: string, details?: Record<string, unknown>) {
super(409, message, ErrorCode.CONFLICT, details);
}
}
/**
* Rate limit exceeded (429)
*/
export class RateLimitError extends HttpException {
public constructor(message = 'Rate limit exceeded. Please try again later.', retryAfter?: number) {
super(429, message, ErrorCode.RATE_LIMIT_EXCEEDED, retryAfter ? {retryAfter} : undefined);
}
}
/**
* Bad request - generic client error (400)
*/
export class BadRequest extends HttpException {
public constructor(message: string, errorCode = ErrorCode.BAD_REQUEST, details?: Record<string, unknown>) {
super(400, message, errorCode, details);
}
}