import fs from 'fs' const T = `databricks stripe datadog mongodb okta zscaler elastic cloudflare brex verkada oscar samsara fivetran gitlab affirm pinterest coinbase lyft flexport figma reddit twilio klaviyo robinhood asana instacart intercom nuro tripadvisor vercel gusto mixpanel duolingo tide faire monzo chime postman sofi carta newrelic discord launchdarkly zocdoc checkr peloton pagerduty dropbox gemini applovin pendo webflow anthropic squarespace wise coursera airtable udemy lattice upwork instabase netlify kayak tubi hellofresh gympass doximity impact ridgeline sagesure ripple anaplan adyen billtrust bitgo blend braze cultureamp justworks melio pushpay setpoint smartsheet taskrabbit`.split(/\s+/).filter(Boolean) // Public board APIs only, no auth. Greenhouse is fetched first and wins when the same // company token answers on more than one ATS (Klaviyo is live on both with 92 shared // titles, and the dedupe key cannot catch it because HTML and plain-text lengths differ). const LEVER = `spotify palantir wealthfront ro outreach zoox binance rover matchgroup hive coupa anchorage gopuff veeva tala dnb jumpcloud aledade pattern plume arcadia neon sonatype fly 15five`.split(/\s+/).filter(Boolean) const ASHBY = `openai notion ramp linear vanta cohere perplexity snowflake benchling watershed writer zapier sentry supabase clickhouse modal replit runway harvey plaid ashby posthog cursor elevenlabs pinecone weaviate temporal hightouch montecarlodata hex flock lemonade wealthsimple pleo semgrep hopper miro anyscale character decagon sierra abridge headway hinge-health nubank oyster skydio knock strava whoop circle consensys clickup influxdata render snyk expensify lightspeed substack poshmark amplitude fullstory gainsight iterable klaviyo airbyte sisense midjourney`.split(/\s+/).filter(Boolean) const strip = h => h.replace(/<[^>]+>/g, ' ') const all=[] const have=new Set() const chunk=(a,n)=>a.reduce((r,v,i)=>(i%n?r[r.length-1].push(v):r.push([v]),r),[]) async function greenhouse(t){ try{ const r=await fetch(`https://boards-api.greenhouse.io/v1/boards/${t}/jobs?content=true`) if(!r.ok) return [] const j=await r.json() return (j.jobs||[]).map(job=>({co:t,src:'greenhouse',title:job.title||'',content:job.content||''})) }catch{ return [] } } async function lever(t){ try{ const r=await fetch(`https://api.lever.co/v0/postings/${t}?mode=json`) if(!r.ok) return [] const j=await r.json() if(!Array.isArray(j)) return [] return j.map(p=>({co:t,src:'lever',title:p.text||'', content:[p.descriptionPlain,...(p.lists||[]).map(l=>l.text+' '+strip(l.content||'')),p.additionalPlain].filter(Boolean).join('\n')})) }catch{ return [] } } async function ashby(t){ try{ const r=await fetch(`https://api.ashbyhq.com/posting-api/job-board/${t}`) if(!r.ok) return [] const j=await r.json() return (j.jobs||[]).map(p=>({co:t,src:'ashby',title:p.title||'',content:p.descriptionPlain||strip(p.descriptionHtml||'')})) }catch{ return [] } } for(const [list,fn] of [[T,greenhouse],[LEVER,lever],[ASHBY,ashby]]){ const todo=[...new Set(list)].filter(t=>!have.has(t)) for(const c of chunk(todo,8)){ const res=await Promise.all(c.map(fn)) c.forEach((t,i)=>{ if(res[i].length){ have.add(t); all.push(...res[i]) } }) } } fs.writeFileSync(process.argv[2], JSON.stringify(all)) const bySrc=s=>new Set(all.filter(x=>x.src===s).map(x=>x.co)).size console.log('fetched', all.length, 'postings from', new Set(all.map(x=>x.co)).size, 'companies', `(greenhouse ${bySrc('greenhouse')}, lever ${bySrc('lever')}, ashby ${bySrc('ashby')})`)