From c206598615544e53cfcbbbf09dd93625b1e4a7a6 Mon Sep 17 00:00:00 2001 From: barsa Date: Fri, 3 Oct 2025 17:13:02 +0900 Subject: [PATCH] Refactor Freebit integration services to enhance type safety and maintainability by utilizing updated provider methods and removing deprecated types. Update authentication and mapping logic to align with the new domain structure, improving data handling consistency across services. Introduce new response transformation methods for Freebit authentication, ensuring robust error handling and streamlined integration. --- .../freebit/services/freebit-auth.service.ts | 31 ++++++---- .../services/freebit-mapper.service.ts | 11 +--- .../services/freebit-operations.service.ts | 59 +++++++++---------- .../domain/sim/providers/freebit/index.ts | 1 + .../domain/sim/providers/freebit/mapper.ts | 8 +++ .../domain/sim/providers/freebit/raw.types.ts | 13 ++++ 6 files changed, 75 insertions(+), 48 deletions(-) diff --git a/apps/bff/src/integrations/freebit/services/freebit-auth.service.ts b/apps/bff/src/integrations/freebit/services/freebit-auth.service.ts index 90a0a97a..6950ae1a 100644 --- a/apps/bff/src/integrations/freebit/services/freebit-auth.service.ts +++ b/apps/bff/src/integrations/freebit/services/freebit-auth.service.ts @@ -3,12 +3,21 @@ import { ConfigService } from "@nestjs/config"; import { Logger } from "nestjs-pino"; import { getErrorMessage } from "@bff/core/utils/error.util"; import type { - FreebitConfig, - FreebitAuthRequest, - FreebitAuthResponse, + AuthRequest as FreebitAuthRequest, + AuthResponse as FreebitAuthResponse, } from "@customer-portal/domain/sim/providers/freebit"; +import { Providers } from "@customer-portal/domain/sim"; import { FreebitError } from "./freebit-error.service"; +interface FreebitConfig { + baseUrl: string; + oemId: string; + oemKey: string; + timeout: number; + retryAttempts: number; + detailsEndpoint?: string; +} + @Injectable() export class FreebitAuthService { private readonly config: FreebitConfig; @@ -60,10 +69,10 @@ export class FreebitAuthService { throw new Error("Freebit API not configured: FREEBIT_OEM_KEY is missing"); } - const request: FreebitAuthRequest = { + const request = Providers.Freebit.schemas.auth.parse({ oemId: this.config.oemId, oemKey: this.config.oemKey, - }; + }); const response = await fetch(`${this.config.baseUrl}/authOem/`, { method: "POST", @@ -75,13 +84,15 @@ export class FreebitAuthService { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } - const data = (await response.json()) as FreebitAuthResponse; - if (data.resultCode !== "100") { + const json = (await response.json()) as unknown; + const data = Providers.Freebit.mapper.transformFreebitAuthResponse(json); + + if (data.resultCode !== "100" || !data.authKey) { throw new FreebitError( - `Authentication failed: ${data.status.message}`, + `Authentication failed: ${data.status?.message ?? "Unknown error"}`, data.resultCode, - data.status.statusCode, - data.status.message + data.status?.statusCode, + data.status?.message ); } diff --git a/apps/bff/src/integrations/freebit/services/freebit-mapper.service.ts b/apps/bff/src/integrations/freebit/services/freebit-mapper.service.ts index 3d3b118e..47c8fd88 100644 --- a/apps/bff/src/integrations/freebit/services/freebit-mapper.service.ts +++ b/apps/bff/src/integrations/freebit/services/freebit-mapper.service.ts @@ -1,9 +1,4 @@ import { Injectable } from "@nestjs/common"; -import type { - FreebitAccountDetailsResponse, - FreebitTrafficInfoResponse, - FreebitQuotaHistoryResponse, -} from "@customer-portal/domain/sim/providers/freebit"; import type { SimDetails, SimTopUpHistory, SimUsage } from "@customer-portal/domain/sim"; import { Providers } from "@customer-portal/domain/sim"; @@ -12,21 +7,21 @@ export class FreebitMapperService { /** * Map Freebit account details response to SimDetails */ - mapToSimDetails(response: FreebitAccountDetailsResponse): SimDetails { + mapToSimDetails(response: unknown): SimDetails { return Providers.Freebit.transformFreebitAccountDetails(response); } /** * Map Freebit traffic info response to SimUsage */ - mapToSimUsage(response: FreebitTrafficInfoResponse): SimUsage { + mapToSimUsage(response: unknown): SimUsage { return Providers.Freebit.transformFreebitTrafficInfo(response); } /** * Map Freebit quota history response to SimTopUpHistory */ - mapToSimTopUpHistory(response: FreebitQuotaHistoryResponse, account: string): SimTopUpHistory { + mapToSimTopUpHistory(response: unknown, account: string): SimTopUpHistory { return Providers.Freebit.transformFreebitQuotaHistory(response, account); } diff --git a/apps/bff/src/integrations/freebit/services/freebit-operations.service.ts b/apps/bff/src/integrations/freebit/services/freebit-operations.service.ts index f3a4760d..c873b177 100644 --- a/apps/bff/src/integrations/freebit/services/freebit-operations.service.ts +++ b/apps/bff/src/integrations/freebit/services/freebit-operations.service.ts @@ -5,16 +5,15 @@ import { FreebitClientService } from "./freebit-client.service"; import { FreebitMapperService } from "./freebit-mapper.service"; import { FreebitAuthService } from "./freebit-auth.service"; import type { - FreebitAccountDetailsResponse, - FreebitTrafficInfoResponse, - FreebitTopUpResponse, - FreebitQuotaHistoryResponse, - FreebitPlanChangeResponse, - FreebitAddSpecResponse, - FreebitCancelPlanResponse, - FreebitEsimReissueResponse, - FreebitEsimAddAccountResponse, - FreebitEsimAccountActivationResponse, + TopUpResponse, + PlanChangeResponse, + AddSpecResponse, + CancelPlanResponse, + CancelAccountResponse, + EsimReissueResponse, + EsimAddAccountResponse, + EsimActivationResponse, + QuotaHistoryRequest, } from "@customer-portal/domain/sim/providers/freebit"; import type { FreebitTopUpRequest, @@ -73,7 +72,7 @@ export class FreebitOperationsService { ]) ); - let response: FreebitAccountDetailsResponse | undefined; + let response: Providers.Freebit.mapper.FreebitAccountDetailsResponse | undefined; let lastError: unknown; for (const ep of candidates) { @@ -82,7 +81,7 @@ export class FreebitOperationsService { this.logger.warn(`Retrying Freebit account details with alternative endpoint: ${ep}`); } response = await this.client.makeAuthenticatedRequest< - FreebitAccountDetailsResponse, + Providers.Freebit.mapper.FreebitAccountDetailsResponse, typeof request >(ep, request); break; @@ -120,7 +119,7 @@ export class FreebitOperationsService { const request: FreebitTrafficInfoRequest = Providers.Freebit.schemas.trafficInfo.parse({ account }); const response = await this.client.makeAuthenticatedRequest< - FreebitTrafficInfoResponse, + Providers.Freebit.mapper.FreebitTrafficInfoResponse, typeof request >("/mvno/getTrafficInfo/", request); @@ -159,7 +158,7 @@ export class FreebitOperationsService { ? { ...baseRequest, runTime: payload.options?.scheduledAt } : baseRequest; - await this.client.makeAuthenticatedRequest( + await this.client.makeAuthenticatedRequest( endpoint, request ); @@ -198,8 +197,8 @@ export class FreebitOperationsService { }); const response = await this.client.makeAuthenticatedRequest< - FreebitQuotaHistoryResponse, - FreebitQuotaHistoryRequest + Providers.Freebit.mapper.FreebitQuotaHistoryResponse, + QuotaHistoryRequest >("/mvno/getQuotaHistory/", request); return this.mapper.mapToSimTopUpHistory(response, account); @@ -239,10 +238,10 @@ export class FreebitOperationsService { runTime: parsed.scheduledAt, }; - const response = await this.client.makeAuthenticatedRequest< - FreebitPlanChangeResponse, - typeof request - >("/mvno/changePlan/", request); + const response = await this.client.makeAuthenticatedRequest( + "/mvno/changePlan/", + request + ); this.logger.log(`Successfully changed plan for account ${parsed.account} to ${parsed.newPlanCode}`, { account: parsed.account, @@ -314,7 +313,7 @@ export class FreebitOperationsService { payload.contractLine = features.networkType; } - await this.client.makeAuthenticatedRequest( + await this.client.makeAuthenticatedRequest( "/master/addSpec/", payload ); @@ -352,7 +351,7 @@ export class FreebitOperationsService { runTime: parsed.runDate, }; - await this.client.makeAuthenticatedRequest( + await this.client.makeAuthenticatedRequest( "/mvno/releasePlan/", request ); @@ -381,7 +380,7 @@ export class FreebitOperationsService { requestDatas: [{ kind: "MVNO", account }], }; - await this.client.makeAuthenticatedRequest( + await this.client.makeAuthenticatedRequest( "/mvno/reissueEsim/", request ); @@ -422,14 +421,14 @@ export class FreebitOperationsService { planCode: parsed.planCode, }); - const request: FreebitEsimAddAccountRequest = { + const payload: FreebitEsimAddAccountRequest = { ...requestPayload, authKey: await this.auth.getAuthKey(), }; - await this.client.makeAuthenticatedRequest( + await this.client.makeAuthenticatedRequest( "/mvno/esim/addAcnt/", - request + payload ); this.logger.log(`Successfully reissued eSIM profile via addAcnt for account ${parsed.account}`, { @@ -515,10 +514,10 @@ export class FreebitOperationsService { Providers.Freebit.schemas.esimActivationRequest.parse(payload); // Use JSON request for PA05-41 - await this.client.makeAuthenticatedJsonRequest< - FreebitEsimAccountActivationResponse, - typeof payload - >("/mvno/esim/addAcct/", payload); + await this.client.makeAuthenticatedJsonRequest( + "/mvno/esim/addAcct/", + payload + ); this.logger.log("Successfully activated new eSIM account via PA05-41", { account, diff --git a/packages/domain/sim/providers/freebit/index.ts b/packages/domain/sim/providers/freebit/index.ts index 0c17e26b..0d622d65 100644 --- a/packages/domain/sim/providers/freebit/index.ts +++ b/packages/domain/sim/providers/freebit/index.ts @@ -47,6 +47,7 @@ export type CancelAccountResponse = ReturnType; export type EsimAddAccountResponse = ReturnType; export type EsimActivationResponse = ReturnType; +export type AuthResponse = ReturnType; export * from "./mapper"; export * from "./raw.types"; diff --git a/packages/domain/sim/providers/freebit/mapper.ts b/packages/domain/sim/providers/freebit/mapper.ts index 5e14083c..0bbb75a3 100644 --- a/packages/domain/sim/providers/freebit/mapper.ts +++ b/packages/domain/sim/providers/freebit/mapper.ts @@ -8,6 +8,7 @@ import { type FreebitAccountDetailsRaw, type FreebitTrafficInfoRaw, type FreebitQuotaHistoryRaw, + type FreebitAuthResponseRaw, type FreebitTopUpRaw, type FreebitAddSpecRaw, type FreebitPlanChangeRaw, @@ -18,6 +19,7 @@ import { freebitAccountDetailsRawSchema, freebitTrafficInfoRawSchema, freebitQuotaHistoryRawSchema, + freebitAuthResponseRawSchema, freebitTopUpRawSchema, freebitAddSpecRawSchema, freebitPlanChangeRawSchema, @@ -206,4 +208,10 @@ export function transformFreebitEsimActivationResponse(raw: unknown) { return freebitEsimAddAccountRawSchema.parse(raw); } +export type FreebitEsimActivationResponse = ReturnType; + +export function transformFreebitAuthResponse(raw: unknown): FreebitAuthResponseRaw { + return freebitAuthResponseRawSchema.parse(raw); +} + diff --git a/packages/domain/sim/providers/freebit/raw.types.ts b/packages/domain/sim/providers/freebit/raw.types.ts index af28d5a0..e72a2ef8 100644 --- a/packages/domain/sim/providers/freebit/raw.types.ts +++ b/packages/domain/sim/providers/freebit/raw.types.ts @@ -166,3 +166,16 @@ export const freebitQuotaHistoryRawSchema = z.object({ export type FreebitQuotaHistoryRaw = z.infer; +export const freebitAuthResponseRawSchema = z.object({ + resultCode: z.string().optional(), + status: z + .object({ + message: z.string().optional(), + statusCode: z.union([z.string(), z.number()]).optional(), + }) + .optional(), + authKey: z.string().optional(), +}); + +export type FreebitAuthResponseRaw = z.infer; +