← back to Handbag Auth Nextjs
scripts/manageHandbagAffiliates.ts
195 lines
// Script to manage handbag affiliate program registry
// Add, update, and query affiliate partnerships
import fs from "fs";
import path from "path";
import type { HandbagAffiliateProgram } from "../src/types/handbagRss";
const AFFILIATES_FILE = path.resolve("data/handbag_affiliates.json");
// Load all affiliate programs
export function loadHandbagAffiliates(): HandbagAffiliateProgram[] {
if (!fs.existsSync(AFFILIATES_FILE)) {
return [];
}
return JSON.parse(fs.readFileSync(AFFILIATES_FILE, "utf8"));
}
// Save affiliate programs
export function saveHandbagAffiliates(list: HandbagAffiliateProgram[]) {
const dir = path.dirname(AFFILIATES_FILE);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(AFFILIATES_FILE, JSON.stringify(list, null, 2));
}
// Add or update an affiliate program
export function addOrUpdateAffiliate(program: HandbagAffiliateProgram) {
const list = loadHandbagAffiliates();
const existing = list.find((p) => p.domain === program.domain);
if (existing) {
Object.assign(existing, program);
console.log(`Updated affiliate: ${program.name}`);
} else {
list.push(program);
console.log(`Added new affiliate: ${program.name}`);
}
saveHandbagAffiliates(list);
return program;
}
// Get affiliate by domain
export function getAffiliateByDomain(domain: string): HandbagAffiliateProgram | undefined {
const list = loadHandbagAffiliates();
return list.find((p) => p.domain === domain);
}
// Get affiliates by merchant type
export function getAffiliatesByType(type: string): HandbagAffiliateProgram[] {
const list = loadHandbagAffiliates();
return list.filter((p) => p.merchantType === type);
}
// Extract domain from URL
export function getDomain(url: string): string {
try {
const u = new URL(url);
return u.hostname.replace(/^www\./, "");
} catch {
return url.replace(/^https?:\/\//, "").split("/")[0].replace(/^www\./, "");
}
}
// List all affiliates
export function listAffiliates() {
const list = loadHandbagAffiliates();
console.log(`\n=== Handbag Affiliate Programs (${list.length}) ===\n`);
const grouped = list.reduce((acc, prog) => {
if (!acc[prog.merchantType]) acc[prog.merchantType] = [];
acc[prog.merchantType].push(prog);
return acc;
}, {} as Record<string, HandbagAffiliateProgram[]>);
for (const [type, programs] of Object.entries(grouped)) {
console.log(`${type.toUpperCase()} (${programs.length}):`);
programs.forEach((p) => {
console.log(` - ${p.name} (${p.domain})`);
if (p.affiliateNetwork) console.log(` Network: ${p.affiliateNetwork}`);
if (p.commissionStructure) console.log(` Commission: ${p.commissionStructure}`);
});
console.log();
}
}
// Import from merchants CSV
export function importFromMerchantsCsv() {
const csvPath = path.resolve("data/handbag_merchants.csv");
if (!fs.existsSync(csvPath)) {
console.error("Merchants CSV not found at:", csvPath);
return;
}
const csv = fs.readFileSync(csvPath, "utf8");
const lines = csv.split("\n").slice(1); // Skip header
let imported = 0;
const existingList = loadHandbagAffiliates();
for (const line of lines) {
if (!line.trim()) continue;
const [name, domain, merchantType, affiliateNetwork, signupUrl, notes] = line
.split(",")
.map((s) => s.trim());
if (!domain) continue;
// Check if already exists
if (existingList.find((p) => p.domain === domain)) {
continue;
}
const program: HandbagAffiliateProgram = {
id: domain.replace(/\./g, "-"),
name,
website: `https://${domain}`,
domain,
merchantType: merchantType as any,
affiliateNetwork: affiliateNetwork || undefined,
signupUrl: signupUrl || undefined,
notes: notes || undefined,
};
addOrUpdateAffiliate(program);
imported++;
}
console.log(`Imported ${imported} new affiliate programs from CSV.`);
}
// CLI interface
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
if (isMainModule) {
const command = process.argv[2];
switch (command) {
case "list":
listAffiliates();
break;
case "add": {
const sample: HandbagAffiliateProgram = {
id: "fashionphile",
name: "Fashionphile",
website: "https://www.fashionphile.com",
domain: "fashionphile.com",
merchantType: "reseller",
affiliateNetwork: "Impact",
commissionStructure: "5% commission",
cookieDurationDays: 30,
signupUrl: "https://fashionphile.com/affiliates",
notes: "Leading pre-owned luxury handbag reseller with authentication guarantee",
};
addOrUpdateAffiliate(sample);
console.log("\nSample affiliate added. Edit the script to add your own.");
break;
}
case "import-csv":
importFromMerchantsCsv();
break;
case "by-type": {
const type = process.argv[3];
if (!type) {
console.error("Usage: ts-node manageHandbagAffiliates.ts by-type <type>");
console.log("Types: brand, retailer, reseller, auction");
process.exit(1);
}
const programs = getAffiliatesByType(type);
console.log(`\n${type.toUpperCase()} Affiliates (${programs.length}):\n`);
programs.forEach((p) => {
console.log(`- ${p.name} (${p.domain})`);
});
break;
}
default:
console.log("Handbag Affiliate Program Manager");
console.log("\nUsage:");
console.log(" ts-node scripts/manageHandbagAffiliates.ts <command>");
console.log("\nCommands:");
console.log(" list - List all affiliate programs");
console.log(" add - Add sample affiliate (edit script to customize)");
console.log(" import-csv - Import from handbag_merchants.csv");
console.log(" by-type <type> - List affiliates by merchant type");
process.exit(1);
}
}