const { onRequest } = require("firebase-functions/v2/https"); const logger = require("firebase-functions/logger"); const axios = require("axios"); // Primary API Credentials const ADZUNA_APP_ID = process.env.ADZUNA_APP_ID || "c4e282b6"; const ADZUNA_APP_KEY = process.env.ADZUNA_APP_KEY || "38200674fe05ccd2408e4b0ce5edf3d6"; const RAPIDAPI_KEY = process.env.RAPIDAPI_KEY || "760bddfc74mshf9dbbfbd051ab7cp143a85jsnf5013e4cc432"; const JOOBLE_API_KEY = process.env.JOOBLE_API_KEY || "2c2da801-a922-4b85-bf5a-c0e2dcfe095d"; // Top 15 Query Map for Target Specialties const TOP_15_QUERY_MAP = { "Paid Media Coordinator": "Paid Media PPC Social", "SEO Specialist": "SEO Content Strategy", "Digital Marketing Coordinator": "Digital Marketing Coordinator", "Social Media Specialist": "Social Media Specialist", "Marketing Analytics Associate": "Google Analytics GA4 Marketing", "Email Marketing Coordinator": "Email Marketing Klaviyo CRM", "Growth Marketing Specialist": "Growth Marketing", "E-commerce Marketing Assistant": "Ecommerce Marketing", "Brand Marketing Associate": "Brand Marketing", "Performance Marketing Specialist": "Performance Marketing", "Content Marketing Coordinator": "Content Marketing Writer", "Influencer Marketing Associate": "Influencer Marketing Affiliate", "Demand Generation Coordinator": "Demand Generation", "Digital Media Buyer": "Media Buyer Digital", "Copywriter & Content Specialist": "Copywriter Digital Content" }; // Geography Filter (Atlanta Metro + Tier 1 Hubs + Remote) const APPROVED_LOCATIONS = [ "atlanta", "alpharetta", "sandy springs", "marietta", "roswell", "dunwoody", "georgia", "ga", "remote", "united states", "us", "new york", "austin", "charlotte", "nashville", "chicago" ]; exports.searchJobs = onRequest({ cors: true }, async (req, res) => { res.set("Access-Control-Allow-Origin", "*"); res.set("Access-Control-Allow-Methods", "GET, OPTIONS"); if (req.method === "OPTIONS") { res.status(204).send(""); return; } const rawGoal = req.query.goal ? String(req.query.goal).trim() : "Digital Marketing Coordinator"; const targetLocation = req.query.location ? String(req.query.location).trim() : "Atlanta"; const searchQuery = TOP_15_QUERY_MAP[rawGoal] || rawGoal; try { const requests = []; // 1. Adzuna API Call const adzunaUrl = `https://api.adzuna.com/v1/api/jobs/us/search/1` + `?app_id=${encodeURIComponent(ADZUNA_APP_ID)}` + `&app_key=${encodeURIComponent(ADZUNA_APP_KEY)}` + `&results_per_page=12` + `&what=${encodeURIComponent(searchQuery)}` + `&where=${encodeURIComponent(targetLocation)}` + `&category=marketing-jobs`; requests.push(axios.get(adzunaUrl, { timeout: 5000 }).then(r => ({ provider: 'adzuna', data: r.data }))); // 2. Remotive API Call (Public Free Endpoint) const remotiveUrl = `https://remotive.com/api/remote-jobs?search=${encodeURIComponent(searchQuery)}&limit=8`; requests.push(axios.get(remotiveUrl, { timeout: 5000 }).then(r => ({ provider: 'remotive', data: r.data }))); // 3. Jooble API Call (Requires HTTP POST with JSON Body) if (JOOBLE_API_KEY) { const joobleUrl = `https://jooble.org/api/${JOOBLE_API_KEY}`; const jooblePromise = axios.post( joobleUrl, { keywords: searchQuery, location: targetLocation }, { headers: { "Content-Type": "application/json" }, timeout: 5000 } ).then(r => ({ provider: 'jooble', data: r.data })); requests.push(jooblePromise); } // 4. JSearch (RapidAPI) Call if (RAPIDAPI_KEY) { const jsearchUrl = `https://jsearch.p.rapidapi.com/search?query=${encodeURIComponent(searchQuery + " in " + targetLocation)}&num_pages=1`; const jsearchPromise = axios.get(jsearchUrl, { headers: { "X-RapidAPI-Key": RAPIDAPI_KEY, "X-RapidAPI-Host": "jsearch.p.rapidapi.com" }, timeout: 5000 }).then(r => ({ provider: 'jsearch', data: r.data })); requests.push(jsearchPromise); } // Fire all API requests in parallel safely const responses = await Promise.allSettled(requests); let combinedJobs = []; responses.forEach(result => { if (result.status !== "fulfilled") return; const { provider, data } = result.value; if (provider === 'adzuna' && data?.results) { const jobs = data.results.map(job => ({ title: (job.title || "Marketing Role").replace(/<\/?[^>]+(>|$)/g, ""), company: job.company?.display_name || "Hiring Company", location: job.location?.display_name || targetLocation, url: job.redirect_url || "#", source: "Adzuna Network" })); combinedJobs.push(...jobs); } if (provider === 'remotive' && data?.jobs) { const jobs = data.jobs.slice(0, 4).map(job => ({ title: job.title, company: job.company_name || "Tech Agency", location: "Remote (US)", url: job.url, source: "Remotive Tech" })); combinedJobs.push(...jobs); } if (provider === 'jooble' && data?.jobs) { const jobs = data.jobs.slice(0, 5).map(job => ({ title: (job.title || "Marketing Position").replace(/<\/?[^>]+(>|$)/g, ""), company: job.company || "Atlanta Employer", location: job.location || targetLocation, url: job.link || "#", source: "Jooble Engine" })); combinedJobs.push(...jobs); } if (provider === 'jsearch' && data?.data) { const jobs = data.data.slice(0, 4).map(job => ({ title: job.job_title, company: job.employer_name, location: `${job.job_city || targetLocation}, ${job.job_state || "GA"}`, url: job.job_apply_link || job.job_google_link, source: "JSearch Aggregator" })); combinedJobs.push(...jobs); } }); // Geographic Guardrail: Ensure roles match approved hubs/states const filteredJobs = combinedJobs.filter(job => { const loc = (job.location || "").toLowerCase(); return APPROVED_LOCATIONS.some(approved => loc.includes(approved)); }); res.status(200).json({ success: true, count: filteredJobs.length, selectedRole: rawGoal, jobs: filteredJobs.slice(0, 10) }); } catch (error) { logger.error("Error executing job aggregator function:", error.message); res.status(500).json({ success: false, error: "Failed to load dynamic job stream." }); } });