/**
* Affiliate Links Generator
*
* Generates Joker.com purchase URLs with optional affiliate tracking.
* Falls back to regular purchase links when affiliate ID is not configured.
*/
import type { JokerPricingResult } from './price-cache.js';
/**
* Purchase link data structure
*/
export interface PurchaseLink {
registrar: 'joker';
domain: string;
url: string;
is_affiliate: boolean;
price_estimate?: number;
currency?: string;
}
/**
* Generate Joker.com purchase link for a single domain
*
* @param domain - Domain name to purchase
* @param pricingData - Optional pricing data for price estimate
* @returns Purchase link with affiliate tracking if configured
*/
export function generateJokerLink(
domain: string,
pricingData?: JokerPricingResult
): PurchaseLink {
const affiliateId = process.env.MCP_AFFILIATE_JOKER_ID;
const normalizedDomain = domain.toLowerCase().trim();
// Base URL for domain registration
// Note: Actual URL format should be verified with Joker.com documentation
// This is a placeholder that may need adjustment
const baseUrl = `https://joker.com/domain/registration`;
// Build URL with or without affiliate parameter
let url: string;
if (affiliateId && affiliateId.trim() !== '') {
// Affiliate link
url = `${baseUrl}?domain=${encodeURIComponent(normalizedDomain)}&aff=${encodeURIComponent(affiliateId)}`;
} else {
// Regular link (no affiliate)
url = `${baseUrl}?domain=${encodeURIComponent(normalizedDomain)}`;
}
return {
registrar: 'joker',
domain: normalizedDomain,
url,
is_affiliate: !!(affiliateId && affiliateId.trim() !== ''),
price_estimate: pricingData?.pricing?.registration_1yr,
currency: pricingData?.pricing?.currency,
};
}
/**
* Generate purchase links for multiple domains
*
* @param domains - Array of domain names
* @param pricingData - Optional map of domain → pricing data
* @returns Array of purchase links
*/
export function generateMultiDomainLinks(
domains: string[],
pricingData?: Map<string, JokerPricingResult>
): PurchaseLink[] {
return domains.map(domain => {
const pricing = pricingData?.get(domain.toLowerCase());
return generateJokerLink(domain, pricing);
});
}
/**
* Calculate total estimated cost for multiple domains
*
* @param links - Array of purchase links
* @returns Total cost and currency, or null if prices unavailable
*/
export function calculateTotal(links: PurchaseLink[]): {
total: number;
currency: string;
domains_with_pricing: number;
domains_without_pricing: number;
} | null {
const linksWithPricing = links.filter(link => link.price_estimate !== undefined);
if (linksWithPricing.length === 0) {
return null;
}
// Use currency from first link with pricing
const currency = linksWithPricing[0].currency || 'EUR';
// Calculate total
const total = linksWithPricing.reduce((sum, link) => sum + (link.price_estimate || 0), 0);
return {
total,
currency,
domains_with_pricing: linksWithPricing.length,
domains_without_pricing: links.length - linksWithPricing.length,
};
}