105 lines
3.0 KiB
TypeScript

/**
* WHMCS Provider - Mapper
*
* Maps WHMCS API responses to domain types.
* Minimal transformation - validates and normalizes only address structure.
*/
import type { WhmcsClient, Address } from "../../schema.js";
import { whmcsClientSchema, addressSchema } from "../../schema.js";
import {
whmcsClientSchema as whmcsRawClientSchema,
whmcsClientResponseSchema,
type WhmcsClient as WhmcsRawClient,
type WhmcsClientResponse,
} from "./raw.types.js";
/**
* Parse and validate WHMCS client response
*/
export const parseWhmcsClientResponse = (raw: unknown): WhmcsClientResponse =>
whmcsClientResponseSchema.parse(raw);
/**
* Transform WHMCS client response to domain WhmcsClient
*/
export function transformWhmcsClientResponse(response: unknown): WhmcsClient {
const parsed = parseWhmcsClientResponse(response);
return transformWhmcsClient(parsed.client);
}
/**
* Transform raw WHMCS client to domain WhmcsClient
*
* Keeps raw WHMCS field names, only normalizes:
* - Address structure to domain Address type
* - Type coercions (strings to numbers/booleans)
*/
export function transformWhmcsClient(raw: WhmcsRawClient): WhmcsClient {
return whmcsClientSchema.parse({
...raw,
// Only normalize address to our domain structure
address: normalizeAddress(raw),
});
}
/**
* Normalize WHMCS address fields to domain Address structure
*/
function normalizeAddress(client: WhmcsRawClient): Address | undefined {
const address = addressSchema.parse({
address1: client.address1 ?? null,
address2: client.address2 ?? null,
city: client.city ?? null,
state: client.fullstate ?? client.state ?? null,
postcode: client.postcode ?? null,
country: client.country ?? null,
countryCode: client.countrycode ?? null,
phoneNumber: client.phonenumberformatted ?? client.phonenumber ?? null,
phoneCountryCode: client.phonecc ?? null,
});
const hasValues = Object.values(address).some(v => v !== undefined && v !== null && v !== "");
return hasValues ? address : undefined;
}
/**
* Transform WHMCS client address to domain Address
*/
export const transformWhmcsClientAddress = (raw: unknown): Address | undefined => {
const client = whmcsRawClientSchema.parse(raw);
return normalizeAddress(client);
};
/**
* Mapping from domain Address keys to WHMCS API field names
*/
const ADDRESS_FIELD_MAP: Record<keyof Address, string> = {
address1: "address1",
address2: "address2",
city: "city",
state: "state",
postcode: "postcode",
country: "country",
countryCode: "countrycode",
phoneNumber: "phonenumber",
phoneCountryCode: "phonecc",
};
/**
* Prepare address update for WHMCS API
* Converts domain Address to WHMCS field names
*/
export const prepareWhmcsClientAddressUpdate = (
address: Partial<Address>
): Record<string, unknown> => {
const update: Record<string, unknown> = {};
for (const [domainKey, whmcsKey] of Object.entries(ADDRESS_FIELD_MAP)) {
const value = address[domainKey as keyof Address];
if (value !== undefined) {
update[whmcsKey] = value ?? "";
}
}
return update;
};