export const CARD_BRANDS = [ "visa", "mastercard", "unionpay", "amex", "diners", "discover", "jcb", ] as const export type CardBrand = (typeof CARD_BRANDS)[number] export const CARD_BRAND_LABELS: Record = { visa: "Visa", mastercard: "Mastercard", unionpay: "UnionPay", amex: "American Express", diners: "Diners Club", discover: "Discover", jcb: "JCB", } export const CARD_BRAND_LOGOS: Record = { visa: "/payment-logos/visa.svg", mastercard: "/payment-logos/mastercard.svg", unionpay: "/payment-logos/unionpay.svg", amex: "/payment-logos/amex.svg", diners: "/payment-logos/diners.svg", discover: "/payment-logos/discover.svg", jcb: "/payment-logos/jcb.svg", } const CARD_BRAND_ALIASES: Record = { visa: "visa", mastercard: "mastercard", unionpay: "unionpay", amex: "amex", americanexpress: "amex", diners: "diners", dinersclub: "diners", discover: "discover", jcb: "jcb", } export function normalizeCardBrand( input: string | null | undefined ): CardBrand | null { if (typeof input !== "string") { return null } const key = input .trim() .toLowerCase() .replace(/[\s_-]+/g, "") return CARD_BRAND_ALIASES[key] ?? null } export function getCardBrandLogoUrl( input: string | null | undefined ): string | null { const brand = normalizeCardBrand(input) return brand ? CARD_BRAND_LOGOS[brand] : null } type CardNumberResult = { card: { type?: string } | null isPotentiallyValid: boolean } type CardValidatorApi = { number?: (value: string) => CardNumberResult } type CardValidatorModule = CardValidatorApi & { default?: CardValidatorApi } export async function detectCardBrand( cardNumber: string ): Promise { const digits = cardNumber.replace(/\D/g, "") if (!digits) { return null } try { const loadedValidator = (await import("card-validator")) as unknown as CardValidatorModule const validator = loadedValidator.default ?? loadedValidator if (typeof validator.number !== "function") { return null } const result = validator.number(digits) if (!result.card || !result.isPotentiallyValid) { return null } return result.card.type ? normalizeCardBrand(result.card.type) : null } catch { return null } }