Assist_Design/apps/bff/src/integrations/freebit/services/freebit-account.service.ts
barsa 03eccd1db2 Enhance Error Handling and Logging Consistency Across Services
- Replaced instances of `getErrorMessage` with `extractErrorMessage` in various services to ensure consistent error handling and improve clarity in logging.
- Updated error logging in the Whmcs, Salesforce, and subscription services to utilize the new error extraction method, enhancing maintainability and debugging capabilities.
- Adjusted ESLint configuration to prevent the use of `console.log` in production code, promoting the use of a centralized logging solution.
- Refactored error handling in the Agentforce widget and other components to align with the updated logging practices, ensuring a consistent approach to error management across the application.
- Cleaned up unused imports and optimized code structure for better maintainability.
2025-12-29 15:07:11 +09:00

122 lines
3.7 KiB
TypeScript

import { Injectable, Inject, BadRequestException } from "@nestjs/common";
import { Logger } from "nestjs-pino";
import { extractErrorMessage } from "@bff/core/utils/error.util.js";
import { FreebitClientService } from "./freebit-client.service.js";
import { FreebitMapperService } from "./freebit-mapper.service.js";
import { FreebitAuthService } from "./freebit-auth.service.js";
import type {
FreebitAccountDetailsRequest,
FreebitAccountDetailsResponse,
SimDetails,
} from "../interfaces/freebit.types.js";
/**
* Service for Freebit account/SIM details operations.
* Handles fetching SIM details and health checks.
*/
@Injectable()
export class FreebitAccountService {
constructor(
private readonly client: FreebitClientService,
private readonly mapper: FreebitMapperService,
private readonly auth: FreebitAuthService,
@Inject(Logger) private readonly logger: Logger
) {}
/**
* Get SIM account details with endpoint fallback
*/
async getSimDetails(account: string): Promise<SimDetails> {
try {
const request: Omit<FreebitAccountDetailsRequest, "authKey"> = {
version: "2",
requestDatas: [{ kind: "MVNO", account }],
};
const config = this.auth.getConfig();
const configured = config.detailsEndpoint || "/master/getAcnt/";
const candidates = Array.from(
new Set([
configured,
configured.replace(/\/$/, ""),
"/master/getAcnt/",
"/master/getAcnt",
"/mvno/getAccountDetail/",
"/mvno/getAccountDetail",
"/mvno/getAcntDetail/",
"/mvno/getAcntDetail",
"/mvno/getAccountInfo/",
"/mvno/getAccountInfo",
"/mvno/getSubscriberInfo/",
"/mvno/getSubscriberInfo",
"/mvno/getInfo/",
"/mvno/getInfo",
"/master/getDetail/",
"/master/getDetail",
])
);
let response: FreebitAccountDetailsResponse | undefined;
let lastError: unknown;
for (const ep of candidates) {
try {
if (ep !== candidates[0]) {
this.logger.warn(`Retrying Freebit account details with alternative endpoint: ${ep}`);
}
response = await this.client.makeAuthenticatedRequest<
FreebitAccountDetailsResponse,
typeof request
>(ep, request);
break;
} catch (err: unknown) {
lastError = err;
if (extractErrorMessage(err).includes("HTTP 404")) {
continue; // try next endpoint for 404 (endpoint not found)
}
// For non-404 errors (auth failures, rate limits, 500s, etc.), fail fast
break;
}
}
if (!response) {
if (lastError instanceof Error) {
throw lastError;
}
throw new Error("Failed to get SIM details from any endpoint");
}
return await this.mapper.mapToSimDetails(response);
} catch (error) {
const message = extractErrorMessage(error);
this.logger.error(`Failed to get SIM details for account ${account}`, {
account,
error: message,
});
throw new BadRequestException(`Failed to get SIM details: ${message}`);
}
}
/**
* Health check - test API connectivity
*/
async healthCheck(): Promise<boolean> {
try {
// Try a simple endpoint first
const simpleCheck = await this.client.makeSimpleRequest("/");
if (simpleCheck) {
return true;
}
// If simple check fails, try authenticated request
await this.auth.getAuthKey();
return true;
} catch (error) {
this.logger.debug("Freebit health check failed", {
error: extractErrorMessage(error),
});
return false;
}
}
}