/** * LinkedIn WebView Injection Scripts * * Used for LinkedIn profile URL extraction and anti-detection * Ported from iOS WKWebView implementation (LinkedInConnectorView.swift) */ /** * LinkedIn App Deep Link Blocker * Prevents LinkedIn from opening the native app - keeps everything in WebView * Intercepts link clicks and navigation attempts */ export declare const LINKEDIN_APP_BLOCKER_SCRIPT = "\n(function() {\n try {\n // CRITICAL: Block ALL LinkedIn app deep link schemes\n var blockedSchemes = ['linkedin://', 'linkedinapp://', 'linkedinssl://', 'linkedin-mobile://'];\n \n function isBlockedUrl(url) {\n if (!url || typeof url !== 'string') return false;\n var urlLower = url.toLowerCase();\n return blockedSchemes.some(function(scheme) {\n return urlLower.startsWith(scheme);\n }) || (urlLower.startsWith('intent://') && urlLower.includes('linkedin'));\n }\n \n // Block app deep links by intercepting link clicks (capture phase - earliest possible)\n document.addEventListener('click', function(e) {\n var target = e.target;\n // Traverse up DOM to find anchor tag\n while (target && target.tagName !== 'A' && target.tagName !== 'BUTTON') {\n target = target.parentElement;\n }\n \n if (target) {\n var href = target.href || target.getAttribute('href') || target.getAttribute('data-href');\n if (href && isBlockedUrl(href)) {\n e.preventDefault();\n e.stopPropagation();\n e.stopImmediatePropagation();\n console.log('\uD83D\uDEAB [LINKEDIN-JS] Blocked app deep link click:', href);\n return false;\n }\n }\n }, true); // Capture phase - intercept before any other handlers\n \n // Override window.open to prevent app opening\n var originalOpen = window.open;\n window.open = function(url, target, features) {\n if (isBlockedUrl(url)) {\n console.log('\uD83D\uDEAB [LINKEDIN-JS] Blocked window.open app link:', url);\n return null;\n }\n return originalOpen.apply(this, arguments);\n };\n \n // Block location.href changes to app URLs\n var originalLocation = window.location;\n try {\n Object.defineProperty(window, 'location', {\n set: function(url) {\n if (isBlockedUrl(url)) {\n console.log('\uD83D\uDEAB [LINKEDIN-JS] Blocked location.href change to app URL:', url);\n return;\n }\n originalLocation.href = url;\n },\n get: function() {\n return originalLocation;\n },\n configurable: true\n });\n } catch (e) {\n // Fallback: Override location.href directly\n var originalHref = Object.getOwnPropertyDescriptor(window.location, 'href');\n if (originalHref && originalHref.set) {\n Object.defineProperty(window.location, 'href', {\n set: function(url) {\n if (isBlockedUrl(url)) {\n console.log('\uD83D\uDEAB [LINKEDIN-JS] Blocked location.href setter to app URL:', url);\n return;\n }\n originalHref.set.call(window.location, url);\n },\n get: originalHref.get,\n configurable: true\n });\n }\n }\n \n // Block location.replace and location.assign\n var originalReplace = window.location.replace;\n window.location.replace = function(url) {\n if (isBlockedUrl(url)) {\n console.log('\uD83D\uDEAB [LINKEDIN-JS] Blocked location.replace to app URL:', url);\n return;\n }\n return originalReplace.call(window.location, url);\n };\n \n var originalAssign = window.location.assign;\n window.location.assign = function(url) {\n if (isBlockedUrl(url)) {\n console.log('\uD83D\uDEAB [LINKEDIN-JS] Blocked location.assign to app URL:', url);\n return;\n }\n return originalAssign.call(window.location, url);\n };\n \n // Intercept meta refresh tags\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(mutation) {\n mutation.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) { // Element node\n if (node.tagName === 'META' && node.httpEquiv && node.httpEquiv.toLowerCase() === 'refresh') {\n var content = node.content || node.getAttribute('content');\n if (content && isBlockedUrl(content)) {\n node.remove();\n console.log('\uD83D\uDEAB [LINKEDIN-JS] Removed meta refresh to app URL');\n }\n }\n // Check all links in added nodes\n var links = node.querySelectorAll ? node.querySelectorAll('a[href]') : [];\n links.forEach(function(link) {\n if (isBlockedUrl(link.href)) {\n link.href = '#';\n link.onclick = function(e) {\n e.preventDefault();\n e.stopPropagation();\n return false;\n };\n console.log('\uD83D\uDEAB [LINKEDIN-JS] Neutralized app deep link in added node');\n }\n });\n }\n });\n });\n });\n \n // Start observing when DOM is ready\n if (document.body) {\n observer.observe(document.body, { childList: true, subtree: true });\n } else {\n document.addEventListener('DOMContentLoaded', function() {\n observer.observe(document.body, { childList: true, subtree: true });\n });\n }\n \n console.log('\u2705 [LINKEDIN-JS] App deep link blocker installed (comprehensive)');\n } catch (e) {\n console.error('\u274C [LINKEDIN-JS] App blocker error:', e);\n }\n})();\ntrue;\n"; /** * LinkedIn Profile URL Extraction Script * Injected ON DEMAND when user is on their profile page * Uses 5 extraction methods for robustness (from iOS implementation) * Based on iOS implementation: LinkedInConnectorView.swift lines 224-339 */ export declare const LINKEDIN_PROFILE_EXTRACTOR_SCRIPT = "\n(function() {\n try {\n if (!document.body) {\n window.ReactNativeWebView.postMessage(JSON.stringify({\n status: 'error',\n message: 'Page not ready'\n }));\n return;\n }\n \n // ========================================\n // 5 EXTRACTION METHODS (from iOS)\n // ========================================\n \n /**\n * Method 1: Check current URL for /in/ pattern\n */\n function extractFromCurrentUrl() {\n var currentUrl = window.location.href;\n var inMatch = currentUrl.match(/linkedin\\.com\\/in\\/([^\\/\\?]+)/);\n \n if (inMatch) {\n return 'https://www.linkedin.com/in/' + inMatch[1];\n }\n \n return null;\n }\n \n /**\n * Method 2: Search all links for /in/ pattern\n */\n function extractFromLinks() {\n var allLinks = document.querySelectorAll('a[href*=\"/in/\"]');\n \n for (var i = 0; i < allLinks.length; i++) {\n var href = allLinks[i].getAttribute('href') || allLinks[i].href;\n \n if (href && href.includes('/in/') && !href.includes('/me')) {\n var match = href.match(/https?:\\/\\/[^\\/]+\\/in\\/([^\\/\\?]+)/);\n if (match) {\n return 'https://www.linkedin.com/in/' + match[1];\n }\n }\n }\n \n return null;\n }\n \n /**\n * Method 3: Check meta tags\n */\n function extractFromMetaTags() {\n var metaTags = document.querySelectorAll('meta');\n \n for (var i = 0; i < metaTags.length; i++) {\n var content = metaTags[i].getAttribute('content') || \n metaTags[i].getAttribute('property') || '';\n \n if (content && content.includes('/in/')) {\n var match = content.match(/https?:\\/\\/[^\\/]+\\/in\\/([^\\/\\?]+)/);\n if (match) {\n return 'https://www.linkedin.com/in/' + match[1];\n }\n }\n }\n \n return null;\n }\n \n /**\n * Method 4: Check scripts for embedded URLs\n */\n function extractFromScripts() {\n var scripts = document.querySelectorAll('script');\n \n for (var i = 0; i < scripts.length; i++) {\n var scriptText = scripts[i].textContent || '';\n var match = scriptText.match(/https?:\\/\\/[^\\/]+\\/in\\/([^\\/\\?\"']+)/);\n \n if (match && !match[0].includes('/me')) {\n return 'https://www.linkedin.com/in/' + match[1];\n }\n }\n \n return null;\n }\n \n /**\n * Method 5: Check data attributes\n */\n function extractFromDataAttributes() {\n var dataElems = document.querySelectorAll('[data-profile-url], [data-entity-urn]');\n \n for (var i = 0; i < dataElems.length; i++) {\n var dataUrl = dataElems[i].getAttribute('data-profile-url') || \n dataElems[i].getAttribute('href') || '';\n \n if (dataUrl && dataUrl.includes('/in/')) {\n var match = dataUrl.match(/https?:\\/\\/[^\\/]+\\/in\\/([^\\/\\?]+)/);\n if (match) {\n return 'https://www.linkedin.com/in/' + match[1];\n }\n }\n }\n \n return null;\n }\n \n // ========================================\n // EXECUTE EXTRACTION\n // ========================================\n \n console.log('\uD83D\uDD0D Starting LinkedIn profile URL extraction...');\n \n // Try all 5 methods in order\n var profileUrl = extractFromCurrentUrl() ||\n extractFromLinks() ||\n extractFromMetaTags() ||\n extractFromScripts() ||\n extractFromDataAttributes();\n \n if (profileUrl) {\n console.log('\u2705 Profile URL extracted:', profileUrl);\n \n // Send success to React Native\n window.ReactNativeWebView.postMessage(JSON.stringify({\n status: 'success',\n profileUrl: profileUrl\n }));\n } else {\n console.warn('\u26A0\uFE0F Could not find LinkedIn profile URL');\n \n // Send error to React Native\n window.ReactNativeWebView.postMessage(JSON.stringify({\n status: 'error',\n message: 'Could not find LinkedIn profile URL. Please navigate to your profile page.'\n }));\n }\n \n } catch (error) {\n console.error('\u274C Error extracting profile URL:', error);\n \n // Send error to React Native\n window.ReactNativeWebView.postMessage(JSON.stringify({\n status: 'error',\n message: 'JavaScript error: ' + (error.message || String(error))\n }));\n }\n})();\ntrue; // Required for iOS compatibility\n"; /** * LinkedIn navigation script to go to user's profile page * Used after OAuth callback to navigate to /me */ export declare const LINKEDIN_NAVIGATE_TO_PROFILE_SCRIPT = "\n(function() {\n try {\n // Try clicking the \"Me\" menu item or profile link\n var meLink = document.querySelector('a[href*=\"/me\"]') || \n document.querySelector('a[href*=\"/in/\"][href*=\"profile\"]') ||\n document.querySelector('[data-control-name=\"identity_welcome_message\"]') ||\n document.querySelector('a[aria-label*=\"Profile\"]') ||\n document.querySelector('a[aria-label*=\"Me\"]');\n if (meLink) {\n console.log('[LINKEDIN] Found profile link, clicking...');\n meLink.click();\n return true;\n }\n // Fallback: navigate directly\n console.log('[LINKEDIN] No profile link found, navigating directly to /me');\n window.location.href = 'https://www.linkedin.com/me';\n return false;\n } catch (e) {\n console.error('[LINKEDIN] Navigation error:', e);\n window.location.href = 'https://www.linkedin.com/me';\n return false;\n }\n})();\ntrue;\n"; /** * LinkedIn Profile Data Consent Popup Script * Shows user consent UI before extracting profile data from DOM * Based on ChatGPT consent popup pattern */ export declare const LINKEDIN_PROFILE_CONSENT_POPUP_SCRIPT = "\n(function() {\n try {\n const existing = document.getElementById('onairos-linkedin-consent-overlay');\n if (existing) existing.remove();\n \n const overlay = document.createElement('div');\n overlay.id = 'onairos-linkedin-consent-overlay';\n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.7);\n z-index: 999999;\n display: flex;\n align-items: center;\n justify-content: center;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n `;\n \n const popup = document.createElement('div');\n popup.style.cssText = `\n background: white;\n border-radius: 16px;\n padding: 32px;\n max-width: 400px;\n width: 90%;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);\n `;\n \n popup.innerHTML = `\n
\n
\uD83D\uDCBC
\n

\n Import LinkedIn Profile?\n

\n

\n Allow Onairos to import your LinkedIn profile data including bio, work history, education, and skills?\n

\n
\n \n \n
\n
\n`;\n \n overlay.appendChild(popup);\n document.body.appendChild(overlay);\n \n document.getElementById('onairos-linkedin-deny').onclick = () => {\n overlay.remove();\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'LINKEDIN_PROFILE_CONSENT',\n status: 'denied'\n }));\n };\n \n document.getElementById('onairos-linkedin-allow').onclick = () => {\n document.getElementById('onairos-linkedin-allow').innerHTML = '\u23F3 Extracting...';\n document.getElementById('onairos-linkedin-allow').disabled = true;\n \n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'LINKEDIN_PROFILE_CONSENT',\n status: 'allowed'\n }));\n \n setTimeout(() => overlay.remove(), 500);\n };\n } catch (error) {\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'LINKEDIN_PROFILE_CONSENT',\n status: 'error',\n message: error.message\n }));\n }\n})();\ntrue;\n"; /** * LinkedIn Profile DOM Scraper Script * Extracts profile data directly from the LinkedIn profile page DOM * * This script extracts: * - Basic info (name, headline, location, about) * - Profile URL * - Work experience * - Education * - Skills * * NOTE: LinkedIn's DOM structure changes frequently. * If extraction fails, inspect the page and update selectors. * * Common selector patterns for LinkedIn profile pages: * - Name: h1, .text-heading-xlarge, [data-anonymize="person-name"] * - Headline: .text-body-medium, [data-anonymize="headline"] * - Location: .text-body-small, span with location text * - About: section with id="about" or class containing "about" * - Experience: section with id="experience" * - Education: section with id="education" * - Skills: section with id="skills" */ export declare const LINKEDIN_PROFILE_SCRAPER_SCRIPT = "\n(function() {\n try {\n console.log('\uD83D\uDD0D [LINKEDIN] Starting profile DOM extraction...');\n \n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'LINKEDIN_PROFILE_PROGRESS',\n stage: 'starting',\n progress: 5,\n message: 'Starting profile extraction...'\n }));\n\n // ========================================\n // HELPER FUNCTIONS\n // ========================================\n \n function getTextContent(selector, parent = document) {\n const el = parent.querySelector(selector);\n return el ? el.textContent.trim() : '';\n }\n \n function getAllTextContent(selector, parent = document) {\n const elements = parent.querySelectorAll(selector);\n return Array.from(elements).map(el => el.textContent.trim()).filter(t => t);\n }\n \n function cleanText(text) {\n if (!text) return '';\n return text.replace(/\\s+/g, ' ').trim();\n }\n\n // ========================================\n // EXTRACT BASIC INFO\n // ========================================\n \n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'LINKEDIN_PROFILE_PROGRESS',\n stage: 'basic_info',\n progress: 10,\n message: 'Extracting basic info...'\n }));\n \n // Name - try multiple selectors\n let fullName = '';\n const nameSelectors = [\n 'h1',\n '.text-heading-xlarge',\n '[data-anonymize=\"person-name\"]',\n '.pv-text-details__left-panel h1',\n '.profile-topcard-person-entity__name'\n ];\n for (const sel of nameSelectors) {\n const name = getTextContent(sel);\n if (name && name.length > 1 && name.length < 100) {\n fullName = cleanText(name);\n break;\n }\n }\n console.log('\uD83D\uDCDB [LINKEDIN] Name:', fullName);\n \n // Headline - try multiple selectors\n let headline = '';\n const headlineSelectors = [\n '.text-body-medium.break-words',\n '[data-anonymize=\"headline\"]',\n '.pv-text-details__left-panel .text-body-medium',\n '.profile-topcard__summary-position-title'\n ];\n for (const sel of headlineSelectors) {\n const h = getTextContent(sel);\n if (h && h.length > 3) {\n headline = cleanText(h);\n break;\n }\n }\n console.log('\uD83D\uDCCB [LINKEDIN] Headline:', headline);\n \n // Location\n let location = '';\n const locationSelectors = [\n '.text-body-small.inline.t-black--light.break-words',\n '.pv-text-details__left-panel .text-body-small',\n '[data-anonymize=\"location\"]',\n '.profile-topcard__location-data'\n ];\n for (const sel of locationSelectors) {\n const loc = getTextContent(sel);\n if (loc && loc.length > 2 && !loc.includes('connections') && !loc.includes('followers')) {\n location = cleanText(loc);\n break;\n }\n }\n console.log('\uD83D\uDCCD [LINKEDIN] Location:', location);\n \n // Profile URL\n const profileUrl = window.location.href.split('?')[0];\n console.log('\uD83D\uDD17 [LINKEDIN] Profile URL:', profileUrl);\n\n // ========================================\n // EXTRACT ABOUT SECTION\n // ========================================\n \n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'LINKEDIN_PROFILE_PROGRESS',\n stage: 'about',\n progress: 25,\n message: 'Extracting about section...'\n }));\n \n let about = '';\n \n // Try to find About section\n const aboutSection = document.querySelector('#about') || \n document.querySelector('[id*=\"about\"]') ||\n document.querySelector('section:has(> div > div > span:contains(\"About\"))');\n \n if (aboutSection) {\n // Look for the about text within the section\n const aboutTextSelectors = [\n '.display-flex.ph5.pv3 span[aria-hidden=\"true\"]',\n '.pv-shared-text-with-see-more span',\n '.inline-show-more-text span',\n 'span[aria-hidden=\"true\"]',\n '.full-width span'\n ];\n \n for (const sel of aboutTextSelectors) {\n const texts = aboutSection.querySelectorAll(sel);\n if (texts.length > 0) {\n about = cleanText(Array.from(texts).map(t => t.textContent).join(' '));\n if (about.length > 20) break;\n }\n }\n }\n \n // Alternative: look for about text near \"About\" heading\n if (!about) {\n const allSpans = document.querySelectorAll('span');\n let foundAboutHeading = false;\n for (const span of allSpans) {\n if (span.textContent.trim() === 'About') {\n foundAboutHeading = true;\n continue;\n }\n if (foundAboutHeading && span.textContent.length > 50) {\n about = cleanText(span.textContent);\n break;\n }\n }\n }\n console.log('\uD83D\uDCDD [LINKEDIN] About present:', !!about);\n\n // ========================================\n // EXTRACT EXPERIENCE\n // ========================================\n \n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'LINKEDIN_PROFILE_PROGRESS',\n stage: 'experience',\n progress: 40,\n message: 'Extracting work experience...'\n }));\n \n const experience = [];\n \n // Find experience section\n const expSection = document.querySelector('#experience') || \n document.querySelector('[id*=\"experience\"]') ||\n document.querySelector('section.experience-section');\n \n if (expSection) {\n // Look for experience entries - LinkedIn uses list items\n const expItems = expSection.querySelectorAll('li.artdeco-list__item, li[class*=\"experience-item\"], ul > li');\n \n for (const item of expItems) {\n const entry = {};\n \n // Title - usually the first/main heading in the item\n const titleEl = item.querySelector('.t-bold span, .mr1.t-bold span, [data-anonymize=\"job-title\"]');\n if (titleEl) entry.title = cleanText(titleEl.textContent);\n \n // Company\n const companyEl = item.querySelector('.t-normal span, .t-14.t-normal span, [data-anonymize=\"company-name\"]');\n if (companyEl) entry.company = cleanText(companyEl.textContent);\n \n // Duration/dates\n const dateEl = item.querySelector('.t-black--light span, .pvs-entity__caption-wrapper');\n if (dateEl) entry.duration = cleanText(dateEl.textContent);\n \n // Description\n const descEl = item.querySelector('.display-flex.align-items-center span[aria-hidden=\"true\"], .inline-show-more-text');\n if (descEl) entry.description = cleanText(descEl.textContent);\n \n // Location\n const locEl = item.querySelector('.t-black--light.t-normal span:last-child');\n if (locEl) entry.location = cleanText(locEl.textContent);\n \n if (entry.title || entry.company) {\n experience.push(entry);\n }\n }\n }\n console.log('\uD83D\uDCBC [LINKEDIN] Experience entries:', experience.length);\n\n // ========================================\n // EXTRACT EDUCATION\n // ========================================\n \n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'LINKEDIN_PROFILE_PROGRESS',\n stage: 'education',\n progress: 60,\n message: 'Extracting education...'\n }));\n \n const education = [];\n \n // Find education section\n const eduSection = document.querySelector('#education') || \n document.querySelector('[id*=\"education\"]') ||\n document.querySelector('section.education-section');\n \n if (eduSection) {\n const eduItems = eduSection.querySelectorAll('li.artdeco-list__item, li[class*=\"education-item\"], ul > li');\n \n for (const item of eduItems) {\n const entry = {};\n \n // School name\n const schoolEl = item.querySelector('.t-bold span, .mr1.t-bold span, [data-anonymize=\"school-name\"]');\n if (schoolEl) entry.school = cleanText(schoolEl.textContent);\n \n // Degree\n const degreeEl = item.querySelector('.t-normal span, .t-14.t-normal span');\n if (degreeEl) entry.degree = cleanText(degreeEl.textContent);\n \n // Field of study (sometimes combined with degree)\n const fieldEl = item.querySelector('.pv-entity__comma-item');\n if (fieldEl) entry.fieldOfStudy = cleanText(fieldEl.textContent);\n \n // Years\n const yearsEl = item.querySelector('.t-black--light span, .pvs-entity__caption-wrapper');\n if (yearsEl) entry.years = cleanText(yearsEl.textContent);\n \n if (entry.school) {\n education.push(entry);\n }\n }\n }\n console.log('\uD83C\uDF93 [LINKEDIN] Education entries:', education.length);\n\n // ========================================\n // EXTRACT SKILLS\n // ========================================\n \n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'LINKEDIN_PROFILE_PROGRESS',\n stage: 'skills',\n progress: 80,\n message: 'Extracting skills...'\n }));\n \n const skills = [];\n \n // Find skills section\n const skillsSection = document.querySelector('#skills') || \n document.querySelector('[id*=\"skills\"]') ||\n document.querySelector('section.skills-section');\n \n if (skillsSection) {\n const skillItems = skillsSection.querySelectorAll('.t-bold span, [data-anonymize=\"skill-name\"], .pv-skill-category-entity__name-text');\n \n for (const item of skillItems) {\n const skill = cleanText(item.textContent);\n if (skill && skill.length > 1 && skill.length < 100 && !skills.includes(skill)) {\n skills.push(skill);\n }\n }\n }\n \n // Also check for skills in \"Top skills\" section on profile card\n const topSkillsSection = document.querySelector('.pv-skill-category-list');\n if (topSkillsSection) {\n const topSkillItems = topSkillsSection.querySelectorAll('span');\n for (const item of topSkillItems) {\n const skill = cleanText(item.textContent);\n if (skill && skill.length > 1 && skill.length < 100 && !skills.includes(skill)) {\n skills.push(skill);\n }\n }\n }\n console.log('\uD83D\uDEE0\uFE0F [LINKEDIN] Skills:', skills.length);\n\n // ========================================\n // EXTRACT ADDITIONAL INFO\n // ========================================\n \n // Connections count\n let connections = 0;\n const connectionsEl = document.querySelector('.t-bold:has(+ span:contains(\"connections\")), .pv-top-card--list-bullet span');\n if (connectionsEl) {\n const connText = connectionsEl.textContent;\n const connMatch = connText.match(/([\\d,]+)\\+?\\s*connections?/i);\n if (connMatch) {\n connections = parseInt(connMatch[1].replace(/,/g, ''));\n }\n }\n \n // Profile picture URL\n let profilePicture = '';\n const imgEl = document.querySelector('.pv-top-card-profile-picture__image, .profile-photo-edit__preview, img[data-anonymize=\"headshot-photo\"]');\n if (imgEl && imgEl.src) {\n profilePicture = imgEl.src;\n }\n\n // ========================================\n // BUILD RESULT OBJECT\n // ========================================\n \n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'LINKEDIN_PROFILE_PROGRESS',\n stage: 'finalizing',\n progress: 95,\n message: 'Finalizing extraction...'\n }));\n \n const profileData = {\n // Basic Info\n fullName: fullName,\n headline: headline,\n location: location,\n about: about,\n profileUrl: profileUrl,\n \n // Profile Details\n profilePicture: profilePicture,\n \n // Professional Info\n experience: experience,\n education: education,\n skills: skills,\n \n // Additional Info\n connections: connections,\n \n // Metadata\n scrapedAt: new Date().toISOString(),\n extractionMethod: 'dom_scraper'\n };\n \n console.log('\u2705 [LINKEDIN] Profile extraction complete!');\n console.log('\uD83D\uDCCA [LINKEDIN] Summary:', {\n hasName: !!fullName,\n hasHeadline: !!headline,\n experienceCount: experience.length,\n educationCount: education.length,\n skillsCount: skills.length\n });\n\n // ========================================\n // SEND RESULT TO REACT NATIVE\n // ========================================\n \n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'LINKEDIN_PROFILE_EXPORT_COMPLETE',\n status: 'success',\n data: profileData,\n success: true\n }));\n\n } catch (error) {\n console.error('\u274C [LINKEDIN] Profile extraction error:', error);\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'LINKEDIN_PROFILE_EXPORT_ERROR',\n status: 'error',\n message: 'Extraction failed: ' + error.message,\n success: false\n }));\n }\n})();\ntrue;\n"; /** * Success/Error notification scripts for LinkedIn */ export declare const LINKEDIN_PROFILE_SUCCESS_SCRIPT = "\n(function() {\n console.log('\u2705 LinkedIn profile export successful!');\n})();\ntrue;\n"; export declare const LINKEDIN_PROFILE_ERROR_SCRIPT = "\n(function() {\n console.log('\u274C LinkedIn profile export failed!');\n})();\ntrue;\n"; //# sourceMappingURL=linkedin.d.ts.map