barsa b1ff1e8fd3 Refactor GitHub Workflows to Consolidate Node and pnpm Setup
- Unified Node.js and pnpm setup across deploy, pr-checks, and security workflows by introducing a custom action for streamlined configuration.
- Removed redundant setup steps to enhance workflow clarity and maintainability.
- Updated security workflow to include concurrency control for better job management.
2025-12-25 19:01:00 +09:00

206 lines
6.9 KiB
TypeScript

/**
* Freebit SIM Provider - Mapper
*/
import type { SimDetails, SimUsage, SimTopUpHistory, SimType, SimStatus } from "../../contract.js";
import { simDetailsSchema, simUsageSchema, simTopUpHistorySchema } from "../../schema.js";
import {
type FreebitAuthResponseRaw,
freebitAccountDetailsRawSchema,
freebitTrafficInfoRawSchema,
freebitQuotaHistoryRawSchema,
freebitAuthResponseRawSchema,
freebitTopUpRawSchema,
freebitAddSpecRawSchema,
freebitPlanChangeRawSchema,
freebitCancelPlanRawSchema,
freebitCancelAccountRawSchema,
freebitEsimReissueRawSchema,
freebitEsimAddAccountRawSchema,
} from "./raw.types.js";
function asString(value: unknown): string {
if (typeof value === "string") return value;
if (typeof value === "number") return String(value);
return "";
}
function asNumber(value: unknown): number {
if (typeof value === "number") return value;
if (typeof value === "string") {
const parsed = parseFloat(value);
return isNaN(parsed) ? 0 : parsed;
}
return 0;
}
function parseBooleanFlag(value: unknown): boolean {
if (typeof value === "boolean") return value;
if (typeof value === "number") return value === 10;
if (typeof value === "string") return value === "10" || value.toLowerCase() === "true";
return false;
}
function mapSimStatus(status: string | undefined): SimStatus {
if (!status) return "pending";
const normalized = status.toLowerCase();
if (normalized.includes("active") || normalized === "10") return "active";
if (normalized.includes("suspend")) return "suspended";
if (normalized.includes("cancel") || normalized.includes("terminate")) return "cancelled";
return "pending";
}
function deriveSimType(sizeValue: unknown, eid?: string | number | null): SimType {
const simSizeStr = typeof sizeValue === "number" ? String(sizeValue) : sizeValue;
const raw = typeof simSizeStr === "string" ? simSizeStr.toLowerCase() : undefined;
const eidStr = typeof eid === "number" ? String(eid) : eid;
if (eidStr && eidStr.length > 0) {
return "esim";
}
switch (raw) {
case "nano":
return "nano";
case "micro":
return "micro";
case "esim":
return "esim";
default:
return "standard";
}
}
export function transformFreebitAccountDetails(raw: unknown): SimDetails {
const response = freebitAccountDetailsRawSchema.parse(raw);
const account = response.responseDatas.at(0);
if (!account) {
throw new Error("Freebit account details missing response data");
}
const sanitizedAccount = asString(account.account);
const legacySize = "size" in account ? (account as { size?: unknown }).size : undefined;
const simSizeValue = account.simSize ?? legacySize;
const eidValue = account.eid;
const simType = deriveSimType(
typeof simSizeValue === "number" ? String(simSizeValue) : simSizeValue,
typeof eidValue === "number" ? String(eidValue) : eidValue
);
const voiceMailEnabled = parseBooleanFlag(account.voicemail ?? account.voiceMail);
const callWaitingEnabled = parseBooleanFlag(account.callwaiting ?? account.callWaiting);
const internationalRoamingEnabled = parseBooleanFlag(account.worldwing ?? account.worldWing);
const simDetails: SimDetails = {
account: sanitizedAccount,
status: mapSimStatus(account.status),
planCode: asString(account.planCode),
planName: asString(account.planName),
simType,
iccid: asString(account.iccid),
eid: asString(eidValue),
msisdn: asString(account.msisdn),
imsi: asString(account.imsi),
remainingQuotaMb: asNumber(account.quota),
remainingQuotaKb: asNumber(account.quotaKb),
voiceMailEnabled,
callWaitingEnabled,
internationalRoamingEnabled,
networkType: asString(account.contractLine),
activatedAt: asString(account.startDate) || undefined,
expiresAt: asString(account.expireDate) || undefined,
};
return simDetailsSchema.parse(simDetails);
}
export function transformFreebitTrafficInfo(raw: unknown): SimUsage {
const response = freebitTrafficInfoRawSchema.parse(raw);
const simUsage: SimUsage = {
account: asString(response.account),
todayUsageMb: response.traffic?.today ? asNumber(response.traffic.today) / 1024 : 0,
todayUsageKb: response.traffic?.today ? asNumber(response.traffic.today) : 0,
monthlyUsageMb: undefined,
monthlyUsageKb: undefined,
recentDaysUsage: [],
isBlacklisted: parseBooleanFlag(response.traffic?.blackList),
lastUpdated: new Date().toISOString(),
};
return simUsageSchema.parse(simUsage);
}
export function transformFreebitQuotaHistory(
raw: unknown,
accountOverride?: string
): SimTopUpHistory {
const response = freebitQuotaHistoryRawSchema.parse(raw);
const history: SimTopUpHistory = {
account: accountOverride ?? asString(response.account),
totalAdditions: asNumber(response.total),
additionCount: asNumber(response.count),
history: (response.quotaHistory || []).map(detail => ({
quotaKb: asNumber(detail.addQuotaKb),
quotaMb: asNumber(detail.addQuotaKb) / 1024,
addedDate: detail.addDate || "",
expiryDate: detail.expireDate || "",
campaignCode: detail.campaignCode || "",
})),
};
return simTopUpHistorySchema.parse(history);
}
export function transformFreebitTopUpResponse(raw: unknown) {
return freebitTopUpRawSchema.parse(raw);
}
export type FreebitTopUpResponse = ReturnType<typeof transformFreebitTopUpResponse>;
export function transformFreebitAddSpecResponse(raw: unknown) {
return freebitAddSpecRawSchema.parse(raw);
}
export type FreebitAddSpecResponse = ReturnType<typeof transformFreebitAddSpecResponse>;
export function transformFreebitPlanChangeResponse(raw: unknown) {
return freebitPlanChangeRawSchema.parse(raw);
}
export type FreebitPlanChangeResponse = ReturnType<typeof transformFreebitPlanChangeResponse>;
export function transformFreebitCancelPlanResponse(raw: unknown) {
return freebitCancelPlanRawSchema.parse(raw);
}
export type FreebitCancelPlanResponse = ReturnType<typeof transformFreebitCancelPlanResponse>;
export function transformFreebitCancelAccountResponse(raw: unknown) {
return freebitCancelAccountRawSchema.parse(raw);
}
export type FreebitCancelAccountResponse = ReturnType<typeof transformFreebitCancelAccountResponse>;
export function transformFreebitEsimReissueResponse(raw: unknown) {
return freebitEsimReissueRawSchema.parse(raw);
}
export type FreebitEsimReissueResponse = ReturnType<typeof transformFreebitEsimReissueResponse>;
export function transformFreebitEsimAddAccountResponse(raw: unknown) {
return freebitEsimAddAccountRawSchema.parse(raw);
}
export type FreebitEsimAddAccountResponse = ReturnType<
typeof transformFreebitEsimAddAccountResponse
>;
export function transformFreebitEsimActivationResponse(raw: unknown) {
return freebitEsimAddAccountRawSchema.parse(raw);
}
export function transformFreebitAuthResponse(raw: unknown): FreebitAuthResponseRaw {
return freebitAuthResponseRawSchema.parse(raw);
}