diff --git a/job_applier.mjs b/job_applier.mjs index d07c1f7..f0ba79d 100644 --- a/job_applier.mjs +++ b/job_applier.mjs @@ -32,7 +32,7 @@ import { APPLY_RUN_TIMEOUT_MS, PER_JOB_TIMEOUT_MS } from './lib/constants.mjs'; -const DEFAULT_ENABLED_APPLY_TYPES = ['easy_apply']; +const DEFAULT_ENABLED_APPLY_TYPES = ['easy_apply', 'wellfound']; const isPreview = process.argv.includes('--preview'); @@ -120,9 +120,12 @@ async function main() { byPlatform[platform].push(job); } - // Process each platform group + // Process each platform group — LinkedIn first, then Wellfound, then external + const platformOrder = ['linkedin', 'wellfound', 'external']; + const sortedPlatforms = Object.entries(byPlatform) + .sort((a, b) => (platformOrder.indexOf(a[0]) ?? 99) - (platformOrder.indexOf(b[0]) ?? 99)); let timedOut = false; - for (const [platform, platformJobs] of Object.entries(byPlatform)) { + for (const [platform, platformJobs] of sortedPlatforms) { if (timedOut) break; console.log(`\n--- ${platform.toUpperCase()} (${platformJobs.length} jobs) ---\n`); let browser; diff --git a/lib/apply/wellfound.mjs b/lib/apply/wellfound.mjs index 51c2e22..8687775 100644 --- a/lib/apply/wellfound.mjs +++ b/lib/apply/wellfound.mjs @@ -14,7 +14,18 @@ export async function apply(page, job, formFiller) { const meta = await page.evaluate(() => ({ title: document.querySelector('h1')?.textContent?.trim(), company: document.querySelector('[class*="company"] h2, [class*="startup"] h2, h2')?.textContent?.trim(), - })); + })).catch(() => ({})); + + // Check if listing is closed/unavailable + const closed = await page.evaluate(() => { + const text = (document.body.innerText || '').toLowerCase(); + return text.includes('no longer accepting') || text.includes('position has been filled') || + text.includes('this job is no longer') || text.includes('job not found'); + }).catch(() => false); + if (closed) { + console.log(` ℹ️ Job closed — no longer available`); + return { status: 'skipped_no_apply', meta }; + } const applyBtn = page.locator('a:has-text("Apply"), button:has-text("Apply Now"), a:has-text("Apply Now")').first(); if (await applyBtn.count() === 0) return { status: 'no_button', meta }; @@ -33,5 +44,20 @@ export async function apply(page, job, formFiller) { await submitBtn.click(); await page.waitForTimeout(SUBMIT_WAIT); - return { status: 'submitted', meta }; + // Verify submission — check for success indicators or form gone + const postSubmit = await page.evaluate(() => { + const text = (document.body.innerText || '').toLowerCase(); + return { + hasSuccess: text.includes('application submitted') || text.includes('successfully applied') || + text.includes('thank you') || text.includes('application received'), + hasForm: !!document.querySelector('form button[type="submit"]:not([disabled])'), + }; + }).catch(() => ({ hasSuccess: false, hasForm: false })); + + if (postSubmit.hasSuccess || !postSubmit.hasForm) { + return { status: 'submitted', meta }; + } + + console.log(` ⚠️ Submit clicked but form still present — may not have submitted`); + return { status: 'incomplete', meta }; } diff --git a/lib/wellfound.mjs b/lib/wellfound.mjs index 144bb69..32f4d58 100644 --- a/lib/wellfound.mjs +++ b/lib/wellfound.mjs @@ -69,6 +69,7 @@ export async function searchWellfound(page, search, { onPage } = {}) { results.push({ id: `wf_${slug}`, platform: 'wellfound', + apply_type: 'wellfound', track, title, company,