ilml-plugin-linkedin 1.20.3 → 1.20.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -0
- package/dist/connect.mjs +35 -35
- package/dist/enrichProfile.mjs +3 -3
- package/dist/enrichProfiles.mjs +2 -2
- package/dist/messageBot.mjs +59 -59
- package/dist/run.mjs +12 -12
- package/dist/scout.mjs +1 -1
- package/dist/syncAll.mjs +68 -68
- package/dist/syncConnections.mjs +1 -1
- package/dist/verifyAbout.mjs +1 -1
- package/dist/version.mjs +1 -1
- package/dist/viewers.mjs +1 -1
- package/dist/visit.mjs +13 -13
- package/ilml-plugin.json +1 -1
- package/package.json +1 -1
package/dist/enrichProfile.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
var $t=Object.defineProperty;var X=(e,t)=>()=>(e&&(t=e(e=0)),t);var Dt=(e,t)=>{for(var n in t)$t(e,n,{get:t[n],enumerable:!0})};async function y(e){let t=Math.floor(Math.random()*2001),n=e+t;return new Promise(o=>setTimeout(o,n))}async function Oe(e){return await e.evaluate(()=>{let t=document.querySelectorAll("div.artdeco-modal--is-open");for(let o of t){let i=o.innerText||"",s=i.includes("Premium")||i.includes("premium")||i.includes("Upgrade")||i.includes("upgrade"),r=i.includes("Try for")||i.includes("free trial")||i.includes("/month")||i.includes("per month")||i.includes("Start my")||i.includes("Subscribe"),m=i.includes("Get hired faster")||i.includes("Get hired 2x");if(s||r||m){let f=o.querySelector('button[aria-label="Dismiss"]')||o.querySelector("button.artdeco-modal__dismiss")||o.querySelector("button[data-test-modal-close-btn]");if(f)return f.click(),{dismissed:!0,matched:i.substring(0,80)};let $=o.querySelectorAll("button");for(let c of $){let k=c.innerText?.trim().toLowerCase()||"",w=c.getAttribute("aria-label")?.toLowerCase()||"";if(k==="not now"||k==="no thanks"||k==="dismiss"||w.includes("dismiss"))return c.click(),{dismissed:!0,matched:i.substring(0,80)}}}}let n=document.querySelector(".premium-upsell-link")||document.querySelector("[data-test-premium-upsell]")||document.querySelector(".premium-hub-upsell");if(n){let o=n.closest('[class*="modal"]')?.querySelector('button[aria-label="Dismiss"]')||n.closest('[class*="banner"]')?.querySelector('button[aria-label="Close"]');if(o)return o.click(),{dismissed:!0,matched:"premium-banner"}}return!1})}var me=X(()=>{});import{getPluginConfig as Lt}from"@ilivemylife/graph-sdk";var Tt,fn,O,mn,pn,qe=X(async()=>{Tt=await Lt();for(let[e,t]of Object.entries(Tt))process.env[e]===void 0&&(process.env[e]=t);fn=process.env.LINKEDIN_NAME,O=Object.freeze({DRAFT:"draft",CONFIRMED:"confirmed",REJECTED:"rejected",NEEDS_REVIEW:"needs_review",SENT:"sent"}),mn=Object.freeze(new Set([O.DRAFT,O.CONFIRMED,O.NEEDS_REVIEW])),pn=Object.freeze(new Set([O.DRAFT,O.CONFIRMED,O.REJECTED,O.NEEDS_REVIEW]))});import"dotenv/config";import*as p from"fs";import*as b from"path";import{fileURLToPath as Rt}from"url";function We(){p.existsSync(_)||p.mkdirSync(_,{recursive:!0})}function Je(e,t){let n=JSON.stringify(t,null,2),o=e+".tmp";p.writeFileSync(o,n);for(let i=0;i<3;i++)try{p.renameSync(o,e);return}catch(s){if(i<2&&(s.code==="EPERM"||s.code==="EBUSY")){let r=Date.now();for(;Date.now()-r<200;);continue}throw s}}function Ke(e,t){if(!p.existsSync(e))return null;try{let n=JSON.parse(p.readFileSync(e,"utf-8"));try{p.copyFileSync(e,e+".backup")}catch{}return n}catch(n){console.error(`[!] ${t} is corrupted: ${n.message}`),console.error(` File: ${b.resolve(e)}`);let o=e+".backup";if(p.existsSync(o))try{let i=JSON.parse(p.readFileSync(o,"utf-8"));console.error(` Restored from ${o}`);try{p.copyFileSync(o,e)}catch{}return i}catch{console.error(" Backup also corrupted!")}console.error(` Starting with empty data. Old file preserved as ${e}.corrupted`);try{p.copyFileSync(e,e+".corrupted")}catch{}return null}}function Pt(){return new Date().toISOString().split("T")[0]}function q(e){if(!e)return null;let t=e.match(/\/in\/([^/?#]+)/);return t?t[1].toLowerCase():null}function Be(e){return typeof e=="string"?e.replace(/\s+/g," ").trim().toLowerCase():""}function Ye(e,t,n=null){if(!t||e[t])return t;let o=q(t);if(!o)return t;let i=null;for(let[s,r]of Object.entries(e)){if(q(r.profileUrl||s)===o)return s;!i&&Array.isArray(r.aliases)&&r.aliases.includes(o)&&(i=s)}if(i){let s=Be(n),r=Be(e[i].name);if(s&&r&&s===r)return i}return t}function Ot(){p.existsSync(he)||p.mkdirSync(he,{recursive:!0})}function Ge(e){let t=q(e);return t?b.join(he,`${t}.json`):null}function qt(e){let t=Ge(e);return t?Ke(t,`profile-history/${q(e)}.json`)||[]:[]}function Bt(e,t){let n=Ge(e);if(!n)return;Ot();let o=qt(e);o.unshift(t);try{Je(n,o)}catch(i){console.error(`[!] Failed to append profile-history for ${q(e)}: ${i.message}`)}}function He(e){return!!(e==null||Array.isArray(e)&&e.length===0||typeof e=="string"&&!e.trim())}function Ue(e){return Array.isArray(e)?[...e].map(t=>String(t).trim()).sort().join("||"):typeof e=="string"?e.replace(/\s+/g," ").trim():e}function Ht(e,t){if(!e)return[];let n=[];for(let o of jt){let i=e[o],s=t[o];He(i)||He(s)||Ue(i)!==Ue(s)&&n.push(o)}return n}function Ut(e){let t=new Set(["seenCount","sources","firstSeen","lastSeen","lastUpdated","encounters","jobIds","lastFullVisitAt","lastSnapshotAt","messageSent","connectionStatus","connectionDate","connectionMethod"]),n={};for(let[o,i]of Object.entries(e))t.has(o)||(n[o]=i);return n}function we(){return W||(We(),W=Ke(pe,"people.json")||{},W)}function ze(e){We(),W=e;try{Je(pe,e)}catch(t){console.error(`[!] Failed to save people.json: ${t.message}`),console.error(` Path: ${b.resolve(pe)}`)}}function ge(e,t={}){if(!e)return null;let n=we(),o=Pt(),i=new Date().toISOString(),s=Ye(n,e,t.name),r=n[s];if(r){let m=Ht(r,t);m.length>0&&(Bt(s,{capturedAt:i,previousLastUpdated:r.lastUpdated||null,changedFields:m,snapshot:Ut(r)}),r.lastSnapshotAt=i),r.seenCount=(r.seenCount||1)+1,r.lastSeen=o,r.lastUpdated=i,t.source&&!r.sources?.includes(t.source)&&(r.sources=r.sources||[],r.sources.push(t.source));for(let f of Ft)if(t[f]!=null){if(Array.isArray(t[f])&&t[f].length===0&&Array.isArray(r[f])&&r[f].length>0)continue;r[f]=t[f]}Array.isArray(t.availableSections)&&(r.lastFullVisitAt=i)}else n[s]={name:t.name||null,title:t.title||null,location:t.location||null,company:t.company||null,about:t.about||null,connectionDegree:t.connectionDegree||null,connectionsCount:t.connectionsCount||null,mutualConnections:t.mutualConnections||null,photoUrl:t.photoUrl||null,hasVerifiedBadge:t.hasVerifiedBadge||!1,currentCompany:t.currentCompany||null,currentSchool:t.currentSchool||null,connectionsLevel:t.connectionsLevel||null,mutualConnectionsCount:t.mutualConnectionsCount||null,followers:t.followers||null,openToWork:t.openToWork||!1,hiring:t.hiring||!1,topSkills:t.topSkills||null,availableSections:t.availableSections||null,experience:t.experience||null,featuredLinks:t.featuredLinks||null,_lastEnrichedAt:t._lastEnrichedAt||null,featured:t.featured||null,education:t.education||null,skillsFull:t.skillsFull||null,recommendations:t.recommendations||null,certifications:t.certifications||null,firstSeen:o,lastSeen:o,seenCount:1,sources:t.source?[t.source]:[],connectionStatus:null,requestedConnectionAt:null,connectionDate:null,connectionMethod:null,messageSent:null,jobIds:[],lastUpdated:i,lastSnapshotAt:null,lastFullVisitAt:Array.isArray(t.availableSections)?i:null};return ze(n),n[s]}function ye(e,t,n={}){if(n.dryRun||!e||!t)return;let o=q(t);if(!o)return;let i=we(),s=Ye(i,e),r=i[s];if(!r)return;let m=q(r.profileUrl||s);o!==m&&(Array.isArray(r.aliases)||(r.aliases=[]),r.aliases.includes(o)||(r.aliases.push(o),r.lastUpdated=new Date().toISOString(),ze(i)))}var Mt,Nt,_,pe,bn,Sn,kn,Cn,vn,he,Ve,xn,En,W,Ft,jt,be=X(async()=>{await qe();Mt=Rt(import.meta.url),Nt=b.dirname(b.dirname(Mt)),_=process.env.DATA_DIR?b.resolve(process.env.DATA_DIR,"collected-profiles"):b.join(Nt,"collected-profiles"),pe=b.join(_,"people.json"),bn=b.join(_,"jobs.json"),Sn=b.join(_,"quota.json"),kn=b.join(_,"conversations.json"),Cn=b.join(_,"sync-state.json"),vn=b.join(_,"application-questions.json"),he=b.join(_,"profile-history"),Ve=(e,t)=>{let n=parseInt(e,10);return Number.isInteger(n)&&n>=0?n:t},xn=Ve(process.env.CONNECT_MAX_DAILY,20),En=Ve(process.env.CONNECT_MAX_WEEKLY,100),W=null;Ft=["name","title","location","company","connectionDegree","connectionsCount","mutualConnections","photoUrl","hasVerifiedBadge","about","currentCompany","currentSchool","connectionsLevel","mutualConnectionsCount","followers","openToWork","hiring","topSkills","availableSections","experience","featuredLinks","_lastEnrichedAt","featured","education","skillsFull","recommendations","certifications"],jt=["name","title","location","currentCompany","currentSchool","connectionDegree","hasVerifiedBadge","openToWork","hiring","about","topSkills"]});var Qe={};Dt(Qe,{extractCertificationsFromDetails:()=>Yt,extractEducationFromDetails:()=>Jt,extractExperienceFromDetails:()=>Vt,extractFeaturedFromDetails:()=>Wt,extractRecommendationsFromDetails:()=>Gt,extractSkillsFromDetails:()=>Kt});async function Vt(e,t){let n=t.replace(/\/+$/,"")+"/details/experience/";try{await e.goto(n,{waitUntil:"domcontentloaded",timeout:6e4}),await y(3e3);let o=e.url();if(/\/(login|authwall|checkpoint)/i.test(o))throw new Error(`Session expired \u2014 bounced to ${o} when fetching /details/experience/`);for(let s=0;s<5;s++)await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await y(900);await y(1e3);let i=0;for(;i<5&&await e.evaluate(()=>{for(let r of document.querySelectorAll("button"))if(/^Load more$/i.test((r.textContent||"").trim()))return r.click(),!0;return!1});)i++,await y(1500),await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await y(700);return await e.evaluate(()=>{let s=document.querySelector("main");if(!s)return[];function r(c){let k=[];for(let w of c.querySelectorAll("div")){let g=Array.from(w.children).filter(E=>E.tagName==="DIV");if(g.length<3)continue;let S=g.filter(E=>(E.textContent||"").trim().length>50);S.length<3||(w.textContent||"").length<500||k.push({el:w,count:S.length,totalText:(w.textContent||"").length})}return k.sort((w,g)=>g.count-w.count||w.totalText-g.totalText),k[0]?.el}let m=r(s);if(!m)return[];let f=Array.from(m.children).filter(c=>c.tagName==="DIV").filter(c=>(c.textContent||"").trim().length>50);function $(c){let k=c[0]||null,w=null,g=null;if(c[1]){let d=c[1].split("\xB7").map(C=>C.trim());w=d[0]||null,d[1]&&(g=d[1])}let S=c.findIndex(d=>/(\d{4}|present)/i.test(d)&&/(-|–|—)/i.test(d)&&d.length<80),E=null,M=null;if(S>=0){let d=c[S].split("\xB7").map(C=>C.trim());E=d[0]||null,d[1]&&(M=d[1])}let N=null,P=-1;if(S>=0&&c[S+1]){let d=c[S+1],C=/^[>*\-•]|^>/.test(d),H=/https?:\/\//.test(d),U=/\d{4}/.test(d),v=/,/.test(d)||/\bArea\b|\bRegion\b|\bProvince\b|\bCountry\b|, [A-Z]{2}\b/.test(d);!C&&!H&&!U&&d.length<100&&v&&(N=d,P=S+1)}let ue=null,h=-1,F=c[c.length-1];if(F&&/and\s+\+\d+\s+skills?$/i.test(F)){h=c.length-1;let d=F.match(/^(.+?)\s+and\s+\+(\d+)\s+skills?$/i);d&&(ue={listed:d[1].split(",").map(C=>C.trim()),additional:parseInt(d[2],10)})}let j=new Set([0,1,S,P,h].filter(d=>d>=0)),D=c.filter((d,C)=>!j.has(C)),x=D.length>0?D.join(`
|
|
1
|
+
var $t=Object.defineProperty;var X=(e,t)=>()=>(e&&(t=e(e=0)),t);var Dt=(e,t)=>{for(var n in t)$t(e,n,{get:t[n],enumerable:!0})};async function y(e){let t=Math.floor(Math.random()*2001),n=e+t;return new Promise(o=>setTimeout(o,n))}async function Oe(e){return await e.evaluate(()=>{let t=document.querySelectorAll("div.artdeco-modal--is-open");for(let o of t){let i=o.innerText||"",s=i.includes("Premium")||i.includes("premium")||i.includes("Upgrade")||i.includes("upgrade"),r=i.includes("Try for")||i.includes("free trial")||i.includes("/month")||i.includes("per month")||i.includes("Start my")||i.includes("Subscribe"),m=i.includes("Get hired faster")||i.includes("Get hired 2x");if(s||r||m){let f=o.querySelector('button[aria-label="Dismiss"]')||o.querySelector("button.artdeco-modal__dismiss")||o.querySelector("button[data-test-modal-close-btn]");if(f)return f.click(),{dismissed:!0,matched:i.substring(0,80)};let $=o.querySelectorAll("button");for(let c of $){let k=c.innerText?.trim().toLowerCase()||"",w=c.getAttribute("aria-label")?.toLowerCase()||"";if(k==="not now"||k==="no thanks"||k==="dismiss"||w.includes("dismiss"))return c.click(),{dismissed:!0,matched:i.substring(0,80)}}}}let n=document.querySelector(".premium-upsell-link")||document.querySelector("[data-test-premium-upsell]")||document.querySelector(".premium-hub-upsell");if(n){let o=n.closest('[class*="modal"]')?.querySelector('button[aria-label="Dismiss"]')||n.closest('[class*="banner"]')?.querySelector('button[aria-label="Close"]');if(o)return o.click(),{dismissed:!0,matched:"premium-banner"}}return!1})}var me=X(()=>{});import{getPluginConfig as Lt}from"@ilivemylife/graph-sdk";var Tt,fn,O,mn,pn,qe=X(async()=>{Tt=await Lt();for(let[e,t]of Object.entries(Tt))process.env[e]===void 0&&(process.env[e]=t);fn=process.env.LINKEDIN_NAME,O=Object.freeze({DRAFT:"draft",CONFIRMED:"confirmed",REJECTED:"rejected",NEEDS_REVIEW:"needs_review",SENT:"sent"}),mn=Object.freeze(new Set([O.DRAFT,O.CONFIRMED,O.NEEDS_REVIEW])),pn=Object.freeze(new Set([O.DRAFT,O.CONFIRMED,O.REJECTED,O.NEEDS_REVIEW]))});import"dotenv/config";import*as p from"fs";import*as b from"path";import{fileURLToPath as Rt}from"url";function We(){p.existsSync(_)||p.mkdirSync(_,{recursive:!0})}function Je(e,t){let n=JSON.stringify(t,null,2),o=e+".tmp";p.writeFileSync(o,n);for(let i=0;i<3;i++)try{p.renameSync(o,e);return}catch(s){if(i<2&&(s.code==="EPERM"||s.code==="EBUSY")){let r=Date.now();for(;Date.now()-r<200;);continue}throw s}}function Ke(e,t){if(!p.existsSync(e))return null;try{let n=JSON.parse(p.readFileSync(e,"utf-8"));try{p.copyFileSync(e,e+".backup")}catch{}return n}catch(n){console.error(`[!] ${t} is corrupted: ${n.message}`),console.error(` File: ${b.resolve(e)}`);let o=e+".backup";if(p.existsSync(o))try{let i=JSON.parse(p.readFileSync(o,"utf-8"));console.error(` Restored from ${o}`);try{p.copyFileSync(o,e)}catch{}return i}catch{console.error(" Backup also corrupted!")}console.error(` Starting with empty data. Old file preserved as ${e}.corrupted`);try{p.copyFileSync(e,e+".corrupted")}catch{}return null}}function Nt(){return new Date().toISOString().split("T")[0]}function q(e){if(!e)return null;let t=e.match(/\/in\/([^/?#]+)/);return t?t[1].toLowerCase():null}function Be(e){return typeof e=="string"?e.replace(/\s+/g," ").trim().toLowerCase():""}function Ye(e,t,n=null){if(!t||e[t])return t;let o=q(t);if(!o)return t;let i=null;for(let[s,r]of Object.entries(e)){if(q(r.profileUrl||s)===o)return s;!i&&Array.isArray(r.aliases)&&r.aliases.includes(o)&&(i=s)}if(i){let s=Be(n),r=Be(e[i].name);if(s&&r&&s===r)return i}return t}function Ot(){p.existsSync(he)||p.mkdirSync(he,{recursive:!0})}function Ge(e){let t=q(e);return t?b.join(he,`${t}.json`):null}function qt(e){let t=Ge(e);return t?Ke(t,`profile-history/${q(e)}.json`)||[]:[]}function Bt(e,t){let n=Ge(e);if(!n)return;Ot();let o=qt(e);o.unshift(t);try{Je(n,o)}catch(i){console.error(`[!] Failed to append profile-history for ${q(e)}: ${i.message}`)}}function He(e){return!!(e==null||Array.isArray(e)&&e.length===0||typeof e=="string"&&!e.trim())}function Ue(e){return Array.isArray(e)?[...e].map(t=>String(t).trim()).sort().join("||"):typeof e=="string"?e.replace(/\s+/g," ").trim():e}function Ht(e,t){if(!e)return[];let n=[];for(let o of jt){let i=e[o],s=t[o];He(i)||He(s)||Ue(i)!==Ue(s)&&n.push(o)}return n}function Ut(e){let t=new Set(["seenCount","sources","firstSeen","lastSeen","lastUpdated","encounters","jobIds","lastFullVisitAt","lastSnapshotAt","messageSent","connectionStatus","connectionDate","connectionMethod"]),n={};for(let[o,i]of Object.entries(e))t.has(o)||(n[o]=i);return n}function we(){return W||(We(),W=Ke(pe,"people.json")||{},W)}function ze(e){We(),W=e;try{Je(pe,e)}catch(t){console.error(`[!] Failed to save people.json: ${t.message}`),console.error(` Path: ${b.resolve(pe)}`)}}function ge(e,t={}){if(!e)return null;let n=we(),o=Nt(),i=new Date().toISOString(),s=Ye(n,e,t.name),r=n[s];if(r){let m=Ht(r,t);m.length>0&&(Bt(s,{capturedAt:i,previousLastUpdated:r.lastUpdated||null,changedFields:m,snapshot:Ut(r)}),r.lastSnapshotAt=i),r.seenCount=(r.seenCount||1)+1,r.lastSeen=o,r.lastUpdated=i,t.source&&!r.sources?.includes(t.source)&&(r.sources=r.sources||[],r.sources.push(t.source));for(let f of Ft)if(t[f]!=null){if(Array.isArray(t[f])&&t[f].length===0&&Array.isArray(r[f])&&r[f].length>0)continue;r[f]=t[f]}Array.isArray(t.availableSections)&&(r.lastFullVisitAt=i)}else n[s]={name:t.name||null,title:t.title||null,location:t.location||null,company:t.company||null,about:t.about||null,connectionDegree:t.connectionDegree||null,connectionsCount:t.connectionsCount||null,mutualConnections:t.mutualConnections||null,photoUrl:t.photoUrl||null,hasVerifiedBadge:t.hasVerifiedBadge||!1,currentCompany:t.currentCompany||null,currentSchool:t.currentSchool||null,connectionsLevel:t.connectionsLevel||null,mutualConnectionsCount:t.mutualConnectionsCount||null,followers:t.followers||null,openToWork:t.openToWork||!1,hiring:t.hiring||!1,topSkills:t.topSkills||null,availableSections:t.availableSections||null,experience:t.experience||null,featuredLinks:t.featuredLinks||null,_lastEnrichedAt:t._lastEnrichedAt||null,featured:t.featured||null,education:t.education||null,skillsFull:t.skillsFull||null,recommendations:t.recommendations||null,certifications:t.certifications||null,firstSeen:o,lastSeen:o,seenCount:1,sources:t.source?[t.source]:[],connectionStatus:null,requestedConnectionAt:null,connectionDate:null,connectionMethod:null,messageSent:null,jobIds:[],lastUpdated:i,lastSnapshotAt:null,lastFullVisitAt:Array.isArray(t.availableSections)?i:null};return ze(n),n[s]}function ye(e,t,n={}){if(n.dryRun||!e||!t)return;let o=q(t);if(!o)return;let i=we(),s=Ye(i,e),r=i[s];if(!r)return;let m=q(r.profileUrl||s);o!==m&&(Array.isArray(r.aliases)||(r.aliases=[]),r.aliases.includes(o)||(r.aliases.push(o),r.lastUpdated=new Date().toISOString(),ze(i)))}var Mt,Pt,_,pe,bn,Sn,kn,Cn,vn,he,Ve,xn,En,W,Ft,jt,be=X(async()=>{await qe();Mt=Rt(import.meta.url),Pt=b.dirname(b.dirname(Mt)),_=process.env.DATA_DIR?b.resolve(process.env.DATA_DIR,"collected-profiles"):b.join(Pt,"collected-profiles"),pe=b.join(_,"people.json"),bn=b.join(_,"jobs.json"),Sn=b.join(_,"quota.json"),kn=b.join(_,"conversations.json"),Cn=b.join(_,"sync-state.json"),vn=b.join(_,"application-questions.json"),he=b.join(_,"profile-history"),Ve=(e,t)=>{let n=parseInt(e,10);return Number.isInteger(n)&&n>=0?n:t},xn=Ve(process.env.CONNECT_MAX_DAILY,20),En=Ve(process.env.CONNECT_MAX_WEEKLY,100),W=null;Ft=["name","title","location","company","connectionDegree","connectionsCount","mutualConnections","photoUrl","hasVerifiedBadge","about","currentCompany","currentSchool","connectionsLevel","mutualConnectionsCount","followers","openToWork","hiring","topSkills","availableSections","experience","featuredLinks","_lastEnrichedAt","featured","education","skillsFull","recommendations","certifications"],jt=["name","title","location","currentCompany","currentSchool","connectionDegree","hasVerifiedBadge","openToWork","hiring","about","topSkills"]});var Qe={};Dt(Qe,{extractCertificationsFromDetails:()=>Yt,extractEducationFromDetails:()=>Jt,extractExperienceFromDetails:()=>Vt,extractFeaturedFromDetails:()=>Wt,extractRecommendationsFromDetails:()=>Gt,extractSkillsFromDetails:()=>Kt});async function Vt(e,t){let n=t.replace(/\/+$/,"")+"/details/experience/";try{await e.goto(n,{waitUntil:"domcontentloaded",timeout:6e4}),await y(3e3);let o=e.url();if(/\/(login|authwall|checkpoint)/i.test(o))throw new Error(`Session expired \u2014 bounced to ${o} when fetching /details/experience/`);for(let s=0;s<5;s++)await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await y(900);await y(1e3);let i=0;for(;i<5&&await e.evaluate(()=>{for(let r of document.querySelectorAll("button"))if(/^Load more$/i.test((r.textContent||"").trim()))return r.click(),!0;return!1});)i++,await y(1500),await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await y(700);return await e.evaluate(()=>{let s=document.querySelector("main");if(!s)return[];function r(c){let k=[];for(let w of c.querySelectorAll("div")){let g=Array.from(w.children).filter(E=>E.tagName==="DIV");if(g.length<3)continue;let S=g.filter(E=>(E.textContent||"").trim().length>50);S.length<3||(w.textContent||"").length<500||k.push({el:w,count:S.length,totalText:(w.textContent||"").length})}return k.sort((w,g)=>g.count-w.count||w.totalText-g.totalText),k[0]?.el}let m=r(s);if(!m)return[];let f=Array.from(m.children).filter(c=>c.tagName==="DIV").filter(c=>(c.textContent||"").trim().length>50);function $(c){let k=c[0]||null,w=null,g=null;if(c[1]){let d=c[1].split("\xB7").map(C=>C.trim());w=d[0]||null,d[1]&&(g=d[1])}let S=c.findIndex(d=>/(\d{4}|present)/i.test(d)&&/(-|–|—)/i.test(d)&&d.length<80),E=null,M=null;if(S>=0){let d=c[S].split("\xB7").map(C=>C.trim());E=d[0]||null,d[1]&&(M=d[1])}let P=null,N=-1;if(S>=0&&c[S+1]){let d=c[S+1],C=/^[>*\-•]|^>/.test(d),H=/https?:\/\//.test(d),U=/\d{4}/.test(d),v=/,/.test(d)||/\bArea\b|\bRegion\b|\bProvince\b|\bCountry\b|, [A-Z]{2}\b/.test(d);!C&&!H&&!U&&d.length<100&&v&&(P=d,N=S+1)}let ue=null,h=-1,F=c[c.length-1];if(F&&/and\s+\+\d+\s+skills?$/i.test(F)){h=c.length-1;let d=F.match(/^(.+?)\s+and\s+\+(\d+)\s+skills?$/i);d&&(ue={listed:d[1].split(",").map(C=>C.trim()),additional:parseInt(d[2],10)})}let j=new Set([0,1,S,N,h].filter(d=>d>=0)),D=c.filter((d,C)=>!j.has(C)),x=D.length>0?D.join(`
|
|
2
2
|
|
|
3
|
-
`):null;return{title:k,company:w,employmentType:g,dates:E,duration:M,location:
|
|
3
|
+
`):null;return{title:k,company:w,employmentType:g,dates:E,duration:M,location:P,description:x,skills:ue,_raw:c}}return f.map(c=>{let w=(c.innerText||"").trim().split(`
|
|
4
4
|
`).map(g=>g.trim()).filter(g=>g&&g.length<5e3);return $(w)}).filter(c=>c.title)})}catch(o){if(/session expired|bounced to|authwall|checkpoint/i.test(o.message||""))throw o;return console.error(`extractExperienceFromDetails failed for ${t}: ${o.message?.slice(0,120)}`),[]}}async function J(e,t,n){let o=t.replace(/\/+$/,"")+`/details/${n}/`;await e.goto(o,{waitUntil:"domcontentloaded",timeout:6e4}),await y(3e3);let i=e.url();if(/\/(login|authwall|checkpoint)/i.test(i))throw new Error(`Session expired \u2014 bounced to ${i} when fetching /details/${n}/`);if(!i.toLowerCase().includes(`/details/${n.toLowerCase()}/`))throw new Error(`Section /details/${n}/ not available on profile (landed on ${i})`);for(let r=0;r<4;r++)await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await y(700);await y(800);let s=0;for(;s<5&&await e.evaluate(()=>{for(let m of document.querySelectorAll("button"))if(/^Load more$/i.test((m.textContent||"").trim()))return m.click(),!0;return!1});)s++,await y(1300),await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await y(600)}async function Y(e,t,n,o){try{return await o()}catch(i){let s=i.message||"";if(/session expired|bounced to|authwall|checkpoint/i.test(s))throw i;return/not available on profile/i.test(s)?(console.log(` (${t}: section not on profile \u2014 skipped)`),[]):(console.error(`${n} failed for ${e}: ${s.slice(0,120)}`),[])}}async function Wt(e,t){return Y(t,"featured","extractFeaturedFromDetails",async()=>(await J(e,t,"featured"),await e.evaluate(`(() => {
|
|
5
5
|
${K}
|
|
6
6
|
|
|
@@ -235,7 +235,7 @@ function findEntryContainer(root) {
|
|
|
235
235
|
candidates.sort((a, b) => b.count - a.count || b.totalText - a.totalText);
|
|
236
236
|
return candidates[0]?.el;
|
|
237
237
|
}
|
|
238
|
-
`});import"dotenv/config";import ln from"puppeteer";me();await be();async function zt(e,t){let n=e.url();if(n.includes("/in/"))return!1;if(n.includes("/login")||n.includes("/authwall")||n.includes("/checkpoint"))throw new Error("Session expired \u2014 redirected to login. Run: ilml linkedin login");console.log(` Off-track: ${n.slice(0,80)}`),console.log(" Navigating back to profile..."),await e.goto(t,{waitUntil:"domcontentloaded",timeout:6e4}),await y(3e3);let o=e.url();return o.includes("/in/")||console.log(` Recovery failed \u2014 still on: ${o.slice(0,80)}`),!0}async function Xe(e,t,n={}){let{extractExperience:o=!1,extractFeatured:i=!1,extractEducation:s=!1,extractSkills:r=!1,extractRecommendations:m=!1,extractCertifications:f=!1}=n;try{await e.goto(t,{waitUntil:"domcontentloaded",timeout:6e4}),await y(3e3),await Oe(e)&&(console.log(" Dismissed Premium overlay"),await y(1500),await zt(e,t));let c=0;for(let h=0;h<2;h++){let F=await e.evaluate(()=>document.body.scrollHeight);for(let D=1;D<=6;D++)await e.evaluate(x=>window.scrollTo(0,x),F*D/6),await y(900);let j=await e.evaluate(()=>document.body.scrollHeight);if(j===c)break;c=j}await y(800);let k=null;try{let h=e.url();h&&/\/in\/[^/?#]/.test(h)&&(k=h.split("?")[0].replace(/\/+$/,""))}catch{}let w=await e.evaluate(()=>{let h=new Set(["Highlights","About","Activity","Experience","Education","Skills","Recommendations","Languages","Interests","Volunteer experience","Featured","Honors & awards","Honors and awards","Projects","Publications","Patents","Certifications","Licenses & certifications","Courses","Test scores","Organizations"]),F=new Set(["Ad Options","Don\u2019t want to see this","0 notifications","Explore Premium profiles","You might like","People you may know","Suggested for you","More profiles for you","Promoted"]),j=l=>{let a=(l||"").trim().replace(/^[·•]\s*/,"");return/^(1st|2nd|3rd|she\/her|he\/him|they\/them|their\/them)$/i.test(a)},D={name:null,title:null,location:null,currentCompany:null,currentSchool:null,connectionDegree:null,hasVerifiedBadge:!1,photoUrl:null,connectionsLevel:null,mutualConnectionsCount:null,followers:null,openToWork:!1,hiring:!1,about:null,topSkills:null,availableSections:[]},x=document.querySelector("main");if(!x)return D;let d=[...Array.from(x.querySelectorAll("h1")),...Array.from(x.querySelectorAll("h2"))],C=Array.from(x.querySelectorAll("h2")),H=d.find(l=>{let a=l.textContent&&l.textContent.trim(),u=(a||"").replace(/\s*\(\d+\)$/,"").trim();return a&&a.length>1&&a.length<100&&!h.has(u)&&!F.has(u)}),U=H?H.textContent.trim():null,v=H?H.parentElement:null;for(;v&&v!==x&&!Array.from(v.children).filter(a=>a.tagName==="P").some(a=>{let u=a.textContent&&a.textContent.trim();return u&&u.length>5&&!j(u)});)v=v.parentElement;let Ee=null,Ie=null,Ae=null,de=null;if(v&&v!==x){let l=Array.from(v.children).filter(u=>u.tagName==="P").filter(u=>{let L=u.textContent&&u.textContent.trim();return L&&L.length>5&&!j(L)});if(l[0]&&(Ee=l[0].textContent.trim()),l[1]){let u=l[1].textContent.trim().split(/\s*[·•]\s*/);Ie=u[0]||null,u.length>1&&(Ae=u.slice(1).join(" \xB7 "))}let a=Array.from(v.children).filter(u=>u.tagName==="DIV");for(let u=a.length-1;u>=0;u--){let L=a[u].textContent&&a[u].textContent.trim();if(L&&!(U&&L.startsWith(U))&&(de=L.split(/[·•]/)[0].trim(),de))break}}let _e=null;if(v){let l=v.querySelectorAll("p, span, div");for(let a of l){let u=(a.textContent||"").trim().replace(/^[·•]\s*/,"");if(u==="1st"||u==="2nd"||u==="3rd"){_e=u;break}}}let Ct=!!x.querySelector('svg[data-test-icon="verified"], [aria-label*="Verified" i]'),$e=document.querySelector('main img[width="200"], button img[alt*="photo" i]'),vt=$e&&$e.src||null,Q=x.textContent||"",De=null,Le=Q.match(/(\d+\+?)\s+connections\b/i);Le&&(De=Le[1]+" connections");let Z=null,Te=Q.match(/(\d+)\s+mutual connection/i),Re=Q.match(/and\s+(\d+)\s+other mutual/i),xt=Q.match(/([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+and\s+([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+are\s+mutual/);Te?Z=parseInt(Te[1],10):Re?Z=2+parseInt(Re[1],10):xt&&(Z=2);let Me=null,Ne=null,Pe=C.find(l=>l.textContent&&l.textContent.trim()==="About");if(Pe){let l=Pe.parentElement;for(;l&&l.tagName!=="SECTION";)l=l.parentElement;if(l){let a=(l.textContent||"").trim();a=a.replace(/^About\s*/,"").trim();let u=a.match(/Top skills\s*(.+?)$/i);if(u){let fe=u[1].split(/\b(?:see (?:more|less)|show (?:more|less))\b/i)[0].trim().split(/\s*[·•]\s*/).map(_t=>_t.trim()).filter(Boolean);fe.length>0&&fe.length<10&&(Ne=fe)}a=a.split(/\n?…\s*more/i)[0].trim(),a=a.split(/\n?\.\.\.\s*more/i)[0].trim(),a=a.split(/\bTop skills\b/i)[0].trim(),a=a.split(/\b(?:see (?:more|less)|show (?:more|less))\b/i)[0].trim(),Me=a||null}}let Fe=null,je=C.find(l=>l.textContent&&l.textContent.trim()==="Activity");if(je){let l=je.parentElement;for(;l&&l.tagName!=="SECTION";)l=l.parentElement;if(l){let a=(l.textContent||"").slice(0,200).match(/([\d,]+)\s+followers/i);a&&(Fe=parseInt(a[1].replace(/,/g,""),10))}}let Et=[...new Set(C.map(l=>(l.textContent||"").trim().replace(/\s*\(\d+\)$/,"").trim()).filter(l=>l&&l.length>1&&l.length<60&&l!==U).filter(l=>h.has(l)))],V=document.body.textContent||"",It=/#OpenToWork\b/i.test(V)||/\bOpen to work\b/.test(V),At=/#Hiring\b/i.test(V)||/\bI'?m hiring\b/i.test(V)||/\bWe are hiring\b/i.test(V);return{name:U,title:Ee,location:de,currentCompany:Ie,currentSchool:Ae,connectionDegree:_e,hasVerifiedBadge:Ct,photoUrl:vt,connectionsLevel:De,mutualConnectionsCount:Z,followers:Fe,openToWork:It,hiring:At,about:Me,topSkills:Ne,availableSections:Et}});console.log(`Viewed: ${w.name} - ${w.title}`);let g=null,S=null,E=null,M=null,N=null,P=null;if(o||i||s||r||m||f){let h=await Promise.resolve().then(()=>(Ze(),Qe));o&&(g=await h.extractExperienceFromDetails(e,t),console.log(` + Experience: ${g.length} entries`)),i&&(S=await h.extractFeaturedFromDetails(e,t),console.log(` + Featured: ${S.length} entries`)),s&&(E=await h.extractEducationFromDetails(e,t),console.log(` + Education: ${E.length} entries`)),r&&(M=await h.extractSkillsFromDetails(e,t),console.log(` + Skills: ${M.length} entries`)),m&&(N=await h.extractRecommendationsFromDetails(e,t),console.log(` + Recommendations: ${N.length} entries`)),f&&(P=await h.extractCertificationsFromDetails(e,t),console.log(` + Certifications: ${P.length} entries`))}return{...w,profileUrl:t,resolvedUrl:k,...g!==null&&{experience:g},...S!==null&&{featured:S},...E!==null&&{education:E},...M!==null&&{skillsFull:M},...N!==null&&{recommendations:N},...P!==null&&{certifications:P}}}catch($){console.error(`Error viewing profile ${t}:`,$.message);try{await e.goto("about:blank",{timeout:1e4}),await y(1e3)}catch{}if(/session expired|bounced to|authwall|checkpoint|redirected to login/i.test($.message||""))throw $;return null}}await be();import I from"fs";import T from"path";var Qt="cookies.json";function et(){let e=process.env.ILML_SCOPE_DIR;return e?T.join(e,"plugins-state","linkedin","cookies.json"):Qt}function tt(){let e=et();if(!I.existsSync(e))throw new Error(`Cookies not found at ${e}. Run: ilml linkedin login`);let t;try{t=I.readFileSync(e,"utf-8")}catch(o){throw new Error(`Failed to read cookies at ${e}: ${o.message}. Run: ilml linkedin login`)}let n;try{n=JSON.parse(t)}catch{throw new Error(`Cookies file at ${e} is corrupted (invalid JSON). Run: ilml linkedin login`)}if(!Array.isArray(n)||n.length===0)throw new Error(`Cookies file at ${e} is empty or not an array. Run: ilml linkedin login`);return n}function nt(){return I.existsSync(et())}function Zt(){let e=process.env.ILML_SCOPE_DIR;return e?T.join(e,"plugins-state","linkedin"):"."}function ot(e){let t=String(e||"").replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,80);return/[a-zA-Z0-9]/.test(t)?t:"default"}function Xt(){let e=process.env.MY_LINKEDIN_URL,t=e&&e.match(/\/in\/([^/?#]+)/);return t&&t[1]?ot(t[1]):"default"}function it(e){let t=process.env.LINKEDIN_CHROME_PROFILE_DIR;if(t)return I.existsSync(t)||I.mkdirSync(t,{recursive:!0}),T.resolve(t);let n=ot(e||Xt()),o=T.join(Zt(),"chrome-profile",n);return I.existsSync(o)||I.mkdirSync(o,{recursive:!0}),T.resolve(o)}var rt=".ilml-seeded";function st(e){return!I.existsSync(T.join(e,rt))}function lt(e){try{I.writeFileSync(T.join(e,rt),new Date().toISOString())}catch{}}function at(e){let t=0;for(let n of["SingletonLock","SingletonCookie","SingletonSocket"])try{I.rmSync(T.join(e,n),{force:!0}),t++}catch{}return t}import Se from"fs";import en from"path";var tn={headless:!1,defaultViewport:null,protocolTimeout:3e5},z=new Set,ct=!1;async function ee(){let e=[...z].map(t=>{try{return Promise.resolve(t.close()).catch(()=>{})}catch{return Promise.resolve()}});z.clear(),await Promise.race([Promise.all(e),new Promise(t=>setTimeout(t,5e3))])}function nn(){if(ct)return;ct=!0;let e=t=>async()=>{await ee(),process.exit(t)};process.once("SIGINT",e(130)),process.once("SIGTERM",e(143)),process.once("SIGHUP",e(129)),process.once("uncaughtException",async t=>{await ee(),console.error(t&&t.stack||t),process.exit(1)}),process.once("unhandledRejection",async t=>{await ee(),console.error(t),process.exit(1)}),process.stdout.on("error",async t=>{t&&t.code==="EPIPE"&&(await ee(),process.exit(0))}),process.on("exit",()=>{for(let t of z)try{let n=t.process&&t.process();n&&n.kill("SIGKILL")}catch{}})}function ke(e){return en.join(e,".ilml-browser-session.json")}function mt(e,t={}){try{Se.writeFileSync(ke(e),JSON.stringify({ownerPid:process.pid,startedAt:Date.now(),...t}))}catch{}}function on(e,t){try{let n=t.wsEndpoint&&t.wsEndpoint();mt(e,n?{wsEndpoint:n}:{})}catch{}}function rn(e){let t=pt(e);t&&t.ownerPid===process.pid&&G(e)}function G(e){try{Se.rmSync(ke(e),{force:!0})}catch{}}function pt(e){try{return JSON.parse(Se.readFileSync(ke(e),"utf-8"))}catch{return null}}function ut(e){if(!e||e===process.pid)return!0;try{return process.kill(e,0),!0}catch(t){return!t||t.code!=="ESRCH"}}function dt(e,t,n){let o,i=new Promise(r=>{o=setTimeout(()=>r(n),t)}),s=Promise.resolve(e).then(r=>(clearTimeout(o),r),r=>{throw clearTimeout(o),r});return Promise.race([s,i])}async function ft(e,t,{probeTimeoutMs:n=4e3}={}){let o=pt(t);if(!o)return"free";if(!o.wsEndpoint)return o.ownerPid&&o.ownerPid!==process.pid&&ut(o.ownerPid)?"live":(G(t),"free");let i=Symbol("timeout"),s=e.connect({browserWSEndpoint:o.wsEndpoint,defaultViewport:null}).catch(()=>null),r=await dt(s,n,i);if(r===i)return s.then(f=>{if(f)try{f.disconnect()}catch{}}),"live";if(!r)return G(t),"free";if(ut(o.ownerPid)){try{r.disconnect()}catch{}return"live"}if(console.log(" (recovered an orphaned automation browser from a previous run \u2014 closing it)"),await dt(r.close().then(()=>!0).catch(()=>!1),n,!1))return G(t),"free";try{r.disconnect()}catch{}return"live"}function sn(e,t){e&&(nn(),z.add(e),e.on("disconnected",()=>{z.delete(e),t&&G(t)}))}async function ht(e,t={}){let n=it(),o={...tn,...t,userDataDir:n},i=`Could not open the LinkedIn automation Chrome profile at ${n}. Another LinkedIn automation command is already running (or its window is still open) \u2014 wait for it to finish or close that window, then retry.`;if(await ft(e,n)==="live")throw new Error(i);mt(n);let s;try{s=await e.launch(o)}catch{if(await ft(e,n)==="live")throw new Error(i);at(n);try{s=await e.launch(o)}catch(m){throw rn(n),new Error(`Could not open the LinkedIn automation Chrome profile at ${n}. If a LinkedIn automation window is already open, close it and retry. (Chrome: ${m.message})`)}}return sn(s,n),on(n,s),{browser:s,profileDir:n,needsSeed:st(n)}}async function wt(e,t){if(!t||!t.needsSeed)return!1;if(!nt())return console.warn(" \u26A0 No saved LinkedIn session found. If this command comes back empty or redirects to login, run: ilml linkedin login"),!1;try{return await e.setCookie(...tt()),lt(t.profileDir),console.log(" (seeded persistent profile from saved cookies \u2014 one-time)"),!0}catch{return!1}}function gt(e){return e?e.replace(/^https?:\/\/(www\.|m\.)?linkedin\.com/i,"https://linkedin.com").split("?")[0].split("#")[0].replace(/\/+$/,"").toLowerCase():""}function yt(e){return(e||"").replace(/ /g," ").replace(/\s+/g," ").trim().toLowerCase()}var A=process.argv.slice(2),an=A.includes("--help")||A.includes("-h"),R=A.find(e=>e.startsWith("http")),B=A.includes("--full"),ne=B||A.includes("--with-experience"),oe=B||A.includes("--with-featured"),ie=B||A.includes("--with-education"),re=B||A.includes("--with-skills"),se=B||A.includes("--with-recommendations"),le=B||A.includes("--with-certifications"),bt=[["experience",ne],["featured",oe],["education",ie],["skills",re],["recommendations",se],["certifications",le]],St=bt.filter(([,e])=>e).length,ve=1+St;function kt(){console.log(`
|
|
238
|
+
`});import"dotenv/config";import ln from"puppeteer";me();await be();async function zt(e,t){let n=e.url();if(n.includes("/in/"))return!1;if(n.includes("/login")||n.includes("/authwall")||n.includes("/checkpoint"))throw new Error("Session expired \u2014 redirected to login. Run: ilml linkedin login");console.log(` Off-track: ${n.slice(0,80)}`),console.log(" Navigating back to profile..."),await e.goto(t,{waitUntil:"domcontentloaded",timeout:6e4}),await y(3e3);let o=e.url();return o.includes("/in/")||console.log(` Recovery failed \u2014 still on: ${o.slice(0,80)}`),!0}async function Xe(e,t,n={}){let{extractExperience:o=!1,extractFeatured:i=!1,extractEducation:s=!1,extractSkills:r=!1,extractRecommendations:m=!1,extractCertifications:f=!1}=n;try{await e.goto(t,{waitUntil:"domcontentloaded",timeout:6e4}),await y(3e3),await Oe(e)&&(console.log(" Dismissed Premium overlay"),await y(1500),await zt(e,t));let c=0;for(let h=0;h<2;h++){let F=await e.evaluate(()=>document.body.scrollHeight);for(let D=1;D<=6;D++)await e.evaluate(x=>window.scrollTo(0,x),F*D/6),await y(900);let j=await e.evaluate(()=>document.body.scrollHeight);if(j===c)break;c=j}await y(800);let k=null;try{let h=e.url();h&&/\/in\/[^/?#]/.test(h)&&(k=h.split("?")[0].replace(/\/+$/,""))}catch{}let w=await e.evaluate(()=>{let h=new Set(["Highlights","About","Activity","Experience","Education","Skills","Recommendations","Languages","Interests","Volunteer experience","Featured","Honors & awards","Honors and awards","Projects","Publications","Patents","Certifications","Licenses & certifications","Courses","Test scores","Organizations"]),F=new Set(["Ad Options","Don\u2019t want to see this","0 notifications","Explore Premium profiles","You might like","People you may know","Suggested for you","More profiles for you","Promoted"]),j=l=>{let a=(l||"").trim().replace(/^[·•]\s*/,"");return/^(1st|2nd|3rd|she\/her|he\/him|they\/them|their\/them)$/i.test(a)},D={name:null,title:null,location:null,currentCompany:null,currentSchool:null,connectionDegree:null,hasVerifiedBadge:!1,photoUrl:null,connectionsLevel:null,mutualConnectionsCount:null,followers:null,openToWork:!1,hiring:!1,about:null,topSkills:null,availableSections:[]},x=document.querySelector("main");if(!x)return D;let d=[...Array.from(x.querySelectorAll("h1")),...Array.from(x.querySelectorAll("h2"))],C=Array.from(x.querySelectorAll("h2")),H=d.find(l=>{let a=l.textContent&&l.textContent.trim(),u=(a||"").replace(/\s*\(\d+\)$/,"").trim();return a&&a.length>1&&a.length<100&&!h.has(u)&&!F.has(u)}),U=H?H.textContent.trim():null,v=H?H.parentElement:null;for(;v&&v!==x&&!Array.from(v.children).filter(a=>a.tagName==="P").some(a=>{let u=a.textContent&&a.textContent.trim();return u&&u.length>5&&!j(u)});)v=v.parentElement;let Ee=null,Ie=null,Ae=null,de=null;if(v&&v!==x){let l=Array.from(v.children).filter(u=>u.tagName==="P").filter(u=>{let L=u.textContent&&u.textContent.trim();return L&&L.length>5&&!j(L)});if(l[0]&&(Ee=l[0].textContent.trim()),l[1]){let u=l[1].textContent.trim().split(/\s*[·•]\s*/);Ie=u[0]||null,u.length>1&&(Ae=u.slice(1).join(" \xB7 "))}let a=Array.from(v.children).filter(u=>u.tagName==="DIV");for(let u=a.length-1;u>=0;u--){let L=a[u].textContent&&a[u].textContent.trim();if(L&&!(U&&L.startsWith(U))&&(de=L.split(/[·•]/)[0].trim(),de))break}}let _e=null;if(v){let l=v.querySelectorAll("p, span, div");for(let a of l){let u=(a.textContent||"").trim().replace(/^[·•]\s*/,"");if(u==="1st"||u==="2nd"||u==="3rd"){_e=u;break}}}let Ct=!!x.querySelector('svg[data-test-icon="verified"], [aria-label*="Verified" i]'),$e=document.querySelector('main img[width="200"], button img[alt*="photo" i]'),vt=$e&&$e.src||null,Q=x.textContent||"",De=null,Le=Q.match(/(\d+\+?)\s+connections\b/i);Le&&(De=Le[1]+" connections");let Z=null,Te=Q.match(/(\d+)\s+mutual connection/i),Re=Q.match(/and\s+(\d+)\s+other mutual/i),xt=Q.match(/([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+and\s+([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+are\s+mutual/);Te?Z=parseInt(Te[1],10):Re?Z=2+parseInt(Re[1],10):xt&&(Z=2);let Me=null,Pe=null,Ne=C.find(l=>l.textContent&&l.textContent.trim()==="About");if(Ne){let l=Ne.parentElement;for(;l&&l.tagName!=="SECTION";)l=l.parentElement;if(l){let a=(l.textContent||"").trim();a=a.replace(/^About\s*/,"").trim();let u=a.match(/Top skills\s*(.+?)$/i);if(u){let fe=u[1].split(/\b(?:see (?:more|less)|show (?:more|less))\b/i)[0].trim().split(/\s*[·•]\s*/).map(_t=>_t.trim()).filter(Boolean);fe.length>0&&fe.length<10&&(Pe=fe)}a=a.split(/\n?…\s*more/i)[0].trim(),a=a.split(/\n?\.\.\.\s*more/i)[0].trim(),a=a.split(/\bTop skills\b/i)[0].trim(),a=a.split(/\b(?:see (?:more|less)|show (?:more|less))\b/i)[0].trim(),Me=a||null}}let Fe=null,je=C.find(l=>l.textContent&&l.textContent.trim()==="Activity");if(je){let l=je.parentElement;for(;l&&l.tagName!=="SECTION";)l=l.parentElement;if(l){let a=(l.textContent||"").slice(0,200).match(/([\d,]+)\s+followers/i);a&&(Fe=parseInt(a[1].replace(/,/g,""),10))}}let Et=[...new Set(C.map(l=>(l.textContent||"").trim().replace(/\s*\(\d+\)$/,"").trim()).filter(l=>l&&l.length>1&&l.length<60&&l!==U).filter(l=>h.has(l)))],V=document.body.textContent||"",It=/#OpenToWork\b/i.test(V)||/\bOpen to work\b/.test(V),At=/#Hiring\b/i.test(V)||/\bI'?m hiring\b/i.test(V)||/\bWe are hiring\b/i.test(V);return{name:U,title:Ee,location:de,currentCompany:Ie,currentSchool:Ae,connectionDegree:_e,hasVerifiedBadge:Ct,photoUrl:vt,connectionsLevel:De,mutualConnectionsCount:Z,followers:Fe,openToWork:It,hiring:At,about:Me,topSkills:Pe,availableSections:Et}});console.log(`Viewed: ${w.name} - ${w.title}`);let g=null,S=null,E=null,M=null,P=null,N=null;if(o||i||s||r||m||f){let h=await Promise.resolve().then(()=>(Ze(),Qe));o&&(g=await h.extractExperienceFromDetails(e,t),console.log(` + Experience: ${g.length} entries`)),i&&(S=await h.extractFeaturedFromDetails(e,t),console.log(` + Featured: ${S.length} entries`)),s&&(E=await h.extractEducationFromDetails(e,t),console.log(` + Education: ${E.length} entries`)),r&&(M=await h.extractSkillsFromDetails(e,t),console.log(` + Skills: ${M.length} entries`)),m&&(P=await h.extractRecommendationsFromDetails(e,t),console.log(` + Recommendations: ${P.length} entries`)),f&&(N=await h.extractCertificationsFromDetails(e,t),console.log(` + Certifications: ${N.length} entries`))}return{...w,profileUrl:t,resolvedUrl:k,...g!==null&&{experience:g},...S!==null&&{featured:S},...E!==null&&{education:E},...M!==null&&{skillsFull:M},...P!==null&&{recommendations:P},...N!==null&&{certifications:N}}}catch($){console.error(`Error viewing profile ${t}:`,$.message);try{await e.goto("about:blank",{timeout:1e4}),await y(1e3)}catch{}if(/session expired|bounced to|authwall|checkpoint|redirected to login/i.test($.message||""))throw $;return null}}await be();import I from"fs";import T from"path";var Qt="cookies.json";function et(){let e=process.env.ILML_SCOPE_DIR;return e?T.join(e,"plugins-state","linkedin","cookies.json"):Qt}function tt(){let e=et();if(!I.existsSync(e))throw new Error(`Cookies not found at ${e}. Run: ilml linkedin login`);let t;try{t=I.readFileSync(e,"utf-8")}catch(o){throw new Error(`Failed to read cookies at ${e}: ${o.message}. Run: ilml linkedin login`)}let n;try{n=JSON.parse(t)}catch{throw new Error(`Cookies file at ${e} is corrupted (invalid JSON). Run: ilml linkedin login`)}if(!Array.isArray(n)||n.length===0)throw new Error(`Cookies file at ${e} is empty or not an array. Run: ilml linkedin login`);return n}function nt(){return I.existsSync(et())}function Zt(){let e=process.env.ILML_SCOPE_DIR;return e?T.join(e,"plugins-state","linkedin"):"."}function ot(e){let t=String(e||"").replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,80);return/[a-zA-Z0-9]/.test(t)?t:"default"}function Xt(){let e=process.env.MY_LINKEDIN_URL,t=e&&e.match(/\/in\/([^/?#]+)/);return t&&t[1]?ot(t[1]):"default"}function it(e){let t=process.env.LINKEDIN_CHROME_PROFILE_DIR;if(t)return I.existsSync(t)||I.mkdirSync(t,{recursive:!0}),T.resolve(t);let n=ot(e||Xt()),o=T.join(Zt(),"chrome-profile",n);return I.existsSync(o)||I.mkdirSync(o,{recursive:!0}),T.resolve(o)}var rt=".ilml-seeded";function st(e){return!I.existsSync(T.join(e,rt))}function lt(e){try{I.writeFileSync(T.join(e,rt),new Date().toISOString())}catch{}}function at(e){let t=0;for(let n of["SingletonLock","SingletonCookie","SingletonSocket"])try{I.rmSync(T.join(e,n),{force:!0}),t++}catch{}return t}import Se from"fs";import en from"path";var tn={headless:!1,defaultViewport:null,protocolTimeout:3e5},z=new Set,ct=!1;async function ee(){let e=[...z].map(t=>{try{return Promise.resolve(t.close()).catch(()=>{})}catch{return Promise.resolve()}});z.clear(),await Promise.race([Promise.all(e),new Promise(t=>setTimeout(t,5e3))])}function nn(){if(ct)return;ct=!0;let e=t=>async()=>{await ee(),process.exit(t)};process.once("SIGINT",e(130)),process.once("SIGTERM",e(143)),process.once("SIGHUP",e(129)),process.once("uncaughtException",async t=>{await ee(),console.error(t&&t.stack||t),process.exit(1)}),process.once("unhandledRejection",async t=>{await ee(),console.error(t),process.exit(1)}),process.stdout.on("error",async t=>{t&&t.code==="EPIPE"&&(await ee(),process.exit(0))}),process.on("exit",()=>{for(let t of z)try{let n=t.process&&t.process();n&&n.kill("SIGKILL")}catch{}})}function ke(e){return en.join(e,".ilml-browser-session.json")}function mt(e,t={}){try{Se.writeFileSync(ke(e),JSON.stringify({ownerPid:process.pid,startedAt:Date.now(),...t}))}catch{}}function on(e,t){try{let n=t.wsEndpoint&&t.wsEndpoint();mt(e,n?{wsEndpoint:n}:{})}catch{}}function rn(e){let t=pt(e);t&&t.ownerPid===process.pid&&G(e)}function G(e){try{Se.rmSync(ke(e),{force:!0})}catch{}}function pt(e){try{return JSON.parse(Se.readFileSync(ke(e),"utf-8"))}catch{return null}}function ut(e){if(!e||e===process.pid)return!0;try{return process.kill(e,0),!0}catch(t){return!t||t.code!=="ESRCH"}}function dt(e,t,n){let o,i=new Promise(r=>{o=setTimeout(()=>r(n),t)}),s=Promise.resolve(e).then(r=>(clearTimeout(o),r),r=>{throw clearTimeout(o),r});return Promise.race([s,i])}async function ft(e,t,{probeTimeoutMs:n=4e3}={}){let o=pt(t);if(!o)return"free";if(!o.wsEndpoint)return o.ownerPid&&o.ownerPid!==process.pid&&ut(o.ownerPid)?"live":(G(t),"free");let i=Symbol("timeout"),s=e.connect({browserWSEndpoint:o.wsEndpoint,defaultViewport:null}).catch(()=>null),r=await dt(s,n,i);if(r===i)return s.then(f=>{if(f)try{f.disconnect()}catch{}}),"live";if(!r)return G(t),"free";if(ut(o.ownerPid)){try{r.disconnect()}catch{}return"live"}if(console.log(" (recovered an orphaned automation browser from a previous run \u2014 closing it)"),await dt(r.close().then(()=>!0).catch(()=>!1),n,!1))return G(t),"free";try{r.disconnect()}catch{}return"live"}function sn(e,t){e&&(nn(),z.add(e),e.on("disconnected",()=>{z.delete(e),t&&G(t)}))}async function ht(e,t={}){let n=it(),o={...tn,...t,userDataDir:n},i=`Could not open the LinkedIn automation Chrome profile at ${n}. Another LinkedIn automation command is already running (or its window is still open) \u2014 wait for it to finish or close that window, then retry.`;if(await ft(e,n)==="live")throw new Error(i);mt(n);let s;try{s=await e.launch(o)}catch{if(await ft(e,n)==="live")throw new Error(i);at(n);try{s=await e.launch(o)}catch(m){throw rn(n),new Error(`Could not open the LinkedIn automation Chrome profile at ${n}. If a LinkedIn automation window is already open, close it and retry. (Chrome: ${m.message})`)}}return sn(s,n),on(n,s),{browser:s,profileDir:n,needsSeed:st(n)}}async function wt(e,t){if(!t||!t.needsSeed)return!1;if(!nt())return console.warn(" \u26A0 No saved LinkedIn session found. If this command comes back empty or redirects to login, run: ilml linkedin login"),!1;try{return await e.setCookie(...tt()),lt(t.profileDir),console.log(" (seeded persistent profile from saved cookies \u2014 one-time)"),!0}catch{return!1}}function gt(e){return e?e.replace(/^https?:\/\/(www\.|m\.)?linkedin\.com/i,"https://linkedin.com").split("?")[0].split("#")[0].replace(/\/+$/,"").toLowerCase():""}function yt(e){return(e||"").replace(/ /g," ").replace(/\s+/g," ").trim().toLowerCase()}var A=process.argv.slice(2),an=A.includes("--help")||A.includes("-h"),R=A.find(e=>e.startsWith("http")),B=A.includes("--full"),ne=B||A.includes("--with-experience"),oe=B||A.includes("--with-featured"),ie=B||A.includes("--with-education"),re=B||A.includes("--with-skills"),se=B||A.includes("--with-recommendations"),le=B||A.includes("--with-certifications"),bt=[["experience",ne],["featured",oe],["education",ie],["skills",re],["recommendations",se],["certifications",le]],St=bt.filter(([,e])=>e).length,ve=1+St;function kt(){console.log(`
|
|
239
239
|
enrich-profile \u2014 visit ONE LinkedIn profile and save what we learn
|
|
240
240
|
|
|
241
241
|
USAGE
|
package/dist/enrichProfiles.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var _n=Object.defineProperty;var ae=(e,t)=>()=>(e&&(t=e(e=0)),t);var me=(e,t)=>{for(var n in t)_n(e,n,{get:t[n],enumerable:!0})};async function k(e){let t=Math.floor(Math.random()*2001),n=e+t;return new Promise(o=>setTimeout(o,n))}async function yt(e){return await e.evaluate(()=>{let t=document.querySelectorAll("div.artdeco-modal--is-open");for(let o of t){let r=o.innerText||"",s=r.includes("Premium")||r.includes("premium")||r.includes("Upgrade")||r.includes("upgrade"),i=r.includes("Try for")||r.includes("free trial")||r.includes("/month")||r.includes("per month")||r.includes("Start my")||r.includes("Subscribe"),l=r.includes("Get hired faster")||r.includes("Get hired 2x");if(s||i||l){let c=o.querySelector('button[aria-label="Dismiss"]')||o.querySelector("button.artdeco-modal__dismiss")||o.querySelector("button[data-test-modal-close-btn]");if(c)return c.click(),{dismissed:!0,matched:r.substring(0,80)};let d=o.querySelectorAll("button");for(let a of d){let m=a.innerText?.trim().toLowerCase()||"",f=a.getAttribute("aria-label")?.toLowerCase()||"";if(m==="not now"||m==="no thanks"||m==="dismiss"||f.includes("dismiss"))return a.click(),{dismissed:!0,matched:r.substring(0,80)}}}}let n=document.querySelector(".premium-upsell-link")||document.querySelector("[data-test-premium-upsell]")||document.querySelector(".premium-hub-upsell");if(n){let o=n.closest('[class*="modal"]')?.querySelector('button[aria-label="Dismiss"]')||n.closest('[class*="banner"]')?.querySelector('button[aria-label="Close"]');if(o)return o.click(),{dismissed:!0,matched:"premium-banner"}}return!1})}var pe=ae(()=>{});import{getPluginConfig as In}from"@ilivemylife/graph-sdk";var Tn,Rn,ee,Or,Dn,Re=ae(async()=>{Tn=await In();for(let[e,t]of Object.entries(Tn))process.env[e]===void 0&&(process.env[e]=t);Rn=process.env.LINKEDIN_NAME,ee=Object.freeze({DRAFT:"draft",CONFIRMED:"confirmed",REJECTED:"rejected",NEEDS_REVIEW:"needs_review",SENT:"sent"}),Or=Object.freeze(new Set([ee.DRAFT,ee.CONFIRMED,ee.NEEDS_REVIEW])),Dn=Object.freeze(new Set([ee.DRAFT,ee.CONFIRMED,ee.REJECTED,ee.NEEDS_REVIEW]))});import"dotenv/config";import*as C from"fs";import*as A from"path";import{fileURLToPath as Jn}from"url";function Bt(){fe=null,Yn=null,Kn=null,ue=null,zn=null,Qn=null}function Le(){C.existsSync(U)||C.mkdirSync(U,{recursive:!0})}function Fe(e,t){let n=JSON.stringify(t,null,2),o=e+".tmp";C.writeFileSync(o,n);for(let r=0;r<3;r++)try{C.renameSync(o,e);return}catch(s){if(r<2&&(s.code==="EPERM"||s.code==="EBUSY")){let i=Date.now();for(;Date.now()-i<200;);continue}throw s}}function Me(e,t){if(!C.existsSync(e))return null;try{let n=JSON.parse(C.readFileSync(e,"utf-8"));try{C.copyFileSync(e,e+".backup")}catch{}return n}catch(n){console.error(`[!] ${t} is corrupted: ${n.message}`),console.error(` File: ${A.resolve(e)}`);let o=e+".backup";if(C.existsSync(o))try{let r=JSON.parse(C.readFileSync(o,"utf-8"));console.error(` Restored from ${o}`);try{C.copyFileSync(o,e)}catch{}return r}catch{console.error(" Backup also corrupted!")}console.error(` Starting with empty data. Old file preserved as ${e}.corrupted`);try{C.copyFileSync(e,e+".corrupted")}catch{}return null}}function Zn(){return new Date().toISOString().split("T")[0]}function te(e){if(!e)return null;let t=e.match(/\/in\/([^/?#]+)/);return t?t[1].toLowerCase():null}function Ft(e){return typeof e=="string"?e.replace(/\s+/g," ").trim().toLowerCase():""}function Vt(e,t,n=null){if(!t||e[t])return t;let o=te(t);if(!o)return t;let r=null;for(let[s,i]of Object.entries(e)){if(te(i.profileUrl||s)===o)return s;!r&&Array.isArray(i.aliases)&&i.aliases.includes(o)&&(r=s)}if(r){let s=Ft(n),i=Ft(e[r].name);if(s&&i&&s===i)return r}return t}function to(){C.existsSync(Ne)||C.mkdirSync(Ne,{recursive:!0})}function Ht(e){let t=te(e);return t?A.join(Ne,`${t}.json`):null}function no(e){let t=Ht(e);return t?Me(t,`profile-history/${te(e)}.json`)||[]:[]}function oo(e,t){let n=Ht(e);if(!n)return;to();let o=no(e);o.unshift(t);try{Fe(n,o)}catch(r){console.error(`[!] Failed to append profile-history for ${te(e)}: ${r.message}`)}}function Mt(e){return!!(e==null||Array.isArray(e)&&e.length===0||typeof e=="string"&&!e.trim())}function Pt(e){return Array.isArray(e)?[...e].map(t=>String(t).trim()).sort().join("||"):typeof e=="string"?e.replace(/\s+/g," ").trim():e}function ro(e,t){if(!e)return[];let n=[];for(let o of eo){let r=e[o],s=t[o];Mt(r)||Mt(s)||Pt(r)!==Pt(s)&&n.push(o)}return n}function so(e){let t=new Set(["seenCount","sources","firstSeen","lastSeen","lastUpdated","encounters","jobIds","lastFullVisitAt","lastSnapshotAt","messageSent","connectionStatus","connectionDate","connectionMethod"]),n={};for(let[o,r]of Object.entries(e))t.has(o)||(n[o]=r);return n}function W(){return fe||(Le(),fe=Me(je,"people.json")||{},fe)}function Jt(e){Le(),fe=e;try{Fe(je,e)}catch(t){console.error(`[!] Failed to save people.json: ${t.message}`),console.error(` Path: ${A.resolve(je)}`)}}function Pe(){return ue||(Le(),ue=Me(qt,"conversations.json")||{},io(ue),ue)}function io(e){let t=0;for(let n of Object.values(e)){if(!(n.draftStatus!==void 0||n.draftPreparedAt!==void 0))continue;let r=(n.messages||[]).find(s=>s.status==="draft");r&&n.draftStatus&&n.draftStatus!=="pending"&&(r.status=n.draftStatus),delete n.draftStatus,delete n.draftPreparedAt,t++}if(t>0){console.log(` [migration] Moved draft state from conv to msg.status for ${t} conversations`);try{Fe(qt,e)}catch{}}}function qe(e,t={}){if(!e)return null;let n=W(),o=Zn(),r=new Date().toISOString(),s=Vt(n,e,t.name),i=n[s];if(i){let l=ro(i,t);l.length>0&&(oo(s,{capturedAt:r,previousLastUpdated:i.lastUpdated||null,changedFields:l,snapshot:so(i)}),i.lastSnapshotAt=r),i.seenCount=(i.seenCount||1)+1,i.lastSeen=o,i.lastUpdated=r,t.source&&!i.sources?.includes(t.source)&&(i.sources=i.sources||[],i.sources.push(t.source));for(let c of Xn)if(t[c]!=null){if(Array.isArray(t[c])&&t[c].length===0&&Array.isArray(i[c])&&i[c].length>0)continue;i[c]=t[c]}Array.isArray(t.availableSections)&&(i.lastFullVisitAt=r)}else n[s]={name:t.name||null,title:t.title||null,location:t.location||null,company:t.company||null,about:t.about||null,connectionDegree:t.connectionDegree||null,connectionsCount:t.connectionsCount||null,mutualConnections:t.mutualConnections||null,photoUrl:t.photoUrl||null,hasVerifiedBadge:t.hasVerifiedBadge||!1,currentCompany:t.currentCompany||null,currentSchool:t.currentSchool||null,connectionsLevel:t.connectionsLevel||null,mutualConnectionsCount:t.mutualConnectionsCount||null,followers:t.followers||null,openToWork:t.openToWork||!1,hiring:t.hiring||!1,topSkills:t.topSkills||null,availableSections:t.availableSections||null,experience:t.experience||null,featuredLinks:t.featuredLinks||null,_lastEnrichedAt:t._lastEnrichedAt||null,featured:t.featured||null,education:t.education||null,skillsFull:t.skillsFull||null,recommendations:t.recommendations||null,certifications:t.certifications||null,firstSeen:o,lastSeen:o,seenCount:1,sources:t.source?[t.source]:[],connectionStatus:null,requestedConnectionAt:null,connectionDate:null,connectionMethod:null,messageSent:null,jobIds:[],lastUpdated:r,lastSnapshotAt:null,lastFullVisitAt:Array.isArray(t.availableSections)?r:null};return Jt(n),n[s]}function Ue(e,t,n={}){if(n.dryRun||!e||!t)return;let o=te(t);if(!o)return;let r=W(),s=Vt(r,e),i=r[s];if(!i)return;let l=te(i.profileUrl||s);o!==l&&(Array.isArray(i.aliases)||(i.aliases=[]),i.aliases.includes(o)||(i.aliases.push(o),i.lastUpdated=new Date().toISOString(),Jt(r)))}var Wn,Gn,U,je,os,rs,qt,ss,is,Ne,Ut,ls,cs,fe,Yn,Kn,ue,zn,Qn,Xn,eo,ye=ae(async()=>{await Re();Wn=Jn(import.meta.url),Gn=A.dirname(A.dirname(Wn)),U=process.env.DATA_DIR?A.resolve(process.env.DATA_DIR,"collected-profiles"):A.join(Gn,"collected-profiles"),je=A.join(U,"people.json"),os=A.join(U,"jobs.json"),rs=A.join(U,"quota.json"),qt=A.join(U,"conversations.json"),ss=A.join(U,"sync-state.json"),is=A.join(U,"application-questions.json"),Ne=A.join(U,"profile-history"),Ut=(e,t)=>{let n=parseInt(e,10);return Number.isInteger(n)&&n>=0?n:t},ls=Ut(process.env.CONNECT_MAX_DAILY,20),cs=Ut(process.env.CONNECT_MAX_WEEKLY,100),fe=null,Yn=null,Kn=null,ue=null,zn=null,Qn=null;Xn=["name","title","location","company","connectionDegree","connectionsCount","mutualConnections","photoUrl","hasVerifiedBadge","about","currentCompany","currentSchool","connectionsLevel","mutualConnectionsCount","followers","openToWork","hiring","topSkills","availableSections","experience","featuredLinks","_lastEnrichedAt","featured","education","skillsFull","recommendations","certifications"],eo=["name","title","location","currentCompany","currentSchool","connectionDegree","hasVerifiedBadge","openToWork","hiring","about","topSkills"]});var Wt={};me(Wt,{extractCertificationsFromDetails:()=>fo,extractEducationFromDetails:()=>ao,extractExperienceFromDetails:()=>lo,extractFeaturedFromDetails:()=>co,extractRecommendationsFromDetails:()=>mo,extractSkillsFromDetails:()=>uo});async function lo(e,t){let n=t.replace(/\/+$/,"")+"/details/experience/";try{await e.goto(n,{waitUntil:"domcontentloaded",timeout:6e4}),await k(3e3);let o=e.url();if(/\/(login|authwall|checkpoint)/i.test(o))throw new Error(`Session expired \u2014 bounced to ${o} when fetching /details/experience/`);for(let s=0;s<5;s++)await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await k(900);await k(1e3);let r=0;for(;r<5&&await e.evaluate(()=>{for(let i of document.querySelectorAll("button"))if(/^Load more$/i.test((i.textContent||"").trim()))return i.click(),!0;return!1});)r++,await k(1500),await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await k(700);return await e.evaluate(()=>{let s=document.querySelector("main");if(!s)return[];function i(a){let m=[];for(let f of a.querySelectorAll("div")){let p=Array.from(f.children).filter(w=>w.tagName==="DIV");if(p.length<3)continue;let v=p.filter(w=>(w.textContent||"").trim().length>50);v.length<3||(f.textContent||"").length<500||m.push({el:f,count:v.length,totalText:(f.textContent||"").length})}return m.sort((f,p)=>p.count-f.count||f.totalText-p.totalText),m[0]?.el}let l=i(s);if(!l)return[];let c=Array.from(l.children).filter(a=>a.tagName==="DIV").filter(a=>(a.textContent||"").trim().length>50);function d(a){let m=a[0]||null,f=null,p=null;if(a[1]){let b=a[1].split("\xB7").map(_=>_.trim());f=b[0]||null,b[1]&&(p=b[1])}let v=a.findIndex(b=>/(\d{4}|present)/i.test(b)&&/(-|–|—)/i.test(b)&&b.length<80),w=null,E=null;if(v>=0){let b=a[v].split("\xB7").map(_=>_.trim());w=b[0]||null,b[1]&&(E=b[1])}let z=null,Q=-1;if(v>=0&&a[v+1]){let b=a[v+1],_=/^[>*\-•]|^>/.test(b),le=/https?:\/\//.test(b),ce=/\d{4}/.test(b),I=/,/.test(b)||/\bArea\b|\bRegion\b|\bProvince\b|\bCountry\b|, [A-Z]{2}\b/.test(b);!_&&!le&&!ce&&b.length<100&&I&&(z=b,Q=v+1)}let _e=null,x=-1,Z=a[a.length-1];if(Z&&/and\s+\+\d+\s+skills?$/i.test(Z)){x=a.length-1;let b=Z.match(/^(.+?)\s+and\s+\+(\d+)\s+skills?$/i);b&&(_e={listed:b[1].split(",").map(_=>_.trim()),additional:parseInt(b[2],10)})}let X=new Set([0,1,v,Q,x].filter(b=>b>=0)),V=a.filter((b,_)=>!X.has(_)),R=V.length>0?V.join(`
|
|
1
|
+
var _n=Object.defineProperty;var ae=(e,t)=>()=>(e&&(t=e(e=0)),t);var me=(e,t)=>{for(var n in t)_n(e,n,{get:t[n],enumerable:!0})};async function k(e){let t=Math.floor(Math.random()*2001),n=e+t;return new Promise(o=>setTimeout(o,n))}async function yt(e){return await e.evaluate(()=>{let t=document.querySelectorAll("div.artdeco-modal--is-open");for(let o of t){let r=o.innerText||"",s=r.includes("Premium")||r.includes("premium")||r.includes("Upgrade")||r.includes("upgrade"),i=r.includes("Try for")||r.includes("free trial")||r.includes("/month")||r.includes("per month")||r.includes("Start my")||r.includes("Subscribe"),l=r.includes("Get hired faster")||r.includes("Get hired 2x");if(s||i||l){let c=o.querySelector('button[aria-label="Dismiss"]')||o.querySelector("button.artdeco-modal__dismiss")||o.querySelector("button[data-test-modal-close-btn]");if(c)return c.click(),{dismissed:!0,matched:r.substring(0,80)};let d=o.querySelectorAll("button");for(let a of d){let m=a.innerText?.trim().toLowerCase()||"",f=a.getAttribute("aria-label")?.toLowerCase()||"";if(m==="not now"||m==="no thanks"||m==="dismiss"||f.includes("dismiss"))return a.click(),{dismissed:!0,matched:r.substring(0,80)}}}}let n=document.querySelector(".premium-upsell-link")||document.querySelector("[data-test-premium-upsell]")||document.querySelector(".premium-hub-upsell");if(n){let o=n.closest('[class*="modal"]')?.querySelector('button[aria-label="Dismiss"]')||n.closest('[class*="banner"]')?.querySelector('button[aria-label="Close"]');if(o)return o.click(),{dismissed:!0,matched:"premium-banner"}}return!1})}var pe=ae(()=>{});import{getPluginConfig as In}from"@ilivemylife/graph-sdk";var Tn,Rn,ee,Or,Dn,Re=ae(async()=>{Tn=await In();for(let[e,t]of Object.entries(Tn))process.env[e]===void 0&&(process.env[e]=t);Rn=process.env.LINKEDIN_NAME,ee=Object.freeze({DRAFT:"draft",CONFIRMED:"confirmed",REJECTED:"rejected",NEEDS_REVIEW:"needs_review",SENT:"sent"}),Or=Object.freeze(new Set([ee.DRAFT,ee.CONFIRMED,ee.NEEDS_REVIEW])),Dn=Object.freeze(new Set([ee.DRAFT,ee.CONFIRMED,ee.REJECTED,ee.NEEDS_REVIEW]))});import"dotenv/config";import*as C from"fs";import*as A from"path";import{fileURLToPath as Jn}from"url";function Bt(){fe=null,Yn=null,Kn=null,ue=null,zn=null,Qn=null}function Le(){C.existsSync(U)||C.mkdirSync(U,{recursive:!0})}function Fe(e,t){let n=JSON.stringify(t,null,2),o=e+".tmp";C.writeFileSync(o,n);for(let r=0;r<3;r++)try{C.renameSync(o,e);return}catch(s){if(r<2&&(s.code==="EPERM"||s.code==="EBUSY")){let i=Date.now();for(;Date.now()-i<200;);continue}throw s}}function Me(e,t){if(!C.existsSync(e))return null;try{let n=JSON.parse(C.readFileSync(e,"utf-8"));try{C.copyFileSync(e,e+".backup")}catch{}return n}catch(n){console.error(`[!] ${t} is corrupted: ${n.message}`),console.error(` File: ${A.resolve(e)}`);let o=e+".backup";if(C.existsSync(o))try{let r=JSON.parse(C.readFileSync(o,"utf-8"));console.error(` Restored from ${o}`);try{C.copyFileSync(o,e)}catch{}return r}catch{console.error(" Backup also corrupted!")}console.error(` Starting with empty data. Old file preserved as ${e}.corrupted`);try{C.copyFileSync(e,e+".corrupted")}catch{}return null}}function Zn(){return new Date().toISOString().split("T")[0]}function te(e){if(!e)return null;let t=e.match(/\/in\/([^/?#]+)/);return t?t[1].toLowerCase():null}function Ft(e){return typeof e=="string"?e.replace(/\s+/g," ").trim().toLowerCase():""}function Vt(e,t,n=null){if(!t||e[t])return t;let o=te(t);if(!o)return t;let r=null;for(let[s,i]of Object.entries(e)){if(te(i.profileUrl||s)===o)return s;!r&&Array.isArray(i.aliases)&&i.aliases.includes(o)&&(r=s)}if(r){let s=Ft(n),i=Ft(e[r].name);if(s&&i&&s===i)return r}return t}function to(){C.existsSync(Ne)||C.mkdirSync(Ne,{recursive:!0})}function Ht(e){let t=te(e);return t?A.join(Ne,`${t}.json`):null}function no(e){let t=Ht(e);return t?Me(t,`profile-history/${te(e)}.json`)||[]:[]}function oo(e,t){let n=Ht(e);if(!n)return;to();let o=no(e);o.unshift(t);try{Fe(n,o)}catch(r){console.error(`[!] Failed to append profile-history for ${te(e)}: ${r.message}`)}}function Mt(e){return!!(e==null||Array.isArray(e)&&e.length===0||typeof e=="string"&&!e.trim())}function Pt(e){return Array.isArray(e)?[...e].map(t=>String(t).trim()).sort().join("||"):typeof e=="string"?e.replace(/\s+/g," ").trim():e}function ro(e,t){if(!e)return[];let n=[];for(let o of eo){let r=e[o],s=t[o];Mt(r)||Mt(s)||Pt(r)!==Pt(s)&&n.push(o)}return n}function so(e){let t=new Set(["seenCount","sources","firstSeen","lastSeen","lastUpdated","encounters","jobIds","lastFullVisitAt","lastSnapshotAt","messageSent","connectionStatus","connectionDate","connectionMethod"]),n={};for(let[o,r]of Object.entries(e))t.has(o)||(n[o]=r);return n}function W(){return fe||(Le(),fe=Me(je,"people.json")||{},fe)}function Jt(e){Le(),fe=e;try{Fe(je,e)}catch(t){console.error(`[!] Failed to save people.json: ${t.message}`),console.error(` Path: ${A.resolve(je)}`)}}function Pe(){return ue||(Le(),ue=Me(qt,"conversations.json")||{},io(ue),ue)}function io(e){let t=0;for(let n of Object.values(e)){if(!(n.draftStatus!==void 0||n.draftPreparedAt!==void 0))continue;let r=(n.messages||[]).find(s=>s.status==="draft");r&&n.draftStatus&&n.draftStatus!=="pending"&&(r.status=n.draftStatus),delete n.draftStatus,delete n.draftPreparedAt,t++}if(t>0){console.log(` [migration] Moved draft state from conv to msg.status for ${t} conversations`);try{Fe(qt,e)}catch{}}}function qe(e,t={}){if(!e)return null;let n=W(),o=Zn(),r=new Date().toISOString(),s=Vt(n,e,t.name),i=n[s];if(i){let l=ro(i,t);l.length>0&&(oo(s,{capturedAt:r,previousLastUpdated:i.lastUpdated||null,changedFields:l,snapshot:so(i)}),i.lastSnapshotAt=r),i.seenCount=(i.seenCount||1)+1,i.lastSeen=o,i.lastUpdated=r,t.source&&!i.sources?.includes(t.source)&&(i.sources=i.sources||[],i.sources.push(t.source));for(let c of Xn)if(t[c]!=null){if(Array.isArray(t[c])&&t[c].length===0&&Array.isArray(i[c])&&i[c].length>0)continue;i[c]=t[c]}Array.isArray(t.availableSections)&&(i.lastFullVisitAt=r)}else n[s]={name:t.name||null,title:t.title||null,location:t.location||null,company:t.company||null,about:t.about||null,connectionDegree:t.connectionDegree||null,connectionsCount:t.connectionsCount||null,mutualConnections:t.mutualConnections||null,photoUrl:t.photoUrl||null,hasVerifiedBadge:t.hasVerifiedBadge||!1,currentCompany:t.currentCompany||null,currentSchool:t.currentSchool||null,connectionsLevel:t.connectionsLevel||null,mutualConnectionsCount:t.mutualConnectionsCount||null,followers:t.followers||null,openToWork:t.openToWork||!1,hiring:t.hiring||!1,topSkills:t.topSkills||null,availableSections:t.availableSections||null,experience:t.experience||null,featuredLinks:t.featuredLinks||null,_lastEnrichedAt:t._lastEnrichedAt||null,featured:t.featured||null,education:t.education||null,skillsFull:t.skillsFull||null,recommendations:t.recommendations||null,certifications:t.certifications||null,firstSeen:o,lastSeen:o,seenCount:1,sources:t.source?[t.source]:[],connectionStatus:null,requestedConnectionAt:null,connectionDate:null,connectionMethod:null,messageSent:null,jobIds:[],lastUpdated:r,lastSnapshotAt:null,lastFullVisitAt:Array.isArray(t.availableSections)?r:null};return Jt(n),n[s]}function Ue(e,t,n={}){if(n.dryRun||!e||!t)return;let o=te(t);if(!o)return;let r=W(),s=Vt(r,e),i=r[s];if(!i)return;let l=te(i.profileUrl||s);o!==l&&(Array.isArray(i.aliases)||(i.aliases=[]),i.aliases.includes(o)||(i.aliases.push(o),i.lastUpdated=new Date().toISOString(),Jt(r)))}var Wn,Gn,U,je,rs,ss,qt,is,ls,Ne,Ut,cs,as,fe,Yn,Kn,ue,zn,Qn,Xn,eo,ye=ae(async()=>{await Re();Wn=Jn(import.meta.url),Gn=A.dirname(A.dirname(Wn)),U=process.env.DATA_DIR?A.resolve(process.env.DATA_DIR,"collected-profiles"):A.join(Gn,"collected-profiles"),je=A.join(U,"people.json"),rs=A.join(U,"jobs.json"),ss=A.join(U,"quota.json"),qt=A.join(U,"conversations.json"),is=A.join(U,"sync-state.json"),ls=A.join(U,"application-questions.json"),Ne=A.join(U,"profile-history"),Ut=(e,t)=>{let n=parseInt(e,10);return Number.isInteger(n)&&n>=0?n:t},cs=Ut(process.env.CONNECT_MAX_DAILY,20),as=Ut(process.env.CONNECT_MAX_WEEKLY,100),fe=null,Yn=null,Kn=null,ue=null,zn=null,Qn=null;Xn=["name","title","location","company","connectionDegree","connectionsCount","mutualConnections","photoUrl","hasVerifiedBadge","about","currentCompany","currentSchool","connectionsLevel","mutualConnectionsCount","followers","openToWork","hiring","topSkills","availableSections","experience","featuredLinks","_lastEnrichedAt","featured","education","skillsFull","recommendations","certifications"],eo=["name","title","location","currentCompany","currentSchool","connectionDegree","hasVerifiedBadge","openToWork","hiring","about","topSkills"]});var Wt={};me(Wt,{extractCertificationsFromDetails:()=>fo,extractEducationFromDetails:()=>ao,extractExperienceFromDetails:()=>lo,extractFeaturedFromDetails:()=>co,extractRecommendationsFromDetails:()=>mo,extractSkillsFromDetails:()=>uo});async function lo(e,t){let n=t.replace(/\/+$/,"")+"/details/experience/";try{await e.goto(n,{waitUntil:"domcontentloaded",timeout:6e4}),await k(3e3);let o=e.url();if(/\/(login|authwall|checkpoint)/i.test(o))throw new Error(`Session expired \u2014 bounced to ${o} when fetching /details/experience/`);for(let s=0;s<5;s++)await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await k(900);await k(1e3);let r=0;for(;r<5&&await e.evaluate(()=>{for(let i of document.querySelectorAll("button"))if(/^Load more$/i.test((i.textContent||"").trim()))return i.click(),!0;return!1});)r++,await k(1500),await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await k(700);return await e.evaluate(()=>{let s=document.querySelector("main");if(!s)return[];function i(a){let m=[];for(let f of a.querySelectorAll("div")){let p=Array.from(f.children).filter(w=>w.tagName==="DIV");if(p.length<3)continue;let v=p.filter(w=>(w.textContent||"").trim().length>50);v.length<3||(f.textContent||"").length<500||m.push({el:f,count:v.length,totalText:(f.textContent||"").length})}return m.sort((f,p)=>p.count-f.count||f.totalText-p.totalText),m[0]?.el}let l=i(s);if(!l)return[];let c=Array.from(l.children).filter(a=>a.tagName==="DIV").filter(a=>(a.textContent||"").trim().length>50);function d(a){let m=a[0]||null,f=null,p=null;if(a[1]){let b=a[1].split("\xB7").map(_=>_.trim());f=b[0]||null,b[1]&&(p=b[1])}let v=a.findIndex(b=>/(\d{4}|present)/i.test(b)&&/(-|–|—)/i.test(b)&&b.length<80),w=null,E=null;if(v>=0){let b=a[v].split("\xB7").map(_=>_.trim());w=b[0]||null,b[1]&&(E=b[1])}let z=null,Q=-1;if(v>=0&&a[v+1]){let b=a[v+1],_=/^[>*\-•]|^>/.test(b),le=/https?:\/\//.test(b),ce=/\d{4}/.test(b),I=/,/.test(b)||/\bArea\b|\bRegion\b|\bProvince\b|\bCountry\b|, [A-Z]{2}\b/.test(b);!_&&!le&&!ce&&b.length<100&&I&&(z=b,Q=v+1)}let _e=null,x=-1,Z=a[a.length-1];if(Z&&/and\s+\+\d+\s+skills?$/i.test(Z)){x=a.length-1;let b=Z.match(/^(.+?)\s+and\s+\+(\d+)\s+skills?$/i);b&&(_e={listed:b[1].split(",").map(_=>_.trim()),additional:parseInt(b[2],10)})}let X=new Set([0,1,v,Q,x].filter(b=>b>=0)),V=a.filter((b,_)=>!X.has(_)),R=V.length>0?V.join(`
|
|
2
2
|
|
|
3
3
|
`):null;return{title:m,company:f,employmentType:p,dates:w,duration:E,location:z,description:R,skills:_e,_raw:a}}return c.map(a=>{let f=(a.innerText||"").trim().split(`
|
|
4
4
|
`).map(p=>p.trim()).filter(p=>p&&p.length<5e3);return d(f)}).filter(a=>a.title)})}catch(o){if(/session expired|bounced to|authwall|checkpoint/i.test(o.message||""))throw o;return console.error(`extractExperienceFromDetails failed for ${t}: ${o.message?.slice(0,120)}`),[]}}async function we(e,t,n){let o=t.replace(/\/+$/,"")+`/details/${n}/`;await e.goto(o,{waitUntil:"domcontentloaded",timeout:6e4}),await k(3e3);let r=e.url();if(/\/(login|authwall|checkpoint)/i.test(r))throw new Error(`Session expired \u2014 bounced to ${r} when fetching /details/${n}/`);if(!r.toLowerCase().includes(`/details/${n.toLowerCase()}/`))throw new Error(`Section /details/${n}/ not available on profile (landed on ${r})`);for(let i=0;i<4;i++)await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await k(700);await k(800);let s=0;for(;s<5&&await e.evaluate(()=>{for(let l of document.querySelectorAll("button"))if(/^Load more$/i.test((l.textContent||"").trim()))return l.click(),!0;return!1});)s++,await k(1300),await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await k(600)}async function Se(e,t,n,o){try{return await o()}catch(r){let s=r.message||"";if(/session expired|bounced to|authwall|checkpoint/i.test(s))throw r;return/not available on profile/i.test(s)?(console.log(` (${t}: section not on profile \u2014 skipped)`),[]):(console.error(`${n} failed for ${e}: ${s.slice(0,120)}`),[])}}async function co(e,t){return Se(t,"featured","extractFeaturedFromDetails",async()=>(await we(e,t,"featured"),await e.evaluate(`(() => {
|
|
@@ -235,7 +235,7 @@ function findEntryContainer(root) {
|
|
|
235
235
|
candidates.sort((a, b) => b.count - a.count || b.totalText - a.totalText);
|
|
236
236
|
return candidates[0]?.el;
|
|
237
237
|
}
|
|
238
|
-
`});var Kt=ae(()=>{});import"dotenv/config";import*as O from"fs";import*as D from"path";import{fileURLToPath as ho}from"url";function wo(){O.existsSync(oe)||O.mkdirSync(oe,{recursive:!0})}function bo(e,t){let n=JSON.stringify(t,null,2),o=e+".tmp";O.writeFileSync(o,n);for(let r=0;r<3;r++)try{O.renameSync(o,e);return}catch(s){if(r<2&&(s.code==="EPERM"||s.code==="EBUSY")){let i=Date.now();for(;Date.now()-i<200;);continue}throw s}}function So(e){try{if(O.existsSync(e))return JSON.parse(O.readFileSync(e,"utf-8"))}catch{}return null}function Qt(){vo=null,ko=null,Co=null,xo=null,ne=null}function Be(){return ne||(ne=So(zt)||{visits:[]},Array.isArray(ne.visits)||(ne.visits=[]),ne)}function Zt(e,t={}){if(!e)return;wo();let n=Be();n.visits.push({date:new Date().toISOString(),profileUrl:e,name:t.name||null,source:t.source||"manual"});let o=Date.now()-90*24*60*60*1e3;n.visits=n.visits.filter(r=>new Date(r.date).getTime()>o);try{bo(zt,n)}catch(r){console.error(`[!] Failed to save visit-log.json: ${r.message}`)}}function Xt(e){let t=Be();for(let n=t.visits.length-1;n>=0;n--)if(t.visits[n].profileUrl===e)return t.visits[n].date;return null}var go,yo,oe,Es,$s,zt,_s,Is,vo,ko,Co,xo,ne,Ve=ae(()=>{Kt();go=ho(import.meta.url),yo=D.dirname(D.dirname(go)),oe=process.env.DATA_DIR?D.resolve(process.env.DATA_DIR,"market-research"):D.join(yo,"market-research"),Es=D.join(oe,"scouted-jobs.json"),$s=D.join(oe,"discovered-people.json"),zt=D.join(oe,"visit-log.json"),_s=D.join(oe,"companies.json"),Is=D.join(oe,"job-decisions.json");vo=null,ko=null,Co=null,xo=null,ne=null});import Bn from"puppeteer";import{addExtra as Vn}from"puppeteer-extra";import Hn from"puppeteer-extra-plugin-stealth";pe();await Re();import P from"fs";import J from"path";var On="cookies.json";function wt(){let e=process.env.ILML_SCOPE_DIR;return e?J.join(e,"plugins-state","linkedin","cookies.json"):On}function bt(){let e=wt();if(!P.existsSync(e))throw new Error(`Cookies not found at ${e}. Run: ilml linkedin login`);let t;try{t=P.readFileSync(e,"utf-8")}catch(o){throw new Error(`Failed to read cookies at ${e}: ${o.message}. Run: ilml linkedin login`)}let n;try{n=JSON.parse(t)}catch{throw new Error(`Cookies file at ${e} is corrupted (invalid JSON). Run: ilml linkedin login`)}if(!Array.isArray(n)||n.length===0)throw new Error(`Cookies file at ${e} is empty or not an array. Run: ilml linkedin login`);return n}function St(){return P.existsSync(wt())}function jn(){let e=process.env.ILML_SCOPE_DIR;return e?J.join(e,"plugins-state","linkedin"):"."}function vt(e){let t=String(e||"").replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,80);return/[a-zA-Z0-9]/.test(t)?t:"default"}function Nn(){let e=process.env.MY_LINKEDIN_URL,t=e&&e.match(/\/in\/([^/?#]+)/);return t&&t[1]?vt(t[1]):"default"}function kt(e){let t=process.env.LINKEDIN_CHROME_PROFILE_DIR;if(t)return P.existsSync(t)||P.mkdirSync(t,{recursive:!0}),J.resolve(t);let n=vt(e||Nn()),o=J.join(jn(),"chrome-profile",n);return P.existsSync(o)||P.mkdirSync(o,{recursive:!0}),J.resolve(o)}var Ct=".ilml-seeded";function xt(e){return!P.existsSync(J.join(e,Ct))}function At(e){try{P.writeFileSync(J.join(e,Ct),new Date().toISOString())}catch{}}function Et(e){let t=0;for(let n of["SingletonLock","SingletonCookie","SingletonSocket"])try{P.rmSync(J.join(e,n),{force:!0}),t++}catch{}return t}import De from"fs";import Ln from"path";var Fn={headless:!1,defaultViewport:null,protocolTimeout:3e5},ge=new Set,$t=!1;async function xe(){let e=[...ge].map(t=>{try{return Promise.resolve(t.close()).catch(()=>{})}catch{return Promise.resolve()}});ge.clear(),await Promise.race([Promise.all(e),new Promise(t=>setTimeout(t,5e3))])}function Mn(){if($t)return;$t=!0;let e=t=>async()=>{await xe(),process.exit(t)};process.once("SIGINT",e(130)),process.once("SIGTERM",e(143)),process.once("SIGHUP",e(129)),process.once("uncaughtException",async t=>{await xe(),console.error(t&&t.stack||t),process.exit(1)}),process.once("unhandledRejection",async t=>{await xe(),console.error(t),process.exit(1)}),process.stdout.on("error",async t=>{t&&t.code==="EPIPE"&&(await xe(),process.exit(0))}),process.on("exit",()=>{for(let t of ge)try{let n=t.process&&t.process();n&&n.kill("SIGKILL")}catch{}})}function Oe(e){return Ln.join(e,".ilml-browser-session.json")}function Rt(e,t={}){try{De.writeFileSync(Oe(e),JSON.stringify({ownerPid:process.pid,startedAt:Date.now(),...t}))}catch{}}function Pn(e,t){try{let n=t.wsEndpoint&&t.wsEndpoint();Rt(e,n?{wsEndpoint:n}:{})}catch{}}function qn(e){let t=Dt(e);t&&t.ownerPid===process.pid&&he(e)}function he(e){try{De.rmSync(Oe(e),{force:!0})}catch{}}function Dt(e){try{return JSON.parse(De.readFileSync(Oe(e),"utf-8"))}catch{return null}}function _t(e){if(!e||e===process.pid)return!0;try{return process.kill(e,0),!0}catch(t){return!t||t.code!=="ESRCH"}}function It(e,t,n){let o,r=new Promise(i=>{o=setTimeout(()=>i(n),t)}),s=Promise.resolve(e).then(i=>(clearTimeout(o),i),i=>{throw clearTimeout(o),i});return Promise.race([s,r])}async function Tt(e,t,{probeTimeoutMs:n=4e3}={}){let o=Dt(t);if(!o)return"free";if(!o.wsEndpoint)return o.ownerPid&&o.ownerPid!==process.pid&&_t(o.ownerPid)?"live":(he(t),"free");let r=Symbol("timeout"),s=e.connect({browserWSEndpoint:o.wsEndpoint,defaultViewport:null}).catch(()=>null),i=await It(s,n,r);if(i===r)return s.then(c=>{if(c)try{c.disconnect()}catch{}}),"live";if(!i)return he(t),"free";if(_t(o.ownerPid)){try{i.disconnect()}catch{}return"live"}if(console.log(" (recovered an orphaned automation browser from a previous run \u2014 closing it)"),await It(i.close().then(()=>!0).catch(()=>!1),n,!1))return he(t),"free";try{i.disconnect()}catch{}return"live"}function Un(e,t){e&&(Mn(),ge.add(e),e.on("disconnected",()=>{ge.delete(e),t&&he(t)}))}async function Ot(e,t={}){let n=kt(),o={...Fn,...t,userDataDir:n},r=`Could not open the LinkedIn automation Chrome profile at ${n}. Another LinkedIn automation command is already running (or its window is still open) \u2014 wait for it to finish or close that window, then retry.`;if(await Tt(e,n)==="live")throw new Error(r);Rt(n);let s;try{s=await e.launch(o)}catch{if(await Tt(e,n)==="live")throw new Error(r);Et(n);try{s=await e.launch(o)}catch(l){throw qn(n),new Error(`Could not open the LinkedIn automation Chrome profile at ${n}. If a LinkedIn automation window is already open, close it and retry. (Chrome: ${l.message})`)}}return Un(s,n),Pn(n,s),{browser:s,profileDir:n,needsSeed:xt(n)}}async function jt(e,t){if(!t||!t.needsSeed)return!1;if(!St())return console.warn(" \u26A0 No saved LinkedIn session found. If this command comes back empty or redirects to login, run: ilml linkedin login"),!1;try{return await e.setCookie(...bt()),At(t.profileDir),console.log(" (seeded persistent profile from saved cookies \u2014 one-time)"),!0}catch{return!1}}var Nt=Vn(Bn);Nt.use(Hn());async function Lt(){let{browser:e,profileDir:t,needsSeed:n}=await Ot(Nt),o=await e.newPage();return await o.evaluateOnNewDocument(()=>{Object.defineProperty(navigator,"webdriver",{get:()=>{}})}),await jt(o,{profileDir:t,needsSeed:n}),console.log(" Browser launched (persistent profile)."),{browser:e,page:o}}pe();await ye();async function po(e,t){let n=e.url();if(n.includes("/in/"))return!1;if(n.includes("/login")||n.includes("/authwall")||n.includes("/checkpoint"))throw new Error("Session expired \u2014 redirected to login. Run: ilml linkedin login");console.log(` Off-track: ${n.slice(0,80)}`),console.log(" Navigating back to profile..."),await e.goto(t,{waitUntil:"domcontentloaded",timeout:6e4}),await k(3e3);let o=e.url();return o.includes("/in/")||console.log(` Recovery failed \u2014 still on: ${o.slice(0,80)}`),!0}async function Yt(e,t,n={}){let{extractExperience:o=!1,extractFeatured:r=!1,extractEducation:s=!1,extractSkills:i=!1,extractRecommendations:l=!1,extractCertifications:c=!1}=n;try{await e.goto(t,{waitUntil:"domcontentloaded",timeout:6e4}),await k(3e3),await yt(e)&&(console.log(" Dismissed Premium overlay"),await k(1500),await po(e,t));let a=0;for(let x=0;x<2;x++){let Z=await e.evaluate(()=>document.body.scrollHeight);for(let V=1;V<=6;V++)await e.evaluate(R=>window.scrollTo(0,R),Z*V/6),await k(900);let X=await e.evaluate(()=>document.body.scrollHeight);if(X===a)break;a=X}await k(800);let m=null;try{let x=e.url();x&&/\/in\/[^/?#]/.test(x)&&(m=x.split("?")[0].replace(/\/+$/,""))}catch{}let f=await e.evaluate(()=>{let x=new Set(["Highlights","About","Activity","Experience","Education","Skills","Recommendations","Languages","Interests","Volunteer experience","Featured","Honors & awards","Honors and awards","Projects","Publications","Patents","Certifications","Licenses & certifications","Courses","Test scores","Organizations"]),Z=new Set(["Ad Options","Don\u2019t want to see this","0 notifications","Explore Premium profiles","You might like","People you may know","Suggested for you","More profiles for you","Promoted"]),X=h=>{let g=(h||"").trim().replace(/^[·•]\s*/,"");return/^(1st|2nd|3rd|she\/her|he\/him|they\/them|their\/them)$/i.test(g)},V={name:null,title:null,location:null,currentCompany:null,currentSchool:null,connectionDegree:null,hasVerifiedBadge:!1,photoUrl:null,connectionsLevel:null,mutualConnectionsCount:null,followers:null,openToWork:!1,hiring:!1,about:null,topSkills:null,availableSections:[]},R=document.querySelector("main");if(!R)return V;let b=[...Array.from(R.querySelectorAll("h1")),...Array.from(R.querySelectorAll("h2"))],_=Array.from(R.querySelectorAll("h2")),le=b.find(h=>{let g=h.textContent&&h.textContent.trim(),y=(g||"").replace(/\s*\(\d+\)$/,"").trim();return g&&g.length>1&&g.length<100&&!x.has(y)&&!Z.has(y)}),ce=le?le.textContent.trim():null,I=le?le.parentElement:null;for(;I&&I!==R&&!Array.from(I.children).filter(g=>g.tagName==="P").some(g=>{let y=g.textContent&&g.textContent.trim();return y&&y.length>5&&!X(y)});)I=I.parentElement;let ot=null,rt=null,st=null,Ie=null;if(I&&I!==R){let h=Array.from(I.children).filter(y=>y.tagName==="P").filter(y=>{let H=y.textContent&&y.textContent.trim();return H&&H.length>5&&!X(H)});if(h[0]&&(ot=h[0].textContent.trim()),h[1]){let y=h[1].textContent.trim().split(/\s*[·•]\s*/);rt=y[0]||null,y.length>1&&(st=y.slice(1).join(" \xB7 "))}let g=Array.from(I.children).filter(y=>y.tagName==="DIV");for(let y=g.length-1;y>=0;y--){let H=g[y].textContent&&g[y].textContent.trim();if(H&&!(ce&&H.startsWith(ce))&&(Ie=H.split(/[·•]/)[0].trim(),Ie))break}}let it=null;if(I){let h=I.querySelectorAll("p, span, div");for(let g of h){let y=(g.textContent||"").trim().replace(/^[·•]\s*/,"");if(y==="1st"||y==="2nd"||y==="3rd"){it=y;break}}}let vn=!!R.querySelector('svg[data-test-icon="verified"], [aria-label*="Verified" i]'),lt=document.querySelector('main img[width="200"], button img[alt*="photo" i]'),kn=lt&<.src||null,ke=R.textContent||"",ct=null,at=ke.match(/(\d+\+?)\s+connections\b/i);at&&(ct=at[1]+" connections");let Ce=null,ut=ke.match(/(\d+)\s+mutual connection/i),ft=ke.match(/and\s+(\d+)\s+other mutual/i),Cn=ke.match(/([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+and\s+([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+are\s+mutual/);ut?Ce=parseInt(ut[1],10):ft?Ce=2+parseInt(ft[1],10):Cn&&(Ce=2);let dt=null,mt=null,pt=_.find(h=>h.textContent&&h.textContent.trim()==="About");if(pt){let h=pt.parentElement;for(;h&&h.tagName!=="SECTION";)h=h.parentElement;if(h){let g=(h.textContent||"").trim();g=g.replace(/^About\s*/,"").trim();let y=g.match(/Top skills\s*(.+?)$/i);if(y){let Te=y[1].split(/\b(?:see (?:more|less)|show (?:more|less))\b/i)[0].trim().split(/\s*[·•]\s*/).map($n=>$n.trim()).filter(Boolean);Te.length>0&&Te.length<10&&(mt=Te)}g=g.split(/\n?…\s*more/i)[0].trim(),g=g.split(/\n?\.\.\.\s*more/i)[0].trim(),g=g.split(/\bTop skills\b/i)[0].trim(),g=g.split(/\b(?:see (?:more|less)|show (?:more|less))\b/i)[0].trim(),dt=g||null}}let ht=null,gt=_.find(h=>h.textContent&&h.textContent.trim()==="Activity");if(gt){let h=gt.parentElement;for(;h&&h.tagName!=="SECTION";)h=h.parentElement;if(h){let g=(h.textContent||"").slice(0,200).match(/([\d,]+)\s+followers/i);g&&(ht=parseInt(g[1].replace(/,/g,""),10))}}let xn=[...new Set(_.map(h=>(h.textContent||"").trim().replace(/\s*\(\d+\)$/,"").trim()).filter(h=>h&&h.length>1&&h.length<60&&h!==ce).filter(h=>x.has(h)))],de=document.body.textContent||"",An=/#OpenToWork\b/i.test(de)||/\bOpen to work\b/.test(de),En=/#Hiring\b/i.test(de)||/\bI'?m hiring\b/i.test(de)||/\bWe are hiring\b/i.test(de);return{name:ce,title:ot,location:Ie,currentCompany:rt,currentSchool:st,connectionDegree:it,hasVerifiedBadge:vn,photoUrl:kn,connectionsLevel:ct,mutualConnectionsCount:Ce,followers:ht,openToWork:An,hiring:En,about:dt,topSkills:mt,availableSections:xn}});console.log(`Viewed: ${f.name} - ${f.title}`);let p=null,v=null,w=null,E=null,z=null,Q=null;if(o||r||s||i||l||c){let x=await Promise.resolve().then(()=>(Gt(),Wt));o&&(p=await x.extractExperienceFromDetails(e,t),console.log(` + Experience: ${p.length} entries`)),r&&(v=await x.extractFeaturedFromDetails(e,t),console.log(` + Featured: ${v.length} entries`)),s&&(w=await x.extractEducationFromDetails(e,t),console.log(` + Education: ${w.length} entries`)),i&&(E=await x.extractSkillsFromDetails(e,t),console.log(` + Skills: ${E.length} entries`)),l&&(z=await x.extractRecommendationsFromDetails(e,t),console.log(` + Recommendations: ${z.length} entries`)),c&&(Q=await x.extractCertificationsFromDetails(e,t),console.log(` + Certifications: ${Q.length} entries`))}return{...f,profileUrl:t,resolvedUrl:m,...p!==null&&{experience:p},...v!==null&&{featured:v},...w!==null&&{education:w},...E!==null&&{skillsFull:E},...z!==null&&{recommendations:z},...Q!==null&&{certifications:Q}}}catch(d){console.error(`Error viewing profile ${t}:`,d.message);try{await e.goto("about:blank",{timeout:1e4}),await k(1e3)}catch{}if(/session expired|bounced to|authwall|checkpoint|redirected to login/i.test(d.message||""))throw d;return null}}Ve();await ye();pe();async function en(e,t,n={}){let{maxVisits:o=50,delayBetween:r=4e3,skipRecentDays:s=7,verbose:i=!1,extractExperience:l=!1}=n,c={visited:0,skipped:0,errors:0},d=Date.now()-s*24*60*60*1e3;for(let a of t){if(c.visited>=o)break;if(!a.profileUrl)continue;let m=Xt(a.profileUrl);if(m&&new Date(m).getTime()>d){c.skipped++;continue}try{let f=await Yt(e,a.profileUrl,{extractExperience:l}),p=a.source||"visit";if(f){let w={...f,source:p};l&&Array.isArray(f.experience)&&f.experience.length>0&&(w._lastEnrichedAt=new Date().toISOString()),qe(a.profileUrl,w),f.resolvedUrl&&Ue(a.profileUrl,f.resolvedUrl)}Zt(a.profileUrl,{name:f?.name||a.name||null,source:p}),c.visited++,i?console.log(` [${c.visited}] ${f?.name||a.profileUrl} \u2014 ${f?.title?.slice(0,40)||"?"}`):c.visited%10===0&&console.log(` Visited: ${c.visited}`);let v=Math.random()*4e3;await k(r+v)}catch(f){c.errors++,i&&console.error(` Error visiting ${a.name||a.profileUrl}: ${f.message?.slice(0,60)}`);let p=(f.message||"").toLowerCase();if(p.includes("detached")||p.includes("session closed")||p.includes("target closed")||p.includes("session expired")||p.includes("bounced to")||p.includes("authwall")||p.includes("checkpoint")||p.includes("redirected to login")){console.log(" Fatal browser/session error \u2014 stopping visits");break}}}return c}await ye();import"dotenv/config";import*as j from"fs";import*as G from"path";import{fileURLToPath as To}from"url";import"dotenv/config";import{createGraphClient as Ao,resolveToken as Eo}from"@ilivemylife/graph-sdk";import{config as $o}from"dotenv";$o();var tn=Eo()||process.env.TOKEN;tn||(console.error(`
|
|
238
|
+
`});var Kt=ae(()=>{});import"dotenv/config";import*as O from"fs";import*as D from"path";import{fileURLToPath as ho}from"url";function wo(){O.existsSync(oe)||O.mkdirSync(oe,{recursive:!0})}function bo(e,t){let n=JSON.stringify(t,null,2),o=e+".tmp";O.writeFileSync(o,n);for(let r=0;r<3;r++)try{O.renameSync(o,e);return}catch(s){if(r<2&&(s.code==="EPERM"||s.code==="EBUSY")){let i=Date.now();for(;Date.now()-i<200;);continue}throw s}}function So(e){try{if(O.existsSync(e))return JSON.parse(O.readFileSync(e,"utf-8"))}catch{}return null}function Qt(){vo=null,ko=null,Co=null,xo=null,ne=null}function Be(){return ne||(ne=So(zt)||{visits:[]},Array.isArray(ne.visits)||(ne.visits=[]),ne)}function Zt(e,t={}){if(!e)return;wo();let n=Be();n.visits.push({date:new Date().toISOString(),profileUrl:e,name:t.name||null,source:t.source||"manual"});let o=Date.now()-90*24*60*60*1e3;n.visits=n.visits.filter(r=>new Date(r.date).getTime()>o);try{bo(zt,n)}catch(r){console.error(`[!] Failed to save visit-log.json: ${r.message}`)}}function Xt(e){let t=Be();for(let n=t.visits.length-1;n>=0;n--)if(t.visits[n].profileUrl===e)return t.visits[n].date;return null}var go,yo,oe,$s,_s,zt,Is,Ts,vo,ko,Co,xo,ne,Ve=ae(()=>{Kt();go=ho(import.meta.url),yo=D.dirname(D.dirname(go)),oe=process.env.DATA_DIR?D.resolve(process.env.DATA_DIR,"market-research"):D.join(yo,"market-research"),$s=D.join(oe,"scouted-jobs.json"),_s=D.join(oe,"discovered-people.json"),zt=D.join(oe,"visit-log.json"),Is=D.join(oe,"companies.json"),Ts=D.join(oe,"job-decisions.json");vo=null,ko=null,Co=null,xo=null,ne=null});import Bn from"puppeteer";import{addExtra as Vn}from"puppeteer-extra";import Hn from"puppeteer-extra-plugin-stealth";pe();await Re();import P from"fs";import J from"path";var On="cookies.json";function wt(){let e=process.env.ILML_SCOPE_DIR;return e?J.join(e,"plugins-state","linkedin","cookies.json"):On}function bt(){let e=wt();if(!P.existsSync(e))throw new Error(`Cookies not found at ${e}. Run: ilml linkedin login`);let t;try{t=P.readFileSync(e,"utf-8")}catch(o){throw new Error(`Failed to read cookies at ${e}: ${o.message}. Run: ilml linkedin login`)}let n;try{n=JSON.parse(t)}catch{throw new Error(`Cookies file at ${e} is corrupted (invalid JSON). Run: ilml linkedin login`)}if(!Array.isArray(n)||n.length===0)throw new Error(`Cookies file at ${e} is empty or not an array. Run: ilml linkedin login`);return n}function St(){return P.existsSync(wt())}function jn(){let e=process.env.ILML_SCOPE_DIR;return e?J.join(e,"plugins-state","linkedin"):"."}function vt(e){let t=String(e||"").replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,80);return/[a-zA-Z0-9]/.test(t)?t:"default"}function Nn(){let e=process.env.MY_LINKEDIN_URL,t=e&&e.match(/\/in\/([^/?#]+)/);return t&&t[1]?vt(t[1]):"default"}function kt(e){let t=process.env.LINKEDIN_CHROME_PROFILE_DIR;if(t)return P.existsSync(t)||P.mkdirSync(t,{recursive:!0}),J.resolve(t);let n=vt(e||Nn()),o=J.join(jn(),"chrome-profile",n);return P.existsSync(o)||P.mkdirSync(o,{recursive:!0}),J.resolve(o)}var Ct=".ilml-seeded";function xt(e){return!P.existsSync(J.join(e,Ct))}function At(e){try{P.writeFileSync(J.join(e,Ct),new Date().toISOString())}catch{}}function Et(e){let t=0;for(let n of["SingletonLock","SingletonCookie","SingletonSocket"])try{P.rmSync(J.join(e,n),{force:!0}),t++}catch{}return t}import De from"fs";import Ln from"path";var Fn={headless:!1,defaultViewport:null,protocolTimeout:3e5},ge=new Set,$t=!1;async function xe(){let e=[...ge].map(t=>{try{return Promise.resolve(t.close()).catch(()=>{})}catch{return Promise.resolve()}});ge.clear(),await Promise.race([Promise.all(e),new Promise(t=>setTimeout(t,5e3))])}function Mn(){if($t)return;$t=!0;let e=t=>async()=>{await xe(),process.exit(t)};process.once("SIGINT",e(130)),process.once("SIGTERM",e(143)),process.once("SIGHUP",e(129)),process.once("uncaughtException",async t=>{await xe(),console.error(t&&t.stack||t),process.exit(1)}),process.once("unhandledRejection",async t=>{await xe(),console.error(t),process.exit(1)}),process.stdout.on("error",async t=>{t&&t.code==="EPIPE"&&(await xe(),process.exit(0))}),process.on("exit",()=>{for(let t of ge)try{let n=t.process&&t.process();n&&n.kill("SIGKILL")}catch{}})}function Oe(e){return Ln.join(e,".ilml-browser-session.json")}function Rt(e,t={}){try{De.writeFileSync(Oe(e),JSON.stringify({ownerPid:process.pid,startedAt:Date.now(),...t}))}catch{}}function Pn(e,t){try{let n=t.wsEndpoint&&t.wsEndpoint();Rt(e,n?{wsEndpoint:n}:{})}catch{}}function qn(e){let t=Dt(e);t&&t.ownerPid===process.pid&&he(e)}function he(e){try{De.rmSync(Oe(e),{force:!0})}catch{}}function Dt(e){try{return JSON.parse(De.readFileSync(Oe(e),"utf-8"))}catch{return null}}function _t(e){if(!e||e===process.pid)return!0;try{return process.kill(e,0),!0}catch(t){return!t||t.code!=="ESRCH"}}function It(e,t,n){let o,r=new Promise(i=>{o=setTimeout(()=>i(n),t)}),s=Promise.resolve(e).then(i=>(clearTimeout(o),i),i=>{throw clearTimeout(o),i});return Promise.race([s,r])}async function Tt(e,t,{probeTimeoutMs:n=4e3}={}){let o=Dt(t);if(!o)return"free";if(!o.wsEndpoint)return o.ownerPid&&o.ownerPid!==process.pid&&_t(o.ownerPid)?"live":(he(t),"free");let r=Symbol("timeout"),s=e.connect({browserWSEndpoint:o.wsEndpoint,defaultViewport:null}).catch(()=>null),i=await It(s,n,r);if(i===r)return s.then(c=>{if(c)try{c.disconnect()}catch{}}),"live";if(!i)return he(t),"free";if(_t(o.ownerPid)){try{i.disconnect()}catch{}return"live"}if(console.log(" (recovered an orphaned automation browser from a previous run \u2014 closing it)"),await It(i.close().then(()=>!0).catch(()=>!1),n,!1))return he(t),"free";try{i.disconnect()}catch{}return"live"}function Un(e,t){e&&(Mn(),ge.add(e),e.on("disconnected",()=>{ge.delete(e),t&&he(t)}))}async function Ot(e,t={}){let n=kt(),o={...Fn,...t,userDataDir:n},r=`Could not open the LinkedIn automation Chrome profile at ${n}. Another LinkedIn automation command is already running (or its window is still open) \u2014 wait for it to finish or close that window, then retry.`;if(await Tt(e,n)==="live")throw new Error(r);Rt(n);let s;try{s=await e.launch(o)}catch{if(await Tt(e,n)==="live")throw new Error(r);Et(n);try{s=await e.launch(o)}catch(l){throw qn(n),new Error(`Could not open the LinkedIn automation Chrome profile at ${n}. If a LinkedIn automation window is already open, close it and retry. (Chrome: ${l.message})`)}}return Un(s,n),Pn(n,s),{browser:s,profileDir:n,needsSeed:xt(n)}}async function jt(e,t){if(!t||!t.needsSeed)return!1;if(!St())return console.warn(" \u26A0 No saved LinkedIn session found. If this command comes back empty or redirects to login, run: ilml linkedin login"),!1;try{return await e.setCookie(...bt()),At(t.profileDir),console.log(" (seeded persistent profile from saved cookies \u2014 one-time)"),!0}catch{return!1}}var Nt=Vn(Bn);Nt.use(Hn());async function Lt(){let{browser:e,profileDir:t,needsSeed:n}=await Ot(Nt),o=await e.newPage();return await o.evaluateOnNewDocument(()=>{Object.defineProperty(navigator,"webdriver",{get:()=>{}})}),await jt(o,{profileDir:t,needsSeed:n}),console.log(" Browser launched (persistent profile)."),{browser:e,page:o}}pe();await ye();async function po(e,t){let n=e.url();if(n.includes("/in/"))return!1;if(n.includes("/login")||n.includes("/authwall")||n.includes("/checkpoint"))throw new Error("Session expired \u2014 redirected to login. Run: ilml linkedin login");console.log(` Off-track: ${n.slice(0,80)}`),console.log(" Navigating back to profile..."),await e.goto(t,{waitUntil:"domcontentloaded",timeout:6e4}),await k(3e3);let o=e.url();return o.includes("/in/")||console.log(` Recovery failed \u2014 still on: ${o.slice(0,80)}`),!0}async function Yt(e,t,n={}){let{extractExperience:o=!1,extractFeatured:r=!1,extractEducation:s=!1,extractSkills:i=!1,extractRecommendations:l=!1,extractCertifications:c=!1}=n;try{await e.goto(t,{waitUntil:"domcontentloaded",timeout:6e4}),await k(3e3),await yt(e)&&(console.log(" Dismissed Premium overlay"),await k(1500),await po(e,t));let a=0;for(let x=0;x<2;x++){let Z=await e.evaluate(()=>document.body.scrollHeight);for(let V=1;V<=6;V++)await e.evaluate(R=>window.scrollTo(0,R),Z*V/6),await k(900);let X=await e.evaluate(()=>document.body.scrollHeight);if(X===a)break;a=X}await k(800);let m=null;try{let x=e.url();x&&/\/in\/[^/?#]/.test(x)&&(m=x.split("?")[0].replace(/\/+$/,""))}catch{}let f=await e.evaluate(()=>{let x=new Set(["Highlights","About","Activity","Experience","Education","Skills","Recommendations","Languages","Interests","Volunteer experience","Featured","Honors & awards","Honors and awards","Projects","Publications","Patents","Certifications","Licenses & certifications","Courses","Test scores","Organizations"]),Z=new Set(["Ad Options","Don\u2019t want to see this","0 notifications","Explore Premium profiles","You might like","People you may know","Suggested for you","More profiles for you","Promoted"]),X=h=>{let g=(h||"").trim().replace(/^[·•]\s*/,"");return/^(1st|2nd|3rd|she\/her|he\/him|they\/them|their\/them)$/i.test(g)},V={name:null,title:null,location:null,currentCompany:null,currentSchool:null,connectionDegree:null,hasVerifiedBadge:!1,photoUrl:null,connectionsLevel:null,mutualConnectionsCount:null,followers:null,openToWork:!1,hiring:!1,about:null,topSkills:null,availableSections:[]},R=document.querySelector("main");if(!R)return V;let b=[...Array.from(R.querySelectorAll("h1")),...Array.from(R.querySelectorAll("h2"))],_=Array.from(R.querySelectorAll("h2")),le=b.find(h=>{let g=h.textContent&&h.textContent.trim(),y=(g||"").replace(/\s*\(\d+\)$/,"").trim();return g&&g.length>1&&g.length<100&&!x.has(y)&&!Z.has(y)}),ce=le?le.textContent.trim():null,I=le?le.parentElement:null;for(;I&&I!==R&&!Array.from(I.children).filter(g=>g.tagName==="P").some(g=>{let y=g.textContent&&g.textContent.trim();return y&&y.length>5&&!X(y)});)I=I.parentElement;let ot=null,rt=null,st=null,Ie=null;if(I&&I!==R){let h=Array.from(I.children).filter(y=>y.tagName==="P").filter(y=>{let H=y.textContent&&y.textContent.trim();return H&&H.length>5&&!X(H)});if(h[0]&&(ot=h[0].textContent.trim()),h[1]){let y=h[1].textContent.trim().split(/\s*[·•]\s*/);rt=y[0]||null,y.length>1&&(st=y.slice(1).join(" \xB7 "))}let g=Array.from(I.children).filter(y=>y.tagName==="DIV");for(let y=g.length-1;y>=0;y--){let H=g[y].textContent&&g[y].textContent.trim();if(H&&!(ce&&H.startsWith(ce))&&(Ie=H.split(/[·•]/)[0].trim(),Ie))break}}let it=null;if(I){let h=I.querySelectorAll("p, span, div");for(let g of h){let y=(g.textContent||"").trim().replace(/^[·•]\s*/,"");if(y==="1st"||y==="2nd"||y==="3rd"){it=y;break}}}let vn=!!R.querySelector('svg[data-test-icon="verified"], [aria-label*="Verified" i]'),lt=document.querySelector('main img[width="200"], button img[alt*="photo" i]'),kn=lt&<.src||null,ke=R.textContent||"",ct=null,at=ke.match(/(\d+\+?)\s+connections\b/i);at&&(ct=at[1]+" connections");let Ce=null,ut=ke.match(/(\d+)\s+mutual connection/i),ft=ke.match(/and\s+(\d+)\s+other mutual/i),Cn=ke.match(/([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+and\s+([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+are\s+mutual/);ut?Ce=parseInt(ut[1],10):ft?Ce=2+parseInt(ft[1],10):Cn&&(Ce=2);let dt=null,mt=null,pt=_.find(h=>h.textContent&&h.textContent.trim()==="About");if(pt){let h=pt.parentElement;for(;h&&h.tagName!=="SECTION";)h=h.parentElement;if(h){let g=(h.textContent||"").trim();g=g.replace(/^About\s*/,"").trim();let y=g.match(/Top skills\s*(.+?)$/i);if(y){let Te=y[1].split(/\b(?:see (?:more|less)|show (?:more|less))\b/i)[0].trim().split(/\s*[·•]\s*/).map($n=>$n.trim()).filter(Boolean);Te.length>0&&Te.length<10&&(mt=Te)}g=g.split(/\n?…\s*more/i)[0].trim(),g=g.split(/\n?\.\.\.\s*more/i)[0].trim(),g=g.split(/\bTop skills\b/i)[0].trim(),g=g.split(/\b(?:see (?:more|less)|show (?:more|less))\b/i)[0].trim(),dt=g||null}}let ht=null,gt=_.find(h=>h.textContent&&h.textContent.trim()==="Activity");if(gt){let h=gt.parentElement;for(;h&&h.tagName!=="SECTION";)h=h.parentElement;if(h){let g=(h.textContent||"").slice(0,200).match(/([\d,]+)\s+followers/i);g&&(ht=parseInt(g[1].replace(/,/g,""),10))}}let xn=[...new Set(_.map(h=>(h.textContent||"").trim().replace(/\s*\(\d+\)$/,"").trim()).filter(h=>h&&h.length>1&&h.length<60&&h!==ce).filter(h=>x.has(h)))],de=document.body.textContent||"",An=/#OpenToWork\b/i.test(de)||/\bOpen to work\b/.test(de),En=/#Hiring\b/i.test(de)||/\bI'?m hiring\b/i.test(de)||/\bWe are hiring\b/i.test(de);return{name:ce,title:ot,location:Ie,currentCompany:rt,currentSchool:st,connectionDegree:it,hasVerifiedBadge:vn,photoUrl:kn,connectionsLevel:ct,mutualConnectionsCount:Ce,followers:ht,openToWork:An,hiring:En,about:dt,topSkills:mt,availableSections:xn}});console.log(`Viewed: ${f.name} - ${f.title}`);let p=null,v=null,w=null,E=null,z=null,Q=null;if(o||r||s||i||l||c){let x=await Promise.resolve().then(()=>(Gt(),Wt));o&&(p=await x.extractExperienceFromDetails(e,t),console.log(` + Experience: ${p.length} entries`)),r&&(v=await x.extractFeaturedFromDetails(e,t),console.log(` + Featured: ${v.length} entries`)),s&&(w=await x.extractEducationFromDetails(e,t),console.log(` + Education: ${w.length} entries`)),i&&(E=await x.extractSkillsFromDetails(e,t),console.log(` + Skills: ${E.length} entries`)),l&&(z=await x.extractRecommendationsFromDetails(e,t),console.log(` + Recommendations: ${z.length} entries`)),c&&(Q=await x.extractCertificationsFromDetails(e,t),console.log(` + Certifications: ${Q.length} entries`))}return{...f,profileUrl:t,resolvedUrl:m,...p!==null&&{experience:p},...v!==null&&{featured:v},...w!==null&&{education:w},...E!==null&&{skillsFull:E},...z!==null&&{recommendations:z},...Q!==null&&{certifications:Q}}}catch(d){console.error(`Error viewing profile ${t}:`,d.message);try{await e.goto("about:blank",{timeout:1e4}),await k(1e3)}catch{}if(/session expired|bounced to|authwall|checkpoint|redirected to login/i.test(d.message||""))throw d;return null}}Ve();await ye();pe();async function en(e,t,n={}){let{maxVisits:o=50,delayBetween:r=4e3,skipRecentDays:s=7,verbose:i=!1,extractExperience:l=!1}=n,c={visited:0,skipped:0,errors:0},d=Date.now()-s*24*60*60*1e3;for(let a of t){if(c.visited>=o)break;if(!a.profileUrl)continue;let m=Xt(a.profileUrl);if(m&&new Date(m).getTime()>d){c.skipped++;continue}try{let f=await Yt(e,a.profileUrl,{extractExperience:l}),p=a.source||"visit";if(f){let w={...f,source:p};l&&Array.isArray(f.experience)&&f.experience.length>0&&(w._lastEnrichedAt=new Date().toISOString()),qe(a.profileUrl,w),f.resolvedUrl&&Ue(a.profileUrl,f.resolvedUrl)}Zt(a.profileUrl,{name:f?.name||a.name||null,source:p}),c.visited++,i?console.log(` [${c.visited}] ${f?.name||a.profileUrl} \u2014 ${f?.title?.slice(0,40)||"?"}`):c.visited%10===0&&console.log(` Visited: ${c.visited}`);let v=Math.random()*4e3;await k(r+v)}catch(f){c.errors++,i&&console.error(` Error visiting ${a.name||a.profileUrl}: ${f.message?.slice(0,60)}`);let p=(f.message||"").toLowerCase();if(p.includes("detached")||p.includes("session closed")||p.includes("target closed")||p.includes("session expired")||p.includes("bounced to")||p.includes("authwall")||p.includes("checkpoint")||p.includes("redirected to login")){console.log(" Fatal browser/session error \u2014 stopping visits");break}}}return c}await ye();import"dotenv/config";import*as j from"fs";import*as G from"path";import{fileURLToPath as To}from"url";import"dotenv/config";import{createGraphClient as Ao,resolveToken as Eo}from"@ilivemylife/graph-sdk";import{config as $o}from"dotenv";$o();var tn=Eo()||process.env.TOKEN;tn||(console.error(`
|
|
239
239
|
[FATAL] No iLiveMyLife token found.`),console.error(" The bot uses Lifebot AI to decide which jobs to apply for"),console.error(` and how to fill application forms. It cannot work without it.
|
|
240
240
|
`),console.error(" Easiest way:"),console.error(" 1. npm install -g @ilivemylife/graph-sdk"),console.error(` 2. ilml login your@email.com yourpassword
|
|
241
241
|
`),console.error(` Or add ILML_TOKEN=... to .env
|