- Deleted migration file that removed cached profile fields from the users table, centralizing profile data retrieval from WHMCS. - Updated CsrfMiddleware to include new public authentication endpoints for password reset, setting password, and WHMCS account linking. - Enhanced error handling in password and WHMCS linking workflows to provide clearer feedback on missing mappings and improve user experience. - Adjusted user creation and update methods in UsersFacade to handle cases where WHMCS mappings are not yet available, ensuring smoother account setup.
100 lines
3.2 KiB
TypeScript
100 lines
3.2 KiB
TypeScript
/**
|
|
* Custom error class for Freebit API errors
|
|
*/
|
|
export class FreebitError extends Error {
|
|
public readonly resultCode?: string | number;
|
|
public readonly statusCode?: string | number;
|
|
public readonly statusMessage?: string;
|
|
|
|
constructor(
|
|
message: string,
|
|
resultCode?: string | number,
|
|
statusCode?: string | number,
|
|
statusMessage?: string
|
|
) {
|
|
super(message);
|
|
this.name = "FreebitError";
|
|
this.resultCode = resultCode;
|
|
this.statusCode = statusCode;
|
|
this.statusMessage = statusMessage;
|
|
|
|
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
|
if (Error.captureStackTrace) {
|
|
Error.captureStackTrace(this, FreebitError);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if error indicates authentication failure
|
|
*/
|
|
isAuthError(): boolean {
|
|
return (
|
|
this.resultCode === "401" ||
|
|
this.statusCode === "401" ||
|
|
this.message.toLowerCase().includes("authentication") ||
|
|
this.message.toLowerCase().includes("unauthorized")
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Check if error indicates rate limiting
|
|
*/
|
|
isRateLimitError(): boolean {
|
|
return (
|
|
this.resultCode === "429" ||
|
|
this.statusCode === "429" ||
|
|
this.message.toLowerCase().includes("rate limit") ||
|
|
this.message.toLowerCase().includes("too many requests")
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Check if error is retryable
|
|
*/
|
|
isRetryable(): boolean {
|
|
const retryableCodes = ["500", "502", "503", "504", "408", "429"];
|
|
return (
|
|
retryableCodes.includes(String(this.resultCode)) ||
|
|
retryableCodes.includes(String(this.statusCode)) ||
|
|
this.message.toLowerCase().includes("timeout") ||
|
|
this.message.toLowerCase().includes("network")
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get user-friendly error message
|
|
*/
|
|
getUserFriendlyMessage(): string {
|
|
if (this.isAuthError()) {
|
|
return "SIM service is temporarily unavailable. Please try again later.";
|
|
}
|
|
|
|
if (this.isRateLimitError()) {
|
|
return "Service is busy. Please wait a moment and try again.";
|
|
}
|
|
|
|
if (this.message.toLowerCase().includes("account not found")) {
|
|
return "SIM account not found. Please contact support to verify your SIM configuration.";
|
|
}
|
|
|
|
if (this.message.toLowerCase().includes("timeout")) {
|
|
return "SIM service request timed out. Please try again.";
|
|
}
|
|
|
|
// Specific error codes
|
|
if (this.resultCode === "215" || this.statusCode === "215") {
|
|
return "Plan change failed. This may be due to: (1) Account has existing scheduled operations, (2) Invalid plan code for this account, (3) Account restrictions. Please check the Freebit Partner Tools for account status or contact support.";
|
|
}
|
|
|
|
if (this.resultCode === "381" || this.statusCode === "381") {
|
|
return "Network type change rejected. The current plan does not allow switching to the requested contract line. Adjust the plan first or contact support.";
|
|
}
|
|
|
|
if (this.resultCode === "382" || this.statusCode === "382") {
|
|
return "Network type change rejected because the contract line is not eligible for modification at this time. Please verify the SIM's status in Freebit before retrying.";
|
|
}
|
|
|
|
return "SIM operation failed. Please try again or contact support.";
|
|
}
|
|
}
|