@onairos/react-native 3.7.2 → 3.7.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/lib/commonjs/api/index.js +219 -9
- package/lib/commonjs/components/BodyText.js +27 -9
- package/lib/commonjs/components/BrandMark.js +111 -10
- package/lib/commonjs/components/CodeInput.js +120 -9
- package/lib/commonjs/components/EmailInput.js +30 -8
- package/lib/commonjs/components/GoogleButton.js +56 -9
- package/lib/commonjs/components/HeadingGroup.js +43 -9
- package/lib/commonjs/components/LLMDataInputModal.js +664 -14
- package/lib/commonjs/components/ModalHeader.js +99 -9
- package/lib/commonjs/components/ModalSheet.js +47 -9
- package/lib/commonjs/components/Onairos.js +380 -14
- package/lib/commonjs/components/OnairosButton.js +313 -13
- package/lib/commonjs/components/OnairosSignInButton.js +130 -12
- package/lib/commonjs/components/Overlay.js +465 -13
- package/lib/commonjs/components/PersonaImage.js +137 -10
- package/lib/commonjs/components/PersonaLoadingScreen.js +318 -12
- package/lib/commonjs/components/PersonalizationConsentScreen.js +467 -13
- package/lib/commonjs/components/PinCreationScreen.js +403 -12
- package/lib/commonjs/components/PinInput.js +464 -9
- package/lib/commonjs/components/PlatformConnectorsStep.js +1311 -23
- package/lib/commonjs/components/PlatformList.js +137 -10
- package/lib/commonjs/components/PlatformToggle.js +180 -9
- package/lib/commonjs/components/PrimaryButton.js +180 -10
- package/lib/commonjs/components/SignInMatchAnimation.js +197 -9
- package/lib/commonjs/components/SignInStep.js +345 -12
- package/lib/commonjs/components/UniversalOnboarding.js +2780 -30
- package/lib/commonjs/components/VerificationStep.js +176 -11
- package/lib/commonjs/components/WelcomeScreen.js +461 -22
- package/lib/commonjs/components/icons/Basicproficon.js +37 -8
- package/lib/commonjs/components/icons/Basicprofile.js +21 -8
- package/lib/commonjs/components/icons/Checkbox.js +21 -8
- package/lib/commonjs/components/icons/Checkmark.js +27 -8
- package/lib/commonjs/components/icons/Contentanalysis.js +21 -8
- package/lib/commonjs/components/icons/Contenticon.js +39 -8
- package/lib/commonjs/components/icons/EnochE.js +41 -8
- package/lib/commonjs/components/icons/Personalityicon.js +30 -8
- package/lib/commonjs/components/icons/Personalityprofile.js +21 -8
- package/lib/commonjs/components/icons/Personalitytraits.js +21 -8
- package/lib/commonjs/components/icons/Userpreferences.js +21 -8
- package/lib/commonjs/components/icons/index.js +84 -17
- package/lib/commonjs/components/onboarding/OAuthWebView.js +1754 -18
- package/lib/commonjs/components/onboarding/OnboardingHeader.js +74 -10
- package/lib/commonjs/components/onboarding/PinInput.js +283 -10
- package/lib/commonjs/components/onboarding/PlatformConnector.js +249 -11
- package/lib/commonjs/config/PLATFORM_APIS.md +849 -0
- package/lib/commonjs/config/api.js +56 -7
- package/lib/commonjs/constants/index.js +120 -7
- package/lib/commonjs/context/AuthContext.js +345 -10
- package/lib/commonjs/hooks/useConnectedAccounts.js +111 -9
- package/lib/commonjs/hooks/useConnections.js +102 -8
- package/lib/commonjs/hooks/useCredentials.js +178 -10
- package/lib/commonjs/hooks/useUserConnections.js +148 -10
- package/lib/commonjs/index.js +439 -34
- package/lib/commonjs/services/apiClient.js +298 -8
- package/lib/commonjs/services/biometricPinService.js +180 -8
- package/lib/commonjs/services/chatGPTConversationExtractor.js +155 -8
- package/lib/commonjs/services/chatGPTConversationService.js +275 -9
- package/lib/commonjs/services/claudeConversationExtractor.js +103 -8
- package/lib/commonjs/services/claudeConversationService.js +158 -9
- package/lib/commonjs/services/connectedAccountsService.js +310 -10
- package/lib/commonjs/services/googleAuthService.js +252 -11
- package/lib/commonjs/services/hingeDataExtractor.js +105 -8
- package/lib/commonjs/services/hingeDataService.js +150 -9
- package/lib/commonjs/services/imageCompressionService.js +260 -7
- package/lib/commonjs/services/instagramDataExtractor.js +126 -8
- package/lib/commonjs/services/instagramDataService.js +163 -9
- package/lib/commonjs/services/jwtStorageService.js +276 -7
- package/lib/commonjs/services/linkedinDOMExtractor.js +245 -7
- package/lib/commonjs/services/linkedinProfileService.js +222 -9
- package/lib/commonjs/services/linkedinScrapingService.js +230 -8
- package/lib/commonjs/services/llmDataStorage.js +294 -8
- package/lib/commonjs/services/mobileTrainingService.js +186 -8
- package/lib/commonjs/services/netflixDataExtractor.js +120 -8
- package/lib/commonjs/services/netflixDataService.js +198 -9
- package/lib/commonjs/services/pinEncryptionService.js +84 -8
- package/lib/commonjs/services/pinStorageUtils.js +105 -7
- package/lib/commonjs/services/platformAuthService.js +1484 -12
- package/lib/commonjs/services/sephoraDataExtractor.js +140 -8
- package/lib/commonjs/services/sephoraDataService.js +200 -9
- package/lib/commonjs/services/spotifyDataExtractor.js +148 -8
- package/lib/commonjs/services/spotifyDataService.js +241 -9
- package/lib/commonjs/services/storageService.js +404 -8
- package/lib/commonjs/services/telegramDataExtractor.js +115 -8
- package/lib/commonjs/services/telegramDataService.js +499 -9
- package/lib/commonjs/services/trainingApiHelpers.js +73 -7
- package/lib/commonjs/services/userConnectionsService.js +340 -10
- package/lib/commonjs/services/youtubeMigrationService.js +416 -10
- package/lib/commonjs/theme/index.js +250 -7
- package/lib/commonjs/types/ambient.d.js +2 -1
- package/lib/commonjs/types/declarations.d.js +2 -1
- package/lib/commonjs/types/index.js +6 -1
- package/lib/commonjs/types/node-fix.d.js +2 -1
- package/lib/commonjs/types/node-override.d.js +2 -1
- package/lib/commonjs/types/opacity.d.js +2 -1
- package/lib/commonjs/types.js +14 -1
- package/lib/commonjs/utils/Portal.js +98 -8
- package/lib/commonjs/utils/api.js +130 -9
- package/lib/commonjs/utils/assetRegistry.js +210 -35
- package/lib/commonjs/utils/auth.js +112 -9
- package/lib/commonjs/utils/connectorTests.js +613 -29
- package/lib/commonjs/utils/crypto.js +62 -8
- package/lib/commonjs/utils/debugHelper.js +64 -1
- package/lib/commonjs/utils/encryption.js +76 -7
- package/lib/commonjs/utils/eventUtils.js +288 -1
- package/lib/commonjs/utils/haptics.js +66 -9
- package/lib/commonjs/utils/imagePreloader.js +6 -1
- package/lib/commonjs/utils/networkDiagnostics.js +226 -8
- package/lib/commonjs/utils/onairosApi.js +350 -9
- package/lib/commonjs/utils/programmaticFlow.js +117 -9
- package/lib/commonjs/utils/retryHelper.js +220 -1
- package/lib/commonjs/utils/secureStorage.js +349 -10
- package/lib/commonjs/utils/webviewScripts/chatgpt.js +551 -1
- package/lib/commonjs/utils/webviewScripts/claude.js +376 -1
- package/lib/commonjs/utils/webviewScripts/hinge.js +411 -1
- package/lib/commonjs/utils/webviewScripts/index.js +698 -15
- package/lib/commonjs/utils/webviewScripts/instagram.js +454 -1
- package/lib/commonjs/utils/webviewScripts/linkedin.js +880 -1
- package/lib/commonjs/utils/webviewScripts/netflix.js +382 -1
- package/lib/commonjs/utils/webviewScripts/sephora.js +516 -1
- package/lib/commonjs/utils/webviewScripts/spotify.js +419 -1
- package/lib/commonjs/utils/webviewScripts/telegram.js +678 -1
- package/lib/module/api/index.js +211 -1
- package/lib/module/components/BodyText.js +20 -1
- package/lib/module/components/BrandMark.js +104 -1
- package/lib/module/components/CodeInput.js +113 -1
- package/lib/module/components/EmailInput.js +23 -1
- package/lib/module/components/GoogleButton.js +49 -1
- package/lib/module/components/HeadingGroup.js +36 -1
- package/lib/module/components/LLMDataInputModal.js +656 -7
- package/lib/module/components/ModalHeader.js +92 -1
- package/lib/module/components/ModalSheet.js +39 -1
- package/lib/module/components/Onairos.js +373 -1
- package/lib/module/components/OnairosButton.js +305 -1
- package/lib/module/components/OnairosSignInButton.js +121 -1
- package/lib/module/components/Overlay.js +456 -1
- package/lib/module/components/PersonaImage.js +129 -1
- package/lib/module/components/PersonaLoadingScreen.js +310 -1
- package/lib/module/components/PersonalizationConsentScreen.js +460 -1
- package/lib/module/components/PinCreationScreen.js +396 -1
- package/lib/module/components/PinInput.js +456 -1
- package/lib/module/components/PlatformConnectorsStep.js +1302 -6
- package/lib/module/components/PlatformList.js +129 -1
- package/lib/module/components/PlatformToggle.js +173 -1
- package/lib/module/components/PrimaryButton.js +172 -1
- package/lib/module/components/SignInMatchAnimation.js +189 -1
- package/lib/module/components/SignInStep.js +338 -1
- package/lib/module/components/UniversalOnboarding.js +2770 -1
- package/lib/module/components/VerificationStep.js +168 -1
- package/lib/module/components/WelcomeScreen.js +453 -1
- package/lib/module/components/icons/Basicproficon.js +30 -1
- package/lib/module/components/icons/Basicprofile.js +14 -1
- package/lib/module/components/icons/Checkbox.js +14 -1
- package/lib/module/components/icons/Checkmark.js +20 -1
- package/lib/module/components/icons/Contentanalysis.js +14 -1
- package/lib/module/components/icons/Contenticon.js +32 -1
- package/lib/module/components/icons/EnochE.js +34 -1
- package/lib/module/components/icons/Personalityicon.js +23 -1
- package/lib/module/components/icons/Personalityprofile.js +14 -1
- package/lib/module/components/icons/Personalitytraits.js +14 -1
- package/lib/module/components/icons/Userpreferences.js +14 -1
- package/lib/module/components/icons/index.js +13 -1
- package/lib/module/components/onboarding/OAuthWebView.js +1746 -1
- package/lib/module/components/onboarding/OnboardingHeader.js +66 -1
- package/lib/module/components/onboarding/PinInput.js +274 -1
- package/lib/module/components/onboarding/PlatformConnector.js +240 -1
- package/lib/module/config/PLATFORM_APIS.md +849 -0
- package/lib/module/config/api.js +47 -1
- package/lib/module/constants/index.js +114 -1
- package/lib/module/context/AuthContext.js +335 -1
- package/lib/module/hooks/useConnectedAccounts.js +106 -1
- package/lib/module/hooks/useConnections.js +95 -1
- package/lib/module/hooks/useCredentials.js +171 -6
- package/lib/module/hooks/useUserConnections.js +140 -1
- package/lib/module/index.js +172 -1
- package/lib/module/services/apiClient.js +295 -1
- package/lib/module/services/biometricPinService.js +169 -1
- package/lib/module/services/chatGPTConversationExtractor.js +149 -1
- package/lib/module/services/chatGPTConversationService.js +268 -1
- package/lib/module/services/claudeConversationExtractor.js +97 -1
- package/lib/module/services/claudeConversationService.js +151 -1
- package/lib/module/services/connectedAccountsService.js +293 -1
- package/lib/module/services/googleAuthService.js +241 -1
- package/lib/module/services/hingeDataExtractor.js +99 -1
- package/lib/module/services/hingeDataService.js +143 -1
- package/lib/module/services/imageCompressionService.js +250 -1
- package/lib/module/services/instagramDataExtractor.js +120 -1
- package/lib/module/services/instagramDataService.js +156 -1
- package/lib/module/services/jwtStorageService.js +257 -1
- package/lib/module/services/linkedinDOMExtractor.js +234 -1
- package/lib/module/services/linkedinProfileService.js +210 -1
- package/lib/module/services/linkedinScrapingService.js +219 -1
- package/lib/module/services/llmDataStorage.js +277 -1
- package/lib/module/services/mobileTrainingService.js +173 -1
- package/lib/module/services/netflixDataExtractor.js +114 -1
- package/lib/module/services/netflixDataService.js +191 -1
- package/lib/module/services/pinEncryptionService.js +74 -6
- package/lib/module/services/pinStorageUtils.js +93 -1
- package/lib/module/services/platformAuthService.js +1461 -1
- package/lib/module/services/sephoraDataExtractor.js +134 -1
- package/lib/module/services/sephoraDataService.js +193 -1
- package/lib/module/services/spotifyDataExtractor.js +142 -1
- package/lib/module/services/spotifyDataService.js +234 -1
- package/lib/module/services/storageService.js +383 -1
- package/lib/module/services/telegramDataExtractor.js +109 -1
- package/lib/module/services/telegramDataService.js +493 -1
- package/lib/module/services/trainingApiHelpers.js +67 -1
- package/lib/module/services/userConnectionsService.js +329 -1
- package/lib/module/services/youtubeMigrationService.js +405 -1
- package/lib/module/theme/index.js +245 -1
- package/lib/module/types.js +10 -1
- package/lib/module/utils/Portal.js +90 -1
- package/lib/module/utils/api.js +118 -1
- package/lib/module/utils/assetRegistry.js +200 -34
- package/lib/module/utils/auth.js +100 -1
- package/lib/module/utils/connectorTests.js +600 -27
- package/lib/module/utils/crypto.js +54 -1
- package/lib/module/utils/debugHelper.js +54 -1
- package/lib/module/utils/encryption.js +67 -1
- package/lib/module/utils/eventUtils.js +270 -1
- package/lib/module/utils/haptics.js +59 -8
- package/lib/module/utils/imagePreloader.js +3 -1
- package/lib/module/utils/networkDiagnostics.js +217 -1
- package/lib/module/utils/onairosApi.js +333 -1
- package/lib/module/utils/programmaticFlow.js +111 -1
- package/lib/module/utils/retryHelper.js +211 -1
- package/lib/module/utils/secureStorage.js +330 -6
- package/lib/module/utils/webviewScripts/chatgpt.js +545 -1
- package/lib/module/utils/webviewScripts/claude.js +370 -1
- package/lib/module/utils/webviewScripts/hinge.js +405 -1
- package/lib/module/utils/webviewScripts/index.js +434 -1
- package/lib/module/utils/webviewScripts/instagram.js +448 -1
- package/lib/module/utils/webviewScripts/linkedin.js +874 -1
- package/lib/module/utils/webviewScripts/netflix.js +376 -1
- package/lib/module/utils/webviewScripts/sephora.js +510 -1
- package/lib/module/utils/webviewScripts/spotify.js +413 -1
- package/lib/module/utils/webviewScripts/telegram.js +672 -1
- package/package.json +2 -2
|
@@ -1 +1,880 @@
|
|
|
1
|
-
'use strict';function _0xc48e(_0x1fe44c,_0xc48ef0){_0x1fe44c=_0x1fe44c-0x0;const _0x2aeeb2=_0x1fe4();let _0x989e1f=_0x2aeeb2[_0x1fe44c];return _0x989e1f;}Object[_0xc48e(0x0)](exports,'__esModule',{'value':!![]}),exports['LINKEDIN_PROFILE_SUCCESS_SCRIPT']=exports[_0xc48e(0x1)]=exports['LINKEDIN_PROFILE_EXTRACTOR_SCRIPT']=exports[_0xc48e(0x2)]=exports[_0xc48e(0x3)]=exports[_0xc48e(0x4)]=exports['LINKEDIN_APP_BLOCKER_SCRIPT']=void 0x0;function _0x1fe4(){const _0x8a83ad=['defineProperty','LINKEDIN_PROFILE_SCRAPER_SCRIPT','LINKEDIN_PROFILE_ERROR_SCRIPT','LINKEDIN_PROFILE_CONSENT_POPUP_SCRIPT','LINKEDIN_NAVIGATE_TO_PROFILE_SCRIPT','\x0a(function()\x20{\x0a\x20\x20try\x20{\x0a\x20\x20\x20\x20//\x20CRITICAL:\x20Block\x20ALL\x20LinkedIn\x20app\x20deep\x20link\x20schemes\x0a\x20\x20\x20\x20var\x20blockedSchemes\x20=\x20[\x27linkedin://\x27,\x20\x27linkedinapp://\x27,\x20\x27linkedinssl://\x27,\x20\x27linkedin-mobile://\x27];\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20function\x20isBlockedUrl(url)\x20{\x0a\x20\x20\x20\x20\x20\x20if\x20(!url\x20||\x20typeof\x20url\x20!==\x20\x27string\x27)\x20return\x20false;\x0a\x20\x20\x20\x20\x20\x20var\x20urlLower\x20=\x20url.toLowerCase();\x0a\x20\x20\x20\x20\x20\x20return\x20blockedSchemes.some(function(scheme)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20return\x20urlLower.startsWith(scheme);\x0a\x20\x20\x20\x20\x20\x20})\x20||\x20(urlLower.startsWith(\x27intent://\x27)\x20&&\x20urlLower.includes(\x27linkedin\x27));\x0a\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20//\x20Block\x20app\x20deep\x20links\x20by\x20intercepting\x20link\x20clicks\x20(capture\x20phase\x20-\x20earliest\x20possible)\x0a\x20\x20\x20\x20document.addEventListener(\x27click\x27,\x20function(e)\x20{\x0a\x20\x20\x20\x20\x20\x20var\x20target\x20=\x20e.target;\x0a\x20\x20\x20\x20\x20\x20//\x20Traverse\x20up\x20DOM\x20to\x20find\x20anchor\x20tag\x0a\x20\x20\x20\x20\x20\x20while\x20(target\x20&&\x20target.tagName\x20!==\x20\x27A\x27\x20&&\x20target.tagName\x20!==\x20\x27BUTTON\x27)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20target\x20=\x20target.parentElement;\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20if\x20(target)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20var\x20href\x20=\x20target.href\x20||\x20target.getAttribute(\x27href\x27)\x20||\x20target.getAttribute(\x27data-href\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20if\x20(href\x20&&\x20isBlockedUrl(href))\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20e.preventDefault();\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20e.stopPropagation();\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20e.stopImmediatePropagation();\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27🚫\x20[LINKEDIN-JS]\x20Blocked\x20app\x20deep\x20link\x20click:\x27,\x20href);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20return\x20false;\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20},\x20true);\x20//\x20Capture\x20phase\x20-\x20intercept\x20before\x20any\x20other\x20handlers\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20//\x20Override\x20window.open\x20to\x20prevent\x20app\x20opening\x0a\x20\x20\x20\x20var\x20originalOpen\x20=\x20window.open;\x0a\x20\x20\x20\x20window.open\x20=\x20function(url,\x20target,\x20features)\x20{\x0a\x20\x20\x20\x20\x20\x20if\x20(isBlockedUrl(url))\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27🚫\x20[LINKEDIN-JS]\x20Blocked\x20window.open\x20app\x20link:\x27,\x20url);\x0a\x20\x20\x20\x20\x20\x20\x20\x20return\x20null;\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20return\x20originalOpen.apply(this,\x20arguments);\x0a\x20\x20\x20\x20};\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20//\x20Block\x20location.href\x20changes\x20to\x20app\x20URLs\x0a\x20\x20\x20\x20var\x20originalLocation\x20=\x20window.location;\x0a\x20\x20\x20\x20try\x20{\x0a\x20\x20\x20\x20\x20\x20Object.defineProperty(window,\x20\x27location\x27,\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20set:\x20function(url)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(isBlockedUrl(url))\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27🚫\x20[LINKEDIN-JS]\x20Blocked\x20location.href\x20change\x20to\x20app\x20URL:\x27,\x20url);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20return;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20originalLocation.href\x20=\x20url;\x0a\x20\x20\x20\x20\x20\x20\x20\x20},\x0a\x20\x20\x20\x20\x20\x20\x20\x20get:\x20function()\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20return\x20originalLocation;\x0a\x20\x20\x20\x20\x20\x20\x20\x20},\x0a\x20\x20\x20\x20\x20\x20\x20\x20configurable:\x20true\x0a\x20\x20\x20\x20\x20\x20});\x0a\x20\x20\x20\x20}\x20catch\x20(e)\x20{\x0a\x20\x20\x20\x20\x20\x20//\x20Fallback:\x20Override\x20location.href\x20directly\x0a\x20\x20\x20\x20\x20\x20var\x20originalHref\x20=\x20Object.getOwnPropertyDescriptor(window.location,\x20\x27href\x27);\x0a\x20\x20\x20\x20\x20\x20if\x20(originalHref\x20&&\x20originalHref.set)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20Object.defineProperty(window.location,\x20\x27href\x27,\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20set:\x20function(url)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(isBlockedUrl(url))\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27🚫\x20[LINKEDIN-JS]\x20Blocked\x20location.href\x20setter\x20to\x20app\x20URL:\x27,\x20url);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20return;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20originalHref.set.call(window.location,\x20url);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20},\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20get:\x20originalHref.get,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20configurable:\x20true\x0a\x20\x20\x20\x20\x20\x20\x20\x20});\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20//\x20Block\x20location.replace\x20and\x20location.assign\x0a\x20\x20\x20\x20var\x20originalReplace\x20=\x20window.location.replace;\x0a\x20\x20\x20\x20window.location.replace\x20=\x20function(url)\x20{\x0a\x20\x20\x20\x20\x20\x20if\x20(isBlockedUrl(url))\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27🚫\x20[LINKEDIN-JS]\x20Blocked\x20location.replace\x20to\x20app\x20URL:\x27,\x20url);\x0a\x20\x20\x20\x20\x20\x20\x20\x20return;\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20return\x20originalReplace.call(window.location,\x20url);\x0a\x20\x20\x20\x20};\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20var\x20originalAssign\x20=\x20window.location.assign;\x0a\x20\x20\x20\x20window.location.assign\x20=\x20function(url)\x20{\x0a\x20\x20\x20\x20\x20\x20if\x20(isBlockedUrl(url))\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27🚫\x20[LINKEDIN-JS]\x20Blocked\x20location.assign\x20to\x20app\x20URL:\x27,\x20url);\x0a\x20\x20\x20\x20\x20\x20\x20\x20return;\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20return\x20originalAssign.call(window.location,\x20url);\x0a\x20\x20\x20\x20};\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20//\x20Intercept\x20meta\x20refresh\x20tags\x0a\x20\x20\x20\x20var\x20observer\x20=\x20new\x20MutationObserver(function(mutations)\x20{\x0a\x20\x20\x20\x20\x20\x20mutations.forEach(function(mutation)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20mutation.addedNodes.forEach(function(node)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(node.nodeType\x20===\x201)\x20{\x20//\x20Element\x20node\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(node.tagName\x20===\x20\x27META\x27\x20&&\x20node.httpEquiv\x20&&\x20node.httpEquiv.toLowerCase()\x20===\x20\x27refresh\x27)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20var\x20content\x20=\x20node.content\x20||\x20node.getAttribute(\x27content\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(content\x20&&\x20isBlockedUrl(content))\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20node.remove();\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27🚫\x20[LINKEDIN-JS]\x20Removed\x20meta\x20refresh\x20to\x20app\x20URL\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20Check\x20all\x20links\x20in\x20added\x20nodes\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20var\x20links\x20=\x20node.querySelectorAll\x20?\x20node.querySelectorAll(\x27a[href]\x27)\x20:\x20[];\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20links.forEach(function(link)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(isBlockedUrl(link.href))\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20link.href\x20=\x20\x27#\x27;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20link.onclick\x20=\x20function(e)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20e.preventDefault();\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20e.stopPropagation();\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20return\x20false;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20};\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27🚫\x20[LINKEDIN-JS]\x20Neutralized\x20app\x20deep\x20link\x20in\x20added\x20node\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20});\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20});\x0a\x20\x20\x20\x20\x20\x20});\x0a\x20\x20\x20\x20});\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20//\x20Start\x20observing\x20when\x20DOM\x20is\x20ready\x0a\x20\x20\x20\x20if\x20(document.body)\x20{\x0a\x20\x20\x20\x20\x20\x20observer.observe(document.body,\x20{\x20childList:\x20true,\x20subtree:\x20true\x20});\x0a\x20\x20\x20\x20}\x20else\x20{\x0a\x20\x20\x20\x20\x20\x20document.addEventListener(\x27DOMContentLoaded\x27,\x20function()\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20observer.observe(document.body,\x20{\x20childList:\x20true,\x20subtree:\x20true\x20});\x0a\x20\x20\x20\x20\x20\x20});\x0a\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20console.log(\x27✅\x20[LINKEDIN-JS]\x20App\x20deep\x20link\x20blocker\x20installed\x20(comprehensive)\x27);\x0a\x20\x20}\x20catch\x20(e)\x20{\x0a\x20\x20\x20\x20console.error(\x27❌\x20[LINKEDIN-JS]\x20App\x20blocker\x20error:\x27,\x20e);\x0a\x20\x20}\x0a})();\x0atrue;\x0a','\x0a(function()\x20{\x0a\x20\x20try\x20{\x0a\x20\x20\x20\x20if\x20(!document.body)\x20{\x0a\x20\x20\x20\x20\x20\x20window.ReactNativeWebView.postMessage(JSON.stringify({\x0a\x20\x20\x20\x20\x20\x20\x20\x20status:\x20\x27error\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20message:\x20\x27Page\x20not\x20ready\x27\x0a\x20\x20\x20\x20\x20\x20}));\x0a\x20\x20\x20\x20\x20\x20return;\x0a\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20//\x205\x20EXTRACTION\x20METHODS\x20(from\x20iOS)\x0a\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20/**\x0a\x20\x20\x20\x20\x20*\x20Method\x201:\x20Check\x20current\x20URL\x20for\x20/in/\x20pattern\x0a\x20\x20\x20\x20\x20*/\x0a\x20\x20\x20\x20function\x20extractFromCurrentUrl()\x20{\x0a\x20\x20\x20\x20\x20\x20var\x20currentUrl\x20=\x20window.location.href;\x0a\x20\x20\x20\x20\x20\x20var\x20inMatch\x20=\x20currentUrl.match(/linkedin\x5c.com\x5c/in\x5c/([^\x5c/\x5c?]+)/);\x0a\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20if\x20(inMatch)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20return\x20\x27https://www.linkedin.com/in/\x27\x20+\x20inMatch[1];\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20return\x20null;\x0a\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20/**\x0a\x20\x20\x20\x20\x20*\x20Method\x202:\x20Search\x20all\x20links\x20for\x20/in/\x20pattern\x0a\x20\x20\x20\x20\x20*/\x0a\x20\x20\x20\x20function\x20extractFromLinks()\x20{\x0a\x20\x20\x20\x20\x20\x20var\x20allLinks\x20=\x20document.querySelectorAll(\x27a[href*=\x22/in/\x22]\x27);\x0a\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20for\x20(var\x20i\x20=\x200;\x20i\x20<\x20allLinks.length;\x20i++)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20var\x20href\x20=\x20allLinks[i].getAttribute(\x27href\x27)\x20||\x20allLinks[i].href;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20if\x20(href\x20&&\x20href.includes(\x27/in/\x27)\x20&&\x20!href.includes(\x27/me\x27))\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20var\x20match\x20=\x20href.match(/https?:\x5c/\x5c/[^\x5c/]+\x5c/in\x5c/([^\x5c/\x5c?]+)/);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(match)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20return\x20\x27https://www.linkedin.com/in/\x27\x20+\x20match[1];\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20return\x20null;\x0a\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20/**\x0a\x20\x20\x20\x20\x20*\x20Method\x203:\x20Check\x20meta\x20tags\x0a\x20\x20\x20\x20\x20*/\x0a\x20\x20\x20\x20function\x20extractFromMetaTags()\x20{\x0a\x20\x20\x20\x20\x20\x20var\x20metaTags\x20=\x20document.querySelectorAll(\x27meta\x27);\x0a\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20for\x20(var\x20i\x20=\x200;\x20i\x20<\x20metaTags.length;\x20i++)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20var\x20content\x20=\x20metaTags[i].getAttribute(\x27content\x27)\x20||\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20metaTags[i].getAttribute(\x27property\x27)\x20||\x20\x27\x27;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20if\x20(content\x20&&\x20content.includes(\x27/in/\x27))\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20var\x20match\x20=\x20content.match(/https?:\x5c/\x5c/[^\x5c/]+\x5c/in\x5c/([^\x5c/\x5c?]+)/);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(match)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20return\x20\x27https://www.linkedin.com/in/\x27\x20+\x20match[1];\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20return\x20null;\x0a\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20/**\x0a\x20\x20\x20\x20\x20*\x20Method\x204:\x20Check\x20scripts\x20for\x20embedded\x20URLs\x0a\x20\x20\x20\x20\x20*/\x0a\x20\x20\x20\x20function\x20extractFromScripts()\x20{\x0a\x20\x20\x20\x20\x20\x20var\x20scripts\x20=\x20document.querySelectorAll(\x27script\x27);\x0a\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20for\x20(var\x20i\x20=\x200;\x20i\x20<\x20scripts.length;\x20i++)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20var\x20scriptText\x20=\x20scripts[i].textContent\x20||\x20\x27\x27;\x0a\x20\x20\x20\x20\x20\x20\x20\x20var\x20match\x20=\x20scriptText.match(/https?:\x5c/\x5c/[^\x5c/]+\x5c/in\x5c/([^\x5c/\x5c?\x22\x27]+)/);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20if\x20(match\x20&&\x20!match[0].includes(\x27/me\x27))\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20return\x20\x27https://www.linkedin.com/in/\x27\x20+\x20match[1];\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20return\x20null;\x0a\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20/**\x0a\x20\x20\x20\x20\x20*\x20Method\x205:\x20Check\x20data\x20attributes\x0a\x20\x20\x20\x20\x20*/\x0a\x20\x20\x20\x20function\x20extractFromDataAttributes()\x20{\x0a\x20\x20\x20\x20\x20\x20var\x20dataElems\x20=\x20document.querySelectorAll(\x27[data-profile-url],\x20[data-entity-urn]\x27);\x0a\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20for\x20(var\x20i\x20=\x200;\x20i\x20<\x20dataElems.length;\x20i++)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20var\x20dataUrl\x20=\x20dataElems[i].getAttribute(\x27data-profile-url\x27)\x20||\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20dataElems[i].getAttribute(\x27href\x27)\x20||\x20\x27\x27;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20if\x20(dataUrl\x20&&\x20dataUrl.includes(\x27/in/\x27))\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20var\x20match\x20=\x20dataUrl.match(/https?:\x5c/\x5c/[^\x5c/]+\x5c/in\x5c/([^\x5c/\x5c?]+)/);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(match)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20return\x20\x27https://www.linkedin.com/in/\x27\x20+\x20match[1];\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20return\x20null;\x0a\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20//\x20EXECUTE\x20EXTRACTION\x0a\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20console.log(\x27🔍\x20Starting\x20LinkedIn\x20profile\x20URL\x20extraction...\x27);\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20//\x20Try\x20all\x205\x20methods\x20in\x20order\x0a\x20\x20\x20\x20var\x20profileUrl\x20=\x20extractFromCurrentUrl()\x20||\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20extractFromLinks()\x20||\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20extractFromMetaTags()\x20||\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20extractFromScripts()\x20||\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20extractFromDataAttributes();\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20if\x20(profileUrl)\x20{\x0a\x20\x20\x20\x20\x20\x20console.log(\x27✅\x20Profile\x20URL\x20extracted:\x27,\x20profileUrl);\x0a\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20//\x20Send\x20success\x20to\x20React\x20Native\x0a\x20\x20\x20\x20\x20\x20window.ReactNativeWebView.postMessage(JSON.stringify({\x0a\x20\x20\x20\x20\x20\x20\x20\x20status:\x20\x27success\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20profileUrl:\x20profileUrl\x0a\x20\x20\x20\x20\x20\x20}));\x0a\x20\x20\x20\x20}\x20else\x20{\x0a\x20\x20\x20\x20\x20\x20console.warn(\x27⚠️\x20Could\x20not\x20find\x20LinkedIn\x20profile\x20URL\x27);\x0a\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20//\x20Send\x20error\x20to\x20React\x20Native\x0a\x20\x20\x20\x20\x20\x20window.ReactNativeWebView.postMessage(JSON.stringify({\x0a\x20\x20\x20\x20\x20\x20\x20\x20status:\x20\x27error\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20message:\x20\x27Could\x20not\x20find\x20LinkedIn\x20profile\x20URL.\x20Please\x20navigate\x20to\x20your\x20profile\x20page.\x27\x0a\x20\x20\x20\x20\x20\x20}));\x0a\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x0a\x20\x20}\x20catch\x20(error)\x20{\x0a\x20\x20\x20\x20console.error(\x27❌\x20Error\x20extracting\x20profile\x20URL:\x27,\x20error);\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20//\x20Send\x20error\x20to\x20React\x20Native\x0a\x20\x20\x20\x20window.ReactNativeWebView.postMessage(JSON.stringify({\x0a\x20\x20\x20\x20\x20\x20status:\x20\x27error\x27,\x0a\x20\x20\x20\x20\x20\x20message:\x20\x27JavaScript\x20error:\x20\x27\x20+\x20(error.message\x20||\x20String(error))\x0a\x20\x20\x20\x20}));\x0a\x20\x20}\x0a})();\x0atrue;\x20//\x20Required\x20for\x20iOS\x20compatibility\x0a','\x0a(function()\x20{\x0a\x20\x20try\x20{\x0a\x20\x20\x20\x20//\x20Try\x20clicking\x20the\x20\x22Me\x22\x20menu\x20item\x20or\x20profile\x20link\x0a\x20\x20\x20\x20var\x20meLink\x20=\x20document.querySelector(\x27a[href*=\x22/me\x22]\x27)\x20||\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20document.querySelector(\x27a[href*=\x22/in/\x22][href*=\x22profile\x22]\x27)\x20||\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20document.querySelector(\x27[data-control-name=\x22identity_welcome_message\x22]\x27)\x20||\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20document.querySelector(\x27a[aria-label*=\x22Profile\x22]\x27)\x20||\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20document.querySelector(\x27a[aria-label*=\x22Me\x22]\x27);\x0a\x20\x20\x20\x20if\x20(meLink)\x20{\x0a\x20\x20\x20\x20\x20\x20console.log(\x27[LINKEDIN]\x20Found\x20profile\x20link,\x20clicking...\x27);\x0a\x20\x20\x20\x20\x20\x20meLink.click();\x0a\x20\x20\x20\x20\x20\x20return\x20true;\x0a\x20\x20\x20\x20}\x0a\x20\x20\x20\x20//\x20Fallback:\x20navigate\x20directly\x0a\x20\x20\x20\x20console.log(\x27[LINKEDIN]\x20No\x20profile\x20link\x20found,\x20navigating\x20directly\x20to\x20/me\x27);\x0a\x20\x20\x20\x20window.location.href\x20=\x20\x27https://www.linkedin.com/me\x27;\x0a\x20\x20\x20\x20return\x20false;\x0a\x20\x20}\x20catch\x20(e)\x20{\x0a\x20\x20\x20\x20console.error(\x27[LINKEDIN]\x20Navigation\x20error:\x27,\x20e);\x0a\x20\x20\x20\x20window.location.href\x20=\x20\x27https://www.linkedin.com/me\x27;\x0a\x20\x20\x20\x20return\x20false;\x0a\x20\x20}\x0a})();\x0atrue;\x0a','\x0a(function()\x20{\x0a\x20\x20\x20\x20try\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20existing\x20=\x20document.getElementById(\x27onairos-linkedin-consent-overlay\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20if\x20(existing)\x20existing.remove();\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20overlay\x20=\x20document.createElement(\x27div\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20overlay.id\x20=\x20\x27onairos-linkedin-consent-overlay\x27;\x0a\x20\x20\x20\x20\x20\x20\x20\x20overlay.style.cssText\x20=\x20`\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20position:\x20fixed;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20top:\x200;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20left:\x200;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20width:\x20100%;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20height:\x20100%;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20background:\x20rgba(0,\x200,\x200,\x200.7);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20z-index:\x20999999;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20display:\x20flex;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20align-items:\x20center;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20justify-content:\x20center;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20font-family:\x20-apple-system,\x20BlinkMacSystemFont,\x20\x27Segoe\x20UI\x27,\x20Roboto,\x20sans-serif;\x0a\x20\x20\x20\x20\x20\x20\x20\x20`;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20popup\x20=\x20document.createElement(\x27div\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20popup.style.cssText\x20=\x20`\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20background:\x20white;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20border-radius:\x2016px;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20padding:\x2032px;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20max-width:\x20400px;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20width:\x2090%;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20box-shadow:\x200\x2020px\x2060px\x20rgba(0,\x200,\x200,\x200.3);\x0a\x20\x20\x20\x20\x20\x20\x20\x20`;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20popup.innerHTML\x20=\x20`\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22text-align:\x20center;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:\x2048px;\x20margin-bottom:\x2016px;\x22>💼</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<h2\x20style=\x22margin:\x200\x200\x2012px\x200;\x20font-size:\x2024px;\x20color:\x20#1a1a1a;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Import\x20LinkedIn\x20Profile?\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</h2>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<p\x20style=\x22margin:\x200\x200\x2024px\x200;\x20color:\x20#666;\x20font-size:\x2016px;\x20line-height:\x201.5;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Allow\x20Onairos\x20to\x20import\x20your\x20LinkedIn\x20profile\x20data\x20including\x20bio,\x20work\x20history,\x20education,\x20and\x20skills?\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</p>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:\x20flex;\x20gap:\x2012px;\x20justify-content:\x20center;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20id=\x22onairos-linkedin-deny\x22\x20style=\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20flex:\x201;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20padding:\x2014px\x2024px;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20border:\x202px\x20solid\x20#e0e0e0;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20background:\x20white;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20color:\x20#666;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20border-radius:\x208px;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20font-size:\x2016px;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20font-weight:\x20600;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20cursor:\x20pointer;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22>Deny</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20id=\x22onairos-linkedin-allow\x22\x20style=\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20flex:\x201;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20padding:\x2014px\x2024px;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20border:\x20none;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20background:\x20#0077B5;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20color:\x20white;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20border-radius:\x208px;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20font-size:\x2016px;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20font-weight:\x20600;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20cursor:\x20pointer;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22>Allow</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a`;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20overlay.appendChild(popup);\x0a\x20\x20\x20\x20\x20\x20\x20\x20document.body.appendChild(overlay);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20document.getElementById(\x27onairos-linkedin-deny\x27).onclick\x20=\x20()\x20=>\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20overlay.remove();\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20window.ReactNativeWebView.postMessage(JSON.stringify({\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type:\x20\x27LINKEDIN_PROFILE_CONSENT\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20status:\x20\x27denied\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}));\x0a\x20\x20\x20\x20\x20\x20\x20\x20};\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20document.getElementById(\x27onairos-linkedin-allow\x27).onclick\x20=\x20()\x20=>\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20document.getElementById(\x27onairos-linkedin-allow\x27).innerHTML\x20=\x20\x27⏳\x20Extracting...\x27;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20document.getElementById(\x27onairos-linkedin-allow\x27).disabled\x20=\x20true;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20window.ReactNativeWebView.postMessage(JSON.stringify({\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type:\x20\x27LINKEDIN_PROFILE_CONSENT\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20status:\x20\x27allowed\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}));\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20setTimeout(()\x20=>\x20overlay.remove(),\x20500);\x0a\x20\x20\x20\x20\x20\x20\x20\x20};\x0a\x20\x20\x20\x20}\x20catch\x20(error)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20window.ReactNativeWebView.postMessage(JSON.stringify({\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type:\x20\x27LINKEDIN_PROFILE_CONSENT\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20status:\x20\x27error\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20message:\x20error.message\x0a\x20\x20\x20\x20\x20\x20\x20\x20}));\x0a\x20\x20\x20\x20}\x0a})();\x0atrue;\x0a','\x0a(function()\x20{\x0a\x20\x20\x20\x20try\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27🔍\x20[LINKEDIN]\x20Starting\x20profile\x20DOM\x20extraction...\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20window.ReactNativeWebView.postMessage(JSON.stringify({\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type:\x20\x27LINKEDIN_PROFILE_PROGRESS\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20stage:\x20\x27starting\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20progress:\x205,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20message:\x20\x27Starting\x20profile\x20extraction...\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20}));\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20HELPER\x20FUNCTIONS\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20function\x20getTextContent(selector,\x20parent\x20=\x20document)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20el\x20=\x20parent.querySelector(selector);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20return\x20el\x20?\x20el.textContent.trim()\x20:\x20\x27\x27;\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20function\x20getAllTextContent(selector,\x20parent\x20=\x20document)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20elements\x20=\x20parent.querySelectorAll(selector);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20return\x20Array.from(elements).map(el\x20=>\x20el.textContent.trim()).filter(t\x20=>\x20t);\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20function\x20cleanText(text)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(!text)\x20return\x20\x27\x27;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20return\x20text.replace(/\x5cs+/g,\x20\x27\x20\x27).trim();\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20EXTRACT\x20BASIC\x20INFO\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20window.ReactNativeWebView.postMessage(JSON.stringify({\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type:\x20\x27LINKEDIN_PROFILE_PROGRESS\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20stage:\x20\x27basic_info\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20progress:\x2010,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20message:\x20\x27Extracting\x20basic\x20info...\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20}));\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20Name\x20-\x20try\x20multiple\x20selectors\x0a\x20\x20\x20\x20\x20\x20\x20\x20let\x20fullName\x20=\x20\x27\x27;\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20nameSelectors\x20=\x20[\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27h1\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27.text-heading-xlarge\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27[data-anonymize=\x22person-name\x22]\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27.pv-text-details__left-panel\x20h1\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27.profile-topcard-person-entity__name\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20];\x0a\x20\x20\x20\x20\x20\x20\x20\x20for\x20(const\x20sel\x20of\x20nameSelectors)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20name\x20=\x20getTextContent(sel);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(name\x20&&\x20name.length\x20>\x201\x20&&\x20name.length\x20<\x20100)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20fullName\x20=\x20cleanText(name);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20break;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27📛\x20[LINKEDIN]\x20Name:\x27,\x20fullName);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20Headline\x20-\x20try\x20multiple\x20selectors\x0a\x20\x20\x20\x20\x20\x20\x20\x20let\x20headline\x20=\x20\x27\x27;\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20headlineSelectors\x20=\x20[\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27.text-body-medium.break-words\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27[data-anonymize=\x22headline\x22]\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27.pv-text-details__left-panel\x20.text-body-medium\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27.profile-topcard__summary-position-title\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20];\x0a\x20\x20\x20\x20\x20\x20\x20\x20for\x20(const\x20sel\x20of\x20headlineSelectors)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20h\x20=\x20getTextContent(sel);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(h\x20&&\x20h.length\x20>\x203)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20headline\x20=\x20cleanText(h);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20break;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27📋\x20[LINKEDIN]\x20Headline:\x27,\x20headline);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20Location\x0a\x20\x20\x20\x20\x20\x20\x20\x20let\x20location\x20=\x20\x27\x27;\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20locationSelectors\x20=\x20[\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27.text-body-small.inline.t-black--light.break-words\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27.pv-text-details__left-panel\x20.text-body-small\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27[data-anonymize=\x22location\x22]\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27.profile-topcard__location-data\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20];\x0a\x20\x20\x20\x20\x20\x20\x20\x20for\x20(const\x20sel\x20of\x20locationSelectors)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20loc\x20=\x20getTextContent(sel);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(loc\x20&&\x20loc.length\x20>\x202\x20&&\x20!loc.includes(\x27connections\x27)\x20&&\x20!loc.includes(\x27followers\x27))\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20location\x20=\x20cleanText(loc);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20break;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27📍\x20[LINKEDIN]\x20Location:\x27,\x20location);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20Profile\x20URL\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20profileUrl\x20=\x20window.location.href.split(\x27?\x27)[0];\x0a\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27🔗\x20[LINKEDIN]\x20Profile\x20URL:\x27,\x20profileUrl);\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20EXTRACT\x20ABOUT\x20SECTION\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20window.ReactNativeWebView.postMessage(JSON.stringify({\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type:\x20\x27LINKEDIN_PROFILE_PROGRESS\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20stage:\x20\x27about\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20progress:\x2025,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20message:\x20\x27Extracting\x20about\x20section...\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20}));\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20let\x20about\x20=\x20\x27\x27;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20Try\x20to\x20find\x20About\x20section\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20aboutSection\x20=\x20document.querySelector(\x27#about\x27)\x20||\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20document.querySelector(\x27[id*=\x22about\x22]\x27)\x20||\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20document.querySelector(\x27section:has(>\x20div\x20>\x20div\x20>\x20span:contains(\x22About\x22))\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20if\x20(aboutSection)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20Look\x20for\x20the\x20about\x20text\x20within\x20the\x20section\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20aboutTextSelectors\x20=\x20[\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27.display-flex.ph5.pv3\x20span[aria-hidden=\x22true\x22]\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27.pv-shared-text-with-see-more\x20span\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27.inline-show-more-text\x20span\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27span[aria-hidden=\x22true\x22]\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27.full-width\x20span\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20];\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20for\x20(const\x20sel\x20of\x20aboutTextSelectors)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20texts\x20=\x20aboutSection.querySelectorAll(sel);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(texts.length\x20>\x200)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20about\x20=\x20cleanText(Array.from(texts).map(t\x20=>\x20t.textContent).join(\x27\x20\x27));\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(about.length\x20>\x2020)\x20break;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20Alternative:\x20look\x20for\x20about\x20text\x20near\x20\x22About\x22\x20heading\x0a\x20\x20\x20\x20\x20\x20\x20\x20if\x20(!about)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20allSpans\x20=\x20document.querySelectorAll(\x27span\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20let\x20foundAboutHeading\x20=\x20false;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20for\x20(const\x20span\x20of\x20allSpans)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(span.textContent.trim()\x20===\x20\x27About\x27)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20foundAboutHeading\x20=\x20true;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20continue;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(foundAboutHeading\x20&&\x20span.textContent.length\x20>\x2050)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20about\x20=\x20cleanText(span.textContent);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20break;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27📝\x20[LINKEDIN]\x20About\x20(preview):\x27,\x20about.substring(0,\x20100)\x20+\x20\x27...\x27);\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20EXTRACT\x20EXPERIENCE\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20window.ReactNativeWebView.postMessage(JSON.stringify({\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type:\x20\x27LINKEDIN_PROFILE_PROGRESS\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20stage:\x20\x27experience\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20progress:\x2040,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20message:\x20\x27Extracting\x20work\x20experience...\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20}));\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20experience\x20=\x20[];\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20Find\x20experience\x20section\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20expSection\x20=\x20document.querySelector(\x27#experience\x27)\x20||\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20document.querySelector(\x27[id*=\x22experience\x22]\x27)\x20||\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20document.querySelector(\x27section.experience-section\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20if\x20(expSection)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20Look\x20for\x20experience\x20entries\x20-\x20LinkedIn\x20uses\x20list\x20items\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20expItems\x20=\x20expSection.querySelectorAll(\x27li.artdeco-list__item,\x20li[class*=\x22experience-item\x22],\x20ul\x20>\x20li\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20for\x20(const\x20item\x20of\x20expItems)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20entry\x20=\x20{};\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20Title\x20-\x20usually\x20the\x20first/main\x20heading\x20in\x20the\x20item\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20titleEl\x20=\x20item.querySelector(\x27.t-bold\x20span,\x20.mr1.t-bold\x20span,\x20[data-anonymize=\x22job-title\x22]\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(titleEl)\x20entry.title\x20=\x20cleanText(titleEl.textContent);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20Company\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20companyEl\x20=\x20item.querySelector(\x27.t-normal\x20span,\x20.t-14.t-normal\x20span,\x20[data-anonymize=\x22company-name\x22]\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(companyEl)\x20entry.company\x20=\x20cleanText(companyEl.textContent);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20Duration/dates\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20dateEl\x20=\x20item.querySelector(\x27.t-black--light\x20span,\x20.pvs-entity__caption-wrapper\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(dateEl)\x20entry.duration\x20=\x20cleanText(dateEl.textContent);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20Description\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20descEl\x20=\x20item.querySelector(\x27.display-flex.align-items-center\x20span[aria-hidden=\x22true\x22],\x20.inline-show-more-text\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(descEl)\x20entry.description\x20=\x20cleanText(descEl.textContent);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20Location\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20locEl\x20=\x20item.querySelector(\x27.t-black--light.t-normal\x20span:last-child\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(locEl)\x20entry.location\x20=\x20cleanText(locEl.textContent);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(entry.title\x20||\x20entry.company)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20experience.push(entry);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27💼\x20[LINKEDIN]\x20Experience\x20entries:\x27,\x20experience.length);\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20EXTRACT\x20EDUCATION\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20window.ReactNativeWebView.postMessage(JSON.stringify({\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type:\x20\x27LINKEDIN_PROFILE_PROGRESS\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20stage:\x20\x27education\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20progress:\x2060,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20message:\x20\x27Extracting\x20education...\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20}));\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20education\x20=\x20[];\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20Find\x20education\x20section\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20eduSection\x20=\x20document.querySelector(\x27#education\x27)\x20||\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20document.querySelector(\x27[id*=\x22education\x22]\x27)\x20||\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20document.querySelector(\x27section.education-section\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20if\x20(eduSection)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20eduItems\x20=\x20eduSection.querySelectorAll(\x27li.artdeco-list__item,\x20li[class*=\x22education-item\x22],\x20ul\x20>\x20li\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20for\x20(const\x20item\x20of\x20eduItems)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20entry\x20=\x20{};\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20School\x20name\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20schoolEl\x20=\x20item.querySelector(\x27.t-bold\x20span,\x20.mr1.t-bold\x20span,\x20[data-anonymize=\x22school-name\x22]\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(schoolEl)\x20entry.school\x20=\x20cleanText(schoolEl.textContent);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20Degree\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20degreeEl\x20=\x20item.querySelector(\x27.t-normal\x20span,\x20.t-14.t-normal\x20span\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(degreeEl)\x20entry.degree\x20=\x20cleanText(degreeEl.textContent);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20Field\x20of\x20study\x20(sometimes\x20combined\x20with\x20degree)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20fieldEl\x20=\x20item.querySelector(\x27.pv-entity__comma-item\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(fieldEl)\x20entry.fieldOfStudy\x20=\x20cleanText(fieldEl.textContent);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20Years\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20yearsEl\x20=\x20item.querySelector(\x27.t-black--light\x20span,\x20.pvs-entity__caption-wrapper\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(yearsEl)\x20entry.years\x20=\x20cleanText(yearsEl.textContent);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(entry.school)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20education.push(entry);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27🎓\x20[LINKEDIN]\x20Education\x20entries:\x27,\x20education.length);\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20EXTRACT\x20SKILLS\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20window.ReactNativeWebView.postMessage(JSON.stringify({\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type:\x20\x27LINKEDIN_PROFILE_PROGRESS\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20stage:\x20\x27skills\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20progress:\x2080,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20message:\x20\x27Extracting\x20skills...\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20}));\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20skills\x20=\x20[];\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20Find\x20skills\x20section\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20skillsSection\x20=\x20document.querySelector(\x27#skills\x27)\x20||\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20document.querySelector(\x27[id*=\x22skills\x22]\x27)\x20||\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20document.querySelector(\x27section.skills-section\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20if\x20(skillsSection)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20skillItems\x20=\x20skillsSection.querySelectorAll(\x27.t-bold\x20span,\x20[data-anonymize=\x22skill-name\x22],\x20.pv-skill-category-entity__name-text\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20for\x20(const\x20item\x20of\x20skillItems)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20skill\x20=\x20cleanText(item.textContent);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(skill\x20&&\x20skill.length\x20>\x201\x20&&\x20skill.length\x20<\x20100\x20&&\x20!skills.includes(skill))\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20skills.push(skill);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20Also\x20check\x20for\x20skills\x20in\x20\x22Top\x20skills\x22\x20section\x20on\x20profile\x20card\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20topSkillsSection\x20=\x20document.querySelector(\x27.pv-skill-category-list\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20if\x20(topSkillsSection)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20topSkillItems\x20=\x20topSkillsSection.querySelectorAll(\x27span\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20for\x20(const\x20item\x20of\x20topSkillItems)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20skill\x20=\x20cleanText(item.textContent);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(skill\x20&&\x20skill.length\x20>\x201\x20&&\x20skill.length\x20<\x20100\x20&&\x20!skills.includes(skill))\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20skills.push(skill);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27🛠️\x20[LINKEDIN]\x20Skills:\x27,\x20skills.length);\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20EXTRACT\x20ADDITIONAL\x20INFO\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20Connections\x20count\x0a\x20\x20\x20\x20\x20\x20\x20\x20let\x20connections\x20=\x200;\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20connectionsEl\x20=\x20document.querySelector(\x27.t-bold:has(+\x20span:contains(\x22connections\x22)),\x20.pv-top-card--list-bullet\x20span\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20if\x20(connectionsEl)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20connText\x20=\x20connectionsEl.textContent;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20const\x20connMatch\x20=\x20connText.match(/([\x5cd,]+)\x5c+?\x5cs*connections?/i);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if\x20(connMatch)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20connections\x20=\x20parseInt(connMatch[1].replace(/,/g,\x20\x27\x27));\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20Profile\x20picture\x20URL\x0a\x20\x20\x20\x20\x20\x20\x20\x20let\x20profilePicture\x20=\x20\x27\x27;\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20imgEl\x20=\x20document.querySelector(\x27.pv-top-card-profile-picture__image,\x20.profile-photo-edit__preview,\x20img[data-anonymize=\x22headshot-photo\x22]\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20if\x20(imgEl\x20&&\x20imgEl.src)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20profilePicture\x20=\x20imgEl.src;\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20BUILD\x20RESULT\x20OBJECT\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20window.ReactNativeWebView.postMessage(JSON.stringify({\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type:\x20\x27LINKEDIN_PROFILE_PROGRESS\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20stage:\x20\x27finalizing\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20progress:\x2095,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20message:\x20\x27Finalizing\x20extraction...\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20}));\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20profileData\x20=\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20Basic\x20Info\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20fullName:\x20fullName,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20headline:\x20headline,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20location:\x20location,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20about:\x20about,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20profileUrl:\x20profileUrl,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20Profile\x20Details\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20profilePicture:\x20profilePicture,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20Professional\x20Info\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20experience:\x20experience,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20education:\x20education,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20skills:\x20skills,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20Additional\x20Info\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20connections:\x20connections,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20//\x20Metadata\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20scrapedAt:\x20new\x20Date().toISOString(),\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20extractionMethod:\x20\x27dom_scraper\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20};\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27✅\x20[LINKEDIN]\x20Profile\x20extraction\x20complete!\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27📊\x20[LINKEDIN]\x20Summary:\x27,\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20name:\x20fullName,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20headline:\x20headline.substring(0,\x2050),\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20experienceCount:\x20experience.length,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20educationCount:\x20education.length,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20skillsCount:\x20skills.length\x0a\x20\x20\x20\x20\x20\x20\x20\x20});\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20SEND\x20RESULT\x20TO\x20REACT\x20NATIVE\x0a\x20\x20\x20\x20\x20\x20\x20\x20//\x20========================================\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20window.ReactNativeWebView.postMessage(JSON.stringify({\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type:\x20\x27LINKEDIN_PROFILE_EXPORT_COMPLETE\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20status:\x20\x27success\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20data:\x20profileData,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20success:\x20true\x0a\x20\x20\x20\x20\x20\x20\x20\x20}));\x0a\x0a\x20\x20\x20\x20}\x20catch\x20(error)\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20console.error(\x27❌\x20[LINKEDIN]\x20Profile\x20extraction\x20error:\x27,\x20error);\x0a\x20\x20\x20\x20\x20\x20\x20\x20window.ReactNativeWebView.postMessage(JSON.stringify({\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type:\x20\x27LINKEDIN_PROFILE_EXPORT_ERROR\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20status:\x20\x27error\x27,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20message:\x20\x27Extraction\x20failed:\x20\x27\x20+\x20error.message,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20success:\x20false\x0a\x20\x20\x20\x20\x20\x20\x20\x20}));\x0a\x20\x20\x20\x20}\x0a})();\x0atrue;\x0a','LINKEDIN_PROFILE_SUCCESS_SCRIPT','\x0a(function()\x20{\x0a\x20\x20\x20\x20console.log(\x27✅\x20LinkedIn\x20profile\x20export\x20successful!\x27);\x0a})();\x0atrue;\x0a'];_0x1fe4=function(){return _0x8a83ad;};return _0x1fe4();}const LINKEDIN_APP_BLOCKER_SCRIPT=exports['LINKEDIN_APP_BLOCKER_SCRIPT']=_0xc48e(0x5),LINKEDIN_PROFILE_EXTRACTOR_SCRIPT=exports['LINKEDIN_PROFILE_EXTRACTOR_SCRIPT']=_0xc48e(0x6),LINKEDIN_NAVIGATE_TO_PROFILE_SCRIPT=exports[_0xc48e(0x4)]=_0xc48e(0x7),LINKEDIN_PROFILE_CONSENT_POPUP_SCRIPT=exports[_0xc48e(0x3)]=_0xc48e(0x8),LINKEDIN_PROFILE_SCRAPER_SCRIPT=exports[_0xc48e(0x1)]=_0xc48e(0x9),LINKEDIN_PROFILE_SUCCESS_SCRIPT=exports[_0xc48e(0xa)]=_0xc48e(0xb),LINKEDIN_PROFILE_ERROR_SCRIPT=exports[_0xc48e(0x2)]='\x0a(function()\x20{\x0a\x20\x20\x20\x20console.log(\x27❌\x20LinkedIn\x20profile\x20export\x20failed!\x27);\x0a})();\x0atrue;\x0a';
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.LINKEDIN_PROFILE_SUCCESS_SCRIPT = exports.LINKEDIN_PROFILE_SCRAPER_SCRIPT = exports.LINKEDIN_PROFILE_EXTRACTOR_SCRIPT = exports.LINKEDIN_PROFILE_ERROR_SCRIPT = exports.LINKEDIN_PROFILE_CONSENT_POPUP_SCRIPT = exports.LINKEDIN_NAVIGATE_TO_PROFILE_SCRIPT = exports.LINKEDIN_APP_BLOCKER_SCRIPT = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* LinkedIn WebView Injection Scripts
|
|
9
|
+
*
|
|
10
|
+
* Used for LinkedIn profile URL extraction and anti-detection
|
|
11
|
+
* Ported from iOS WKWebView implementation (LinkedInConnectorView.swift)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* LinkedIn App Deep Link Blocker
|
|
16
|
+
* Prevents LinkedIn from opening the native app - keeps everything in WebView
|
|
17
|
+
* Intercepts link clicks and navigation attempts
|
|
18
|
+
*/
|
|
19
|
+
const LINKEDIN_APP_BLOCKER_SCRIPT = exports.LINKEDIN_APP_BLOCKER_SCRIPT = `
|
|
20
|
+
(function() {
|
|
21
|
+
try {
|
|
22
|
+
// CRITICAL: Block ALL LinkedIn app deep link schemes
|
|
23
|
+
var blockedSchemes = ['linkedin://', 'linkedinapp://', 'linkedinssl://', 'linkedin-mobile://'];
|
|
24
|
+
|
|
25
|
+
function isBlockedUrl(url) {
|
|
26
|
+
if (!url || typeof url !== 'string') return false;
|
|
27
|
+
var urlLower = url.toLowerCase();
|
|
28
|
+
return blockedSchemes.some(function(scheme) {
|
|
29
|
+
return urlLower.startsWith(scheme);
|
|
30
|
+
}) || (urlLower.startsWith('intent://') && urlLower.includes('linkedin'));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Block app deep links by intercepting link clicks (capture phase - earliest possible)
|
|
34
|
+
document.addEventListener('click', function(e) {
|
|
35
|
+
var target = e.target;
|
|
36
|
+
// Traverse up DOM to find anchor tag
|
|
37
|
+
while (target && target.tagName !== 'A' && target.tagName !== 'BUTTON') {
|
|
38
|
+
target = target.parentElement;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (target) {
|
|
42
|
+
var href = target.href || target.getAttribute('href') || target.getAttribute('data-href');
|
|
43
|
+
if (href && isBlockedUrl(href)) {
|
|
44
|
+
e.preventDefault();
|
|
45
|
+
e.stopPropagation();
|
|
46
|
+
e.stopImmediatePropagation();
|
|
47
|
+
console.log('🚫 [LINKEDIN-JS] Blocked app deep link click:', href);
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}, true); // Capture phase - intercept before any other handlers
|
|
52
|
+
|
|
53
|
+
// Override window.open to prevent app opening
|
|
54
|
+
var originalOpen = window.open;
|
|
55
|
+
window.open = function(url, target, features) {
|
|
56
|
+
if (isBlockedUrl(url)) {
|
|
57
|
+
console.log('🚫 [LINKEDIN-JS] Blocked window.open app link:', url);
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
return originalOpen.apply(this, arguments);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Block location.href changes to app URLs
|
|
64
|
+
var originalLocation = window.location;
|
|
65
|
+
try {
|
|
66
|
+
Object.defineProperty(window, 'location', {
|
|
67
|
+
set: function(url) {
|
|
68
|
+
if (isBlockedUrl(url)) {
|
|
69
|
+
console.log('🚫 [LINKEDIN-JS] Blocked location.href change to app URL:', url);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
originalLocation.href = url;
|
|
73
|
+
},
|
|
74
|
+
get: function() {
|
|
75
|
+
return originalLocation;
|
|
76
|
+
},
|
|
77
|
+
configurable: true
|
|
78
|
+
});
|
|
79
|
+
} catch (e) {
|
|
80
|
+
// Fallback: Override location.href directly
|
|
81
|
+
var originalHref = Object.getOwnPropertyDescriptor(window.location, 'href');
|
|
82
|
+
if (originalHref && originalHref.set) {
|
|
83
|
+
Object.defineProperty(window.location, 'href', {
|
|
84
|
+
set: function(url) {
|
|
85
|
+
if (isBlockedUrl(url)) {
|
|
86
|
+
console.log('🚫 [LINKEDIN-JS] Blocked location.href setter to app URL:', url);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
originalHref.set.call(window.location, url);
|
|
90
|
+
},
|
|
91
|
+
get: originalHref.get,
|
|
92
|
+
configurable: true
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Block location.replace and location.assign
|
|
98
|
+
var originalReplace = window.location.replace;
|
|
99
|
+
window.location.replace = function(url) {
|
|
100
|
+
if (isBlockedUrl(url)) {
|
|
101
|
+
console.log('🚫 [LINKEDIN-JS] Blocked location.replace to app URL:', url);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
return originalReplace.call(window.location, url);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
var originalAssign = window.location.assign;
|
|
108
|
+
window.location.assign = function(url) {
|
|
109
|
+
if (isBlockedUrl(url)) {
|
|
110
|
+
console.log('🚫 [LINKEDIN-JS] Blocked location.assign to app URL:', url);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
return originalAssign.call(window.location, url);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// Intercept meta refresh tags
|
|
117
|
+
var observer = new MutationObserver(function(mutations) {
|
|
118
|
+
mutations.forEach(function(mutation) {
|
|
119
|
+
mutation.addedNodes.forEach(function(node) {
|
|
120
|
+
if (node.nodeType === 1) { // Element node
|
|
121
|
+
if (node.tagName === 'META' && node.httpEquiv && node.httpEquiv.toLowerCase() === 'refresh') {
|
|
122
|
+
var content = node.content || node.getAttribute('content');
|
|
123
|
+
if (content && isBlockedUrl(content)) {
|
|
124
|
+
node.remove();
|
|
125
|
+
console.log('🚫 [LINKEDIN-JS] Removed meta refresh to app URL');
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Check all links in added nodes
|
|
129
|
+
var links = node.querySelectorAll ? node.querySelectorAll('a[href]') : [];
|
|
130
|
+
links.forEach(function(link) {
|
|
131
|
+
if (isBlockedUrl(link.href)) {
|
|
132
|
+
link.href = '#';
|
|
133
|
+
link.onclick = function(e) {
|
|
134
|
+
e.preventDefault();
|
|
135
|
+
e.stopPropagation();
|
|
136
|
+
return false;
|
|
137
|
+
};
|
|
138
|
+
console.log('🚫 [LINKEDIN-JS] Neutralized app deep link in added node');
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Start observing when DOM is ready
|
|
147
|
+
if (document.body) {
|
|
148
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
149
|
+
} else {
|
|
150
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
151
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
console.log('✅ [LINKEDIN-JS] App deep link blocker installed (comprehensive)');
|
|
156
|
+
} catch (e) {
|
|
157
|
+
console.error('❌ [LINKEDIN-JS] App blocker error:', e);
|
|
158
|
+
}
|
|
159
|
+
})();
|
|
160
|
+
true;
|
|
161
|
+
`;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* LinkedIn Profile URL Extraction Script
|
|
165
|
+
* Injected ON DEMAND when user is on their profile page
|
|
166
|
+
* Uses 5 extraction methods for robustness (from iOS implementation)
|
|
167
|
+
* Based on iOS implementation: LinkedInConnectorView.swift lines 224-339
|
|
168
|
+
*/
|
|
169
|
+
const LINKEDIN_PROFILE_EXTRACTOR_SCRIPT = exports.LINKEDIN_PROFILE_EXTRACTOR_SCRIPT = `
|
|
170
|
+
(function() {
|
|
171
|
+
try {
|
|
172
|
+
if (!document.body) {
|
|
173
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
174
|
+
status: 'error',
|
|
175
|
+
message: 'Page not ready'
|
|
176
|
+
}));
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ========================================
|
|
181
|
+
// 5 EXTRACTION METHODS (from iOS)
|
|
182
|
+
// ========================================
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Method 1: Check current URL for /in/ pattern
|
|
186
|
+
*/
|
|
187
|
+
function extractFromCurrentUrl() {
|
|
188
|
+
var currentUrl = window.location.href;
|
|
189
|
+
var inMatch = currentUrl.match(/linkedin\\.com\\/in\\/([^\\/\\?]+)/);
|
|
190
|
+
|
|
191
|
+
if (inMatch) {
|
|
192
|
+
return 'https://www.linkedin.com/in/' + inMatch[1];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Method 2: Search all links for /in/ pattern
|
|
200
|
+
*/
|
|
201
|
+
function extractFromLinks() {
|
|
202
|
+
var allLinks = document.querySelectorAll('a[href*="/in/"]');
|
|
203
|
+
|
|
204
|
+
for (var i = 0; i < allLinks.length; i++) {
|
|
205
|
+
var href = allLinks[i].getAttribute('href') || allLinks[i].href;
|
|
206
|
+
|
|
207
|
+
if (href && href.includes('/in/') && !href.includes('/me')) {
|
|
208
|
+
var match = href.match(/https?:\\/\\/[^\\/]+\\/in\\/([^\\/\\?]+)/);
|
|
209
|
+
if (match) {
|
|
210
|
+
return 'https://www.linkedin.com/in/' + match[1];
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Method 3: Check meta tags
|
|
220
|
+
*/
|
|
221
|
+
function extractFromMetaTags() {
|
|
222
|
+
var metaTags = document.querySelectorAll('meta');
|
|
223
|
+
|
|
224
|
+
for (var i = 0; i < metaTags.length; i++) {
|
|
225
|
+
var content = metaTags[i].getAttribute('content') ||
|
|
226
|
+
metaTags[i].getAttribute('property') || '';
|
|
227
|
+
|
|
228
|
+
if (content && content.includes('/in/')) {
|
|
229
|
+
var match = content.match(/https?:\\/\\/[^\\/]+\\/in\\/([^\\/\\?]+)/);
|
|
230
|
+
if (match) {
|
|
231
|
+
return 'https://www.linkedin.com/in/' + match[1];
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Method 4: Check scripts for embedded URLs
|
|
241
|
+
*/
|
|
242
|
+
function extractFromScripts() {
|
|
243
|
+
var scripts = document.querySelectorAll('script');
|
|
244
|
+
|
|
245
|
+
for (var i = 0; i < scripts.length; i++) {
|
|
246
|
+
var scriptText = scripts[i].textContent || '';
|
|
247
|
+
var match = scriptText.match(/https?:\\/\\/[^\\/]+\\/in\\/([^\\/\\?"']+)/);
|
|
248
|
+
|
|
249
|
+
if (match && !match[0].includes('/me')) {
|
|
250
|
+
return 'https://www.linkedin.com/in/' + match[1];
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Method 5: Check data attributes
|
|
259
|
+
*/
|
|
260
|
+
function extractFromDataAttributes() {
|
|
261
|
+
var dataElems = document.querySelectorAll('[data-profile-url], [data-entity-urn]');
|
|
262
|
+
|
|
263
|
+
for (var i = 0; i < dataElems.length; i++) {
|
|
264
|
+
var dataUrl = dataElems[i].getAttribute('data-profile-url') ||
|
|
265
|
+
dataElems[i].getAttribute('href') || '';
|
|
266
|
+
|
|
267
|
+
if (dataUrl && dataUrl.includes('/in/')) {
|
|
268
|
+
var match = dataUrl.match(/https?:\\/\\/[^\\/]+\\/in\\/([^\\/\\?]+)/);
|
|
269
|
+
if (match) {
|
|
270
|
+
return 'https://www.linkedin.com/in/' + match[1];
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// ========================================
|
|
279
|
+
// EXECUTE EXTRACTION
|
|
280
|
+
// ========================================
|
|
281
|
+
|
|
282
|
+
console.log('🔍 Starting LinkedIn profile URL extraction...');
|
|
283
|
+
|
|
284
|
+
// Try all 5 methods in order
|
|
285
|
+
var profileUrl = extractFromCurrentUrl() ||
|
|
286
|
+
extractFromLinks() ||
|
|
287
|
+
extractFromMetaTags() ||
|
|
288
|
+
extractFromScripts() ||
|
|
289
|
+
extractFromDataAttributes();
|
|
290
|
+
|
|
291
|
+
if (profileUrl) {
|
|
292
|
+
console.log('✅ Profile URL extracted:', profileUrl);
|
|
293
|
+
|
|
294
|
+
// Send success to React Native
|
|
295
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
296
|
+
status: 'success',
|
|
297
|
+
profileUrl: profileUrl
|
|
298
|
+
}));
|
|
299
|
+
} else {
|
|
300
|
+
console.warn('⚠️ Could not find LinkedIn profile URL');
|
|
301
|
+
|
|
302
|
+
// Send error to React Native
|
|
303
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
304
|
+
status: 'error',
|
|
305
|
+
message: 'Could not find LinkedIn profile URL. Please navigate to your profile page.'
|
|
306
|
+
}));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
} catch (error) {
|
|
310
|
+
console.error('❌ Error extracting profile URL:', error);
|
|
311
|
+
|
|
312
|
+
// Send error to React Native
|
|
313
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
314
|
+
status: 'error',
|
|
315
|
+
message: 'JavaScript error: ' + (error.message || String(error))
|
|
316
|
+
}));
|
|
317
|
+
}
|
|
318
|
+
})();
|
|
319
|
+
true; // Required for iOS compatibility
|
|
320
|
+
`;
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* LinkedIn navigation script to go to user's profile page
|
|
324
|
+
* Used after OAuth callback to navigate to /me
|
|
325
|
+
*/
|
|
326
|
+
const LINKEDIN_NAVIGATE_TO_PROFILE_SCRIPT = exports.LINKEDIN_NAVIGATE_TO_PROFILE_SCRIPT = `
|
|
327
|
+
(function() {
|
|
328
|
+
try {
|
|
329
|
+
// Try clicking the "Me" menu item or profile link
|
|
330
|
+
var meLink = document.querySelector('a[href*="/me"]') ||
|
|
331
|
+
document.querySelector('a[href*="/in/"][href*="profile"]') ||
|
|
332
|
+
document.querySelector('[data-control-name="identity_welcome_message"]') ||
|
|
333
|
+
document.querySelector('a[aria-label*="Profile"]') ||
|
|
334
|
+
document.querySelector('a[aria-label*="Me"]');
|
|
335
|
+
if (meLink) {
|
|
336
|
+
console.log('[LINKEDIN] Found profile link, clicking...');
|
|
337
|
+
meLink.click();
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
// Fallback: navigate directly
|
|
341
|
+
console.log('[LINKEDIN] No profile link found, navigating directly to /me');
|
|
342
|
+
window.location.href = 'https://www.linkedin.com/me';
|
|
343
|
+
return false;
|
|
344
|
+
} catch (e) {
|
|
345
|
+
console.error('[LINKEDIN] Navigation error:', e);
|
|
346
|
+
window.location.href = 'https://www.linkedin.com/me';
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
})();
|
|
350
|
+
true;
|
|
351
|
+
`;
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* LinkedIn Profile Data Consent Popup Script
|
|
355
|
+
* Shows user consent UI before extracting profile data from DOM
|
|
356
|
+
* Based on ChatGPT consent popup pattern
|
|
357
|
+
*/
|
|
358
|
+
const LINKEDIN_PROFILE_CONSENT_POPUP_SCRIPT = exports.LINKEDIN_PROFILE_CONSENT_POPUP_SCRIPT = `
|
|
359
|
+
(function() {
|
|
360
|
+
try {
|
|
361
|
+
const existing = document.getElementById('onairos-linkedin-consent-overlay');
|
|
362
|
+
if (existing) existing.remove();
|
|
363
|
+
|
|
364
|
+
const overlay = document.createElement('div');
|
|
365
|
+
overlay.id = 'onairos-linkedin-consent-overlay';
|
|
366
|
+
overlay.style.cssText = \`
|
|
367
|
+
position: fixed;
|
|
368
|
+
top: 0;
|
|
369
|
+
left: 0;
|
|
370
|
+
width: 100%;
|
|
371
|
+
height: 100%;
|
|
372
|
+
background: rgba(0, 0, 0, 0.7);
|
|
373
|
+
z-index: 999999;
|
|
374
|
+
display: flex;
|
|
375
|
+
align-items: center;
|
|
376
|
+
justify-content: center;
|
|
377
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
378
|
+
\`;
|
|
379
|
+
|
|
380
|
+
const popup = document.createElement('div');
|
|
381
|
+
popup.style.cssText = \`
|
|
382
|
+
background: white;
|
|
383
|
+
border-radius: 16px;
|
|
384
|
+
padding: 32px;
|
|
385
|
+
max-width: 400px;
|
|
386
|
+
width: 90%;
|
|
387
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
|
388
|
+
\`;
|
|
389
|
+
|
|
390
|
+
popup.innerHTML = \`
|
|
391
|
+
<div style="text-align: center;">
|
|
392
|
+
<div style="font-size: 48px; margin-bottom: 16px;">💼</div>
|
|
393
|
+
<h2 style="margin: 0 0 12px 0; font-size: 24px; color: #1a1a1a;">
|
|
394
|
+
Import LinkedIn Profile?
|
|
395
|
+
</h2>
|
|
396
|
+
<p style="margin: 0 0 24px 0; color: #666; font-size: 16px; line-height: 1.5;">
|
|
397
|
+
Allow Onairos to import your LinkedIn profile data including bio, work history, education, and skills?
|
|
398
|
+
</p>
|
|
399
|
+
<div style="display: flex; gap: 12px; justify-content: center;">
|
|
400
|
+
<button id="onairos-linkedin-deny" style="
|
|
401
|
+
flex: 1;
|
|
402
|
+
padding: 14px 24px;
|
|
403
|
+
border: 2px solid #e0e0e0;
|
|
404
|
+
background: white;
|
|
405
|
+
color: #666;
|
|
406
|
+
border-radius: 8px;
|
|
407
|
+
font-size: 16px;
|
|
408
|
+
font-weight: 600;
|
|
409
|
+
cursor: pointer;
|
|
410
|
+
">Deny</button>
|
|
411
|
+
<button id="onairos-linkedin-allow" style="
|
|
412
|
+
flex: 1;
|
|
413
|
+
padding: 14px 24px;
|
|
414
|
+
border: none;
|
|
415
|
+
background: #0077B5;
|
|
416
|
+
color: white;
|
|
417
|
+
border-radius: 8px;
|
|
418
|
+
font-size: 16px;
|
|
419
|
+
font-weight: 600;
|
|
420
|
+
cursor: pointer;
|
|
421
|
+
">Allow</button>
|
|
422
|
+
</div>
|
|
423
|
+
</div>
|
|
424
|
+
\`;
|
|
425
|
+
|
|
426
|
+
overlay.appendChild(popup);
|
|
427
|
+
document.body.appendChild(overlay);
|
|
428
|
+
|
|
429
|
+
document.getElementById('onairos-linkedin-deny').onclick = () => {
|
|
430
|
+
overlay.remove();
|
|
431
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
432
|
+
type: 'LINKEDIN_PROFILE_CONSENT',
|
|
433
|
+
status: 'denied'
|
|
434
|
+
}));
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
document.getElementById('onairos-linkedin-allow').onclick = () => {
|
|
438
|
+
document.getElementById('onairos-linkedin-allow').innerHTML = '⏳ Extracting...';
|
|
439
|
+
document.getElementById('onairos-linkedin-allow').disabled = true;
|
|
440
|
+
|
|
441
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
442
|
+
type: 'LINKEDIN_PROFILE_CONSENT',
|
|
443
|
+
status: 'allowed'
|
|
444
|
+
}));
|
|
445
|
+
|
|
446
|
+
setTimeout(() => overlay.remove(), 500);
|
|
447
|
+
};
|
|
448
|
+
} catch (error) {
|
|
449
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
450
|
+
type: 'LINKEDIN_PROFILE_CONSENT',
|
|
451
|
+
status: 'error',
|
|
452
|
+
message: error.message
|
|
453
|
+
}));
|
|
454
|
+
}
|
|
455
|
+
})();
|
|
456
|
+
true;
|
|
457
|
+
`;
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* LinkedIn Profile DOM Scraper Script
|
|
461
|
+
* Extracts profile data directly from the LinkedIn profile page DOM
|
|
462
|
+
*
|
|
463
|
+
* This script extracts:
|
|
464
|
+
* - Basic info (name, headline, location, about)
|
|
465
|
+
* - Profile URL
|
|
466
|
+
* - Work experience
|
|
467
|
+
* - Education
|
|
468
|
+
* - Skills
|
|
469
|
+
*
|
|
470
|
+
* NOTE: LinkedIn's DOM structure changes frequently.
|
|
471
|
+
* If extraction fails, inspect the page and update selectors.
|
|
472
|
+
*
|
|
473
|
+
* Common selector patterns for LinkedIn profile pages:
|
|
474
|
+
* - Name: h1, .text-heading-xlarge, [data-anonymize="person-name"]
|
|
475
|
+
* - Headline: .text-body-medium, [data-anonymize="headline"]
|
|
476
|
+
* - Location: .text-body-small, span with location text
|
|
477
|
+
* - About: section with id="about" or class containing "about"
|
|
478
|
+
* - Experience: section with id="experience"
|
|
479
|
+
* - Education: section with id="education"
|
|
480
|
+
* - Skills: section with id="skills"
|
|
481
|
+
*/
|
|
482
|
+
const LINKEDIN_PROFILE_SCRAPER_SCRIPT = exports.LINKEDIN_PROFILE_SCRAPER_SCRIPT = `
|
|
483
|
+
(function() {
|
|
484
|
+
try {
|
|
485
|
+
console.log('🔍 [LINKEDIN] Starting profile DOM extraction...');
|
|
486
|
+
|
|
487
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
488
|
+
type: 'LINKEDIN_PROFILE_PROGRESS',
|
|
489
|
+
stage: 'starting',
|
|
490
|
+
progress: 5,
|
|
491
|
+
message: 'Starting profile extraction...'
|
|
492
|
+
}));
|
|
493
|
+
|
|
494
|
+
// ========================================
|
|
495
|
+
// HELPER FUNCTIONS
|
|
496
|
+
// ========================================
|
|
497
|
+
|
|
498
|
+
function getTextContent(selector, parent = document) {
|
|
499
|
+
const el = parent.querySelector(selector);
|
|
500
|
+
return el ? el.textContent.trim() : '';
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function getAllTextContent(selector, parent = document) {
|
|
504
|
+
const elements = parent.querySelectorAll(selector);
|
|
505
|
+
return Array.from(elements).map(el => el.textContent.trim()).filter(t => t);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
function cleanText(text) {
|
|
509
|
+
if (!text) return '';
|
|
510
|
+
return text.replace(/\\s+/g, ' ').trim();
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// ========================================
|
|
514
|
+
// EXTRACT BASIC INFO
|
|
515
|
+
// ========================================
|
|
516
|
+
|
|
517
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
518
|
+
type: 'LINKEDIN_PROFILE_PROGRESS',
|
|
519
|
+
stage: 'basic_info',
|
|
520
|
+
progress: 10,
|
|
521
|
+
message: 'Extracting basic info...'
|
|
522
|
+
}));
|
|
523
|
+
|
|
524
|
+
// Name - try multiple selectors
|
|
525
|
+
let fullName = '';
|
|
526
|
+
const nameSelectors = [
|
|
527
|
+
'h1',
|
|
528
|
+
'.text-heading-xlarge',
|
|
529
|
+
'[data-anonymize="person-name"]',
|
|
530
|
+
'.pv-text-details__left-panel h1',
|
|
531
|
+
'.profile-topcard-person-entity__name'
|
|
532
|
+
];
|
|
533
|
+
for (const sel of nameSelectors) {
|
|
534
|
+
const name = getTextContent(sel);
|
|
535
|
+
if (name && name.length > 1 && name.length < 100) {
|
|
536
|
+
fullName = cleanText(name);
|
|
537
|
+
break;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
console.log('📛 [LINKEDIN] Name:', fullName);
|
|
541
|
+
|
|
542
|
+
// Headline - try multiple selectors
|
|
543
|
+
let headline = '';
|
|
544
|
+
const headlineSelectors = [
|
|
545
|
+
'.text-body-medium.break-words',
|
|
546
|
+
'[data-anonymize="headline"]',
|
|
547
|
+
'.pv-text-details__left-panel .text-body-medium',
|
|
548
|
+
'.profile-topcard__summary-position-title'
|
|
549
|
+
];
|
|
550
|
+
for (const sel of headlineSelectors) {
|
|
551
|
+
const h = getTextContent(sel);
|
|
552
|
+
if (h && h.length > 3) {
|
|
553
|
+
headline = cleanText(h);
|
|
554
|
+
break;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
console.log('📋 [LINKEDIN] Headline:', headline);
|
|
558
|
+
|
|
559
|
+
// Location
|
|
560
|
+
let location = '';
|
|
561
|
+
const locationSelectors = [
|
|
562
|
+
'.text-body-small.inline.t-black--light.break-words',
|
|
563
|
+
'.pv-text-details__left-panel .text-body-small',
|
|
564
|
+
'[data-anonymize="location"]',
|
|
565
|
+
'.profile-topcard__location-data'
|
|
566
|
+
];
|
|
567
|
+
for (const sel of locationSelectors) {
|
|
568
|
+
const loc = getTextContent(sel);
|
|
569
|
+
if (loc && loc.length > 2 && !loc.includes('connections') && !loc.includes('followers')) {
|
|
570
|
+
location = cleanText(loc);
|
|
571
|
+
break;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
console.log('📍 [LINKEDIN] Location:', location);
|
|
575
|
+
|
|
576
|
+
// Profile URL
|
|
577
|
+
const profileUrl = window.location.href.split('?')[0];
|
|
578
|
+
console.log('🔗 [LINKEDIN] Profile URL:', profileUrl);
|
|
579
|
+
|
|
580
|
+
// ========================================
|
|
581
|
+
// EXTRACT ABOUT SECTION
|
|
582
|
+
// ========================================
|
|
583
|
+
|
|
584
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
585
|
+
type: 'LINKEDIN_PROFILE_PROGRESS',
|
|
586
|
+
stage: 'about',
|
|
587
|
+
progress: 25,
|
|
588
|
+
message: 'Extracting about section...'
|
|
589
|
+
}));
|
|
590
|
+
|
|
591
|
+
let about = '';
|
|
592
|
+
|
|
593
|
+
// Try to find About section
|
|
594
|
+
const aboutSection = document.querySelector('#about') ||
|
|
595
|
+
document.querySelector('[id*="about"]') ||
|
|
596
|
+
document.querySelector('section:has(> div > div > span:contains("About"))');
|
|
597
|
+
|
|
598
|
+
if (aboutSection) {
|
|
599
|
+
// Look for the about text within the section
|
|
600
|
+
const aboutTextSelectors = [
|
|
601
|
+
'.display-flex.ph5.pv3 span[aria-hidden="true"]',
|
|
602
|
+
'.pv-shared-text-with-see-more span',
|
|
603
|
+
'.inline-show-more-text span',
|
|
604
|
+
'span[aria-hidden="true"]',
|
|
605
|
+
'.full-width span'
|
|
606
|
+
];
|
|
607
|
+
|
|
608
|
+
for (const sel of aboutTextSelectors) {
|
|
609
|
+
const texts = aboutSection.querySelectorAll(sel);
|
|
610
|
+
if (texts.length > 0) {
|
|
611
|
+
about = cleanText(Array.from(texts).map(t => t.textContent).join(' '));
|
|
612
|
+
if (about.length > 20) break;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// Alternative: look for about text near "About" heading
|
|
618
|
+
if (!about) {
|
|
619
|
+
const allSpans = document.querySelectorAll('span');
|
|
620
|
+
let foundAboutHeading = false;
|
|
621
|
+
for (const span of allSpans) {
|
|
622
|
+
if (span.textContent.trim() === 'About') {
|
|
623
|
+
foundAboutHeading = true;
|
|
624
|
+
continue;
|
|
625
|
+
}
|
|
626
|
+
if (foundAboutHeading && span.textContent.length > 50) {
|
|
627
|
+
about = cleanText(span.textContent);
|
|
628
|
+
break;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
console.log('📝 [LINKEDIN] About (preview):', about.substring(0, 100) + '...');
|
|
633
|
+
|
|
634
|
+
// ========================================
|
|
635
|
+
// EXTRACT EXPERIENCE
|
|
636
|
+
// ========================================
|
|
637
|
+
|
|
638
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
639
|
+
type: 'LINKEDIN_PROFILE_PROGRESS',
|
|
640
|
+
stage: 'experience',
|
|
641
|
+
progress: 40,
|
|
642
|
+
message: 'Extracting work experience...'
|
|
643
|
+
}));
|
|
644
|
+
|
|
645
|
+
const experience = [];
|
|
646
|
+
|
|
647
|
+
// Find experience section
|
|
648
|
+
const expSection = document.querySelector('#experience') ||
|
|
649
|
+
document.querySelector('[id*="experience"]') ||
|
|
650
|
+
document.querySelector('section.experience-section');
|
|
651
|
+
|
|
652
|
+
if (expSection) {
|
|
653
|
+
// Look for experience entries - LinkedIn uses list items
|
|
654
|
+
const expItems = expSection.querySelectorAll('li.artdeco-list__item, li[class*="experience-item"], ul > li');
|
|
655
|
+
|
|
656
|
+
for (const item of expItems) {
|
|
657
|
+
const entry = {};
|
|
658
|
+
|
|
659
|
+
// Title - usually the first/main heading in the item
|
|
660
|
+
const titleEl = item.querySelector('.t-bold span, .mr1.t-bold span, [data-anonymize="job-title"]');
|
|
661
|
+
if (titleEl) entry.title = cleanText(titleEl.textContent);
|
|
662
|
+
|
|
663
|
+
// Company
|
|
664
|
+
const companyEl = item.querySelector('.t-normal span, .t-14.t-normal span, [data-anonymize="company-name"]');
|
|
665
|
+
if (companyEl) entry.company = cleanText(companyEl.textContent);
|
|
666
|
+
|
|
667
|
+
// Duration/dates
|
|
668
|
+
const dateEl = item.querySelector('.t-black--light span, .pvs-entity__caption-wrapper');
|
|
669
|
+
if (dateEl) entry.duration = cleanText(dateEl.textContent);
|
|
670
|
+
|
|
671
|
+
// Description
|
|
672
|
+
const descEl = item.querySelector('.display-flex.align-items-center span[aria-hidden="true"], .inline-show-more-text');
|
|
673
|
+
if (descEl) entry.description = cleanText(descEl.textContent);
|
|
674
|
+
|
|
675
|
+
// Location
|
|
676
|
+
const locEl = item.querySelector('.t-black--light.t-normal span:last-child');
|
|
677
|
+
if (locEl) entry.location = cleanText(locEl.textContent);
|
|
678
|
+
|
|
679
|
+
if (entry.title || entry.company) {
|
|
680
|
+
experience.push(entry);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
console.log('💼 [LINKEDIN] Experience entries:', experience.length);
|
|
685
|
+
|
|
686
|
+
// ========================================
|
|
687
|
+
// EXTRACT EDUCATION
|
|
688
|
+
// ========================================
|
|
689
|
+
|
|
690
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
691
|
+
type: 'LINKEDIN_PROFILE_PROGRESS',
|
|
692
|
+
stage: 'education',
|
|
693
|
+
progress: 60,
|
|
694
|
+
message: 'Extracting education...'
|
|
695
|
+
}));
|
|
696
|
+
|
|
697
|
+
const education = [];
|
|
698
|
+
|
|
699
|
+
// Find education section
|
|
700
|
+
const eduSection = document.querySelector('#education') ||
|
|
701
|
+
document.querySelector('[id*="education"]') ||
|
|
702
|
+
document.querySelector('section.education-section');
|
|
703
|
+
|
|
704
|
+
if (eduSection) {
|
|
705
|
+
const eduItems = eduSection.querySelectorAll('li.artdeco-list__item, li[class*="education-item"], ul > li');
|
|
706
|
+
|
|
707
|
+
for (const item of eduItems) {
|
|
708
|
+
const entry = {};
|
|
709
|
+
|
|
710
|
+
// School name
|
|
711
|
+
const schoolEl = item.querySelector('.t-bold span, .mr1.t-bold span, [data-anonymize="school-name"]');
|
|
712
|
+
if (schoolEl) entry.school = cleanText(schoolEl.textContent);
|
|
713
|
+
|
|
714
|
+
// Degree
|
|
715
|
+
const degreeEl = item.querySelector('.t-normal span, .t-14.t-normal span');
|
|
716
|
+
if (degreeEl) entry.degree = cleanText(degreeEl.textContent);
|
|
717
|
+
|
|
718
|
+
// Field of study (sometimes combined with degree)
|
|
719
|
+
const fieldEl = item.querySelector('.pv-entity__comma-item');
|
|
720
|
+
if (fieldEl) entry.fieldOfStudy = cleanText(fieldEl.textContent);
|
|
721
|
+
|
|
722
|
+
// Years
|
|
723
|
+
const yearsEl = item.querySelector('.t-black--light span, .pvs-entity__caption-wrapper');
|
|
724
|
+
if (yearsEl) entry.years = cleanText(yearsEl.textContent);
|
|
725
|
+
|
|
726
|
+
if (entry.school) {
|
|
727
|
+
education.push(entry);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
console.log('🎓 [LINKEDIN] Education entries:', education.length);
|
|
732
|
+
|
|
733
|
+
// ========================================
|
|
734
|
+
// EXTRACT SKILLS
|
|
735
|
+
// ========================================
|
|
736
|
+
|
|
737
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
738
|
+
type: 'LINKEDIN_PROFILE_PROGRESS',
|
|
739
|
+
stage: 'skills',
|
|
740
|
+
progress: 80,
|
|
741
|
+
message: 'Extracting skills...'
|
|
742
|
+
}));
|
|
743
|
+
|
|
744
|
+
const skills = [];
|
|
745
|
+
|
|
746
|
+
// Find skills section
|
|
747
|
+
const skillsSection = document.querySelector('#skills') ||
|
|
748
|
+
document.querySelector('[id*="skills"]') ||
|
|
749
|
+
document.querySelector('section.skills-section');
|
|
750
|
+
|
|
751
|
+
if (skillsSection) {
|
|
752
|
+
const skillItems = skillsSection.querySelectorAll('.t-bold span, [data-anonymize="skill-name"], .pv-skill-category-entity__name-text');
|
|
753
|
+
|
|
754
|
+
for (const item of skillItems) {
|
|
755
|
+
const skill = cleanText(item.textContent);
|
|
756
|
+
if (skill && skill.length > 1 && skill.length < 100 && !skills.includes(skill)) {
|
|
757
|
+
skills.push(skill);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// Also check for skills in "Top skills" section on profile card
|
|
763
|
+
const topSkillsSection = document.querySelector('.pv-skill-category-list');
|
|
764
|
+
if (topSkillsSection) {
|
|
765
|
+
const topSkillItems = topSkillsSection.querySelectorAll('span');
|
|
766
|
+
for (const item of topSkillItems) {
|
|
767
|
+
const skill = cleanText(item.textContent);
|
|
768
|
+
if (skill && skill.length > 1 && skill.length < 100 && !skills.includes(skill)) {
|
|
769
|
+
skills.push(skill);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
console.log('🛠️ [LINKEDIN] Skills:', skills.length);
|
|
774
|
+
|
|
775
|
+
// ========================================
|
|
776
|
+
// EXTRACT ADDITIONAL INFO
|
|
777
|
+
// ========================================
|
|
778
|
+
|
|
779
|
+
// Connections count
|
|
780
|
+
let connections = 0;
|
|
781
|
+
const connectionsEl = document.querySelector('.t-bold:has(+ span:contains("connections")), .pv-top-card--list-bullet span');
|
|
782
|
+
if (connectionsEl) {
|
|
783
|
+
const connText = connectionsEl.textContent;
|
|
784
|
+
const connMatch = connText.match(/([\\d,]+)\\+?\\s*connections?/i);
|
|
785
|
+
if (connMatch) {
|
|
786
|
+
connections = parseInt(connMatch[1].replace(/,/g, ''));
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
// Profile picture URL
|
|
791
|
+
let profilePicture = '';
|
|
792
|
+
const imgEl = document.querySelector('.pv-top-card-profile-picture__image, .profile-photo-edit__preview, img[data-anonymize="headshot-photo"]');
|
|
793
|
+
if (imgEl && imgEl.src) {
|
|
794
|
+
profilePicture = imgEl.src;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
// ========================================
|
|
798
|
+
// BUILD RESULT OBJECT
|
|
799
|
+
// ========================================
|
|
800
|
+
|
|
801
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
802
|
+
type: 'LINKEDIN_PROFILE_PROGRESS',
|
|
803
|
+
stage: 'finalizing',
|
|
804
|
+
progress: 95,
|
|
805
|
+
message: 'Finalizing extraction...'
|
|
806
|
+
}));
|
|
807
|
+
|
|
808
|
+
const profileData = {
|
|
809
|
+
// Basic Info
|
|
810
|
+
fullName: fullName,
|
|
811
|
+
headline: headline,
|
|
812
|
+
location: location,
|
|
813
|
+
about: about,
|
|
814
|
+
profileUrl: profileUrl,
|
|
815
|
+
|
|
816
|
+
// Profile Details
|
|
817
|
+
profilePicture: profilePicture,
|
|
818
|
+
|
|
819
|
+
// Professional Info
|
|
820
|
+
experience: experience,
|
|
821
|
+
education: education,
|
|
822
|
+
skills: skills,
|
|
823
|
+
|
|
824
|
+
// Additional Info
|
|
825
|
+
connections: connections,
|
|
826
|
+
|
|
827
|
+
// Metadata
|
|
828
|
+
scrapedAt: new Date().toISOString(),
|
|
829
|
+
extractionMethod: 'dom_scraper'
|
|
830
|
+
};
|
|
831
|
+
|
|
832
|
+
console.log('✅ [LINKEDIN] Profile extraction complete!');
|
|
833
|
+
console.log('📊 [LINKEDIN] Summary:', {
|
|
834
|
+
name: fullName,
|
|
835
|
+
headline: headline.substring(0, 50),
|
|
836
|
+
experienceCount: experience.length,
|
|
837
|
+
educationCount: education.length,
|
|
838
|
+
skillsCount: skills.length
|
|
839
|
+
});
|
|
840
|
+
|
|
841
|
+
// ========================================
|
|
842
|
+
// SEND RESULT TO REACT NATIVE
|
|
843
|
+
// ========================================
|
|
844
|
+
|
|
845
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
846
|
+
type: 'LINKEDIN_PROFILE_EXPORT_COMPLETE',
|
|
847
|
+
status: 'success',
|
|
848
|
+
data: profileData,
|
|
849
|
+
success: true
|
|
850
|
+
}));
|
|
851
|
+
|
|
852
|
+
} catch (error) {
|
|
853
|
+
console.error('❌ [LINKEDIN] Profile extraction error:', error);
|
|
854
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
855
|
+
type: 'LINKEDIN_PROFILE_EXPORT_ERROR',
|
|
856
|
+
status: 'error',
|
|
857
|
+
message: 'Extraction failed: ' + error.message,
|
|
858
|
+
success: false
|
|
859
|
+
}));
|
|
860
|
+
}
|
|
861
|
+
})();
|
|
862
|
+
true;
|
|
863
|
+
`;
|
|
864
|
+
|
|
865
|
+
/**
|
|
866
|
+
* Success/Error notification scripts for LinkedIn
|
|
867
|
+
*/
|
|
868
|
+
const LINKEDIN_PROFILE_SUCCESS_SCRIPT = exports.LINKEDIN_PROFILE_SUCCESS_SCRIPT = `
|
|
869
|
+
(function() {
|
|
870
|
+
console.log('✅ LinkedIn profile export successful!');
|
|
871
|
+
})();
|
|
872
|
+
true;
|
|
873
|
+
`;
|
|
874
|
+
const LINKEDIN_PROFILE_ERROR_SCRIPT = exports.LINKEDIN_PROFILE_ERROR_SCRIPT = `
|
|
875
|
+
(function() {
|
|
876
|
+
console.log('❌ LinkedIn profile export failed!');
|
|
877
|
+
})();
|
|
878
|
+
true;
|
|
879
|
+
`;
|
|
880
|
+
//# sourceMappingURL=linkedin.js.map
|