six-degrees 0.6.0 → 0.8.0
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/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +4 -0
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +42 -14
- package/.next/standalone/.next/routes-manifest.json +24 -0
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +26 -18
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +26 -18
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +25 -16
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/admin-delete/route.js +2 -2
- package/.next/standalone/.next/server/app/api/admin-delete/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/admin-update/route.js +2 -2
- package/.next/standalone/.next/server/app/api/admin-update/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/bridges/route.js +2 -2
- package/.next/standalone/.next/server/app/api/bridges/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/bulk-import/route.js +2 -2
- package/.next/standalone/.next/server/app/api/bulk-import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js +3 -3
- package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/company-scores/route.js +3 -3
- package/.next/standalone/.next/server/app/api/company-scores/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/connections/route.js +2 -2
- package/.next/standalone/.next/server/app/api/connections/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/backup/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/data/backup/route/build-manifest.json +12 -0
- package/.next/standalone/.next/server/app/api/data/backup/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/data/backup/route.js +7 -0
- package/.next/standalone/.next/server/app/api/data/backup/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/data/backup/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/data/backup/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/data/csv/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/data/csv/route/build-manifest.json +12 -0
- package/.next/standalone/.next/server/app/api/data/csv/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/data/csv/route.js +8 -0
- package/.next/standalone/.next/server/app/api/data/csv/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/data/csv/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/data/csv/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/data/export/route.js +1 -1
- package/.next/standalone/.next/server/app/api/data/export/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/import/route.js +1 -1
- package/.next/standalone/.next/server/app/api/data/import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/restart/route.js +1 -1
- package/.next/standalone/.next/server/app/api/data/restart/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/restore/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/data/restore/route/build-manifest.json +12 -0
- package/.next/standalone/.next/server/app/api/data/restore/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/data/restore/route.js +7 -0
- package/.next/standalone/.next/server/app/api/data/restore/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/data/restore/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/data/restore/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/data/reveal/route.js +1 -1
- package/.next/standalone/.next/server/app/api/data/reveal/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/route.js +1 -1
- package/.next/standalone/.next/server/app/api/data/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/delete-cluster/route.js +2 -2
- package/.next/standalone/.next/server/app/api/delete-cluster/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/ingest/route.js +2 -2
- package/.next/standalone/.next/server/app/api/ingest/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/route.js +2 -2
- package/.next/standalone/.next/server/app/api/network/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/notifications/route.js +2 -2
- package/.next/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/outreach/route.js +3 -3
- package/.next/standalone/.next/server/app/api/outreach/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/queue/route.js +2 -2
- package/.next/standalone/.next/server/app/api/queue/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/scraper/route.js +5 -3
- package/.next/standalone/.next/server/app/api/scraper/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/route.js +3 -3
- package/.next/standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js +3 -3
- package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js +3 -3
- package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/setup-profile/route.js +2 -2
- package/.next/standalone/.next/server/app/api/setup-profile/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/social/crm/route.js +1 -1
- package/.next/standalone/.next/server/app/api/social/crm/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/social/messages/route.js +1 -1
- package/.next/standalone/.next/server/app/api/social/messages/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/social/route.js +2 -2
- package/.next/standalone/.next/server/app/api/social/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/unlock/route.js +2 -2
- package/.next/standalone/.next/server/app/api/unlock/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/update-images/route.js +2 -2
- package/.next/standalone/.next/server/app/api/update-images/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/users/route.js +2 -2
- package/.next/standalone/.next/server/app/api/users/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/avatars/[file]/route.js +1 -1
- package/.next/standalone/.next/server/app/avatars/[file]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/import/page.js +1 -1
- package/.next/standalone/.next/server/app/import/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/import/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/import.html +1 -1
- package/.next/standalone/.next/server/app/import.rsc +32 -24
- package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +32 -24
- package/.next/standalone/.next/server/app/import.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/import.segments/import/__PAGE__.segment.rsc +23 -18
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +29 -22
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +20 -15
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +29 -22
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/insights/page/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/insights/page/build-manifest.json +20 -0
- package/.next/standalone/.next/server/app/insights/page/next-font-manifest.json +11 -0
- package/.next/standalone/.next/server/app/insights/page/react-loadable-manifest.json +1 -0
- package/.next/standalone/.next/server/app/insights/page/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/insights/page.js +13 -0
- package/.next/standalone/.next/server/app/insights/page.js.map +5 -0
- package/.next/standalone/.next/server/app/insights/page.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/insights/page_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/insights.html +1 -0
- package/.next/standalone/.next/server/app/insights.meta +26 -0
- package/.next/standalone/.next/server/app/insights.rsc +35 -0
- package/.next/standalone/.next/server/app/insights.segments/_full.segment.rsc +35 -0
- package/.next/standalone/.next/server/app/insights.segments/_tree.segment.rsc +4 -0
- package/.next/standalone/.next/server/app/insights.segments/insights/__PAGE__.segment.rsc +33 -0
- package/.next/standalone/.next/server/app/launch/page.js +1 -1
- package/.next/standalone/.next/server/app/launch/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/launch/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/launch.html +2 -2
- package/.next/standalone/.next/server/app/launch.rsc +32 -24
- package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +32 -24
- package/.next/standalone/.next/server/app/launch.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/launch.segments/launch/__PAGE__.segment.rsc +23 -18
- package/.next/standalone/.next/server/app/page.js +1 -1
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/paths/page.js +1 -1
- package/.next/standalone/.next/server/app/paths/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/paths/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/paths.html +1 -1
- package/.next/standalone/.next/server/app/paths.rsc +32 -24
- package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +32 -24
- package/.next/standalone/.next/server/app/paths.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/paths.segments/paths/__PAGE__.segment.rsc +21 -18
- package/.next/standalone/.next/server/app/profile/page.js +1 -1
- package/.next/standalone/.next/server/app/profile/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/profile/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/profile.html +1 -1
- package/.next/standalone/.next/server/app/profile.rsc +32 -24
- package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +32 -24
- package/.next/standalone/.next/server/app/profile.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/profile.segments/profile/__PAGE__.segment.rsc +23 -18
- package/.next/standalone/.next/server/app/queue/page.js +1 -1
- package/.next/standalone/.next/server/app/queue/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/queue/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/queue.html +1 -1
- package/.next/standalone/.next/server/app/queue.rsc +32 -24
- package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +32 -24
- package/.next/standalone/.next/server/app/queue.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/queue.segments/queue/__PAGE__.segment.rsc +21 -18
- package/.next/standalone/.next/server/app/scores/page.js +1 -1
- package/.next/standalone/.next/server/app/scores/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/scores/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/scores.html +1 -1
- package/.next/standalone/.next/server/app/scores.rsc +32 -24
- package/.next/standalone/.next/server/app/scores.segments/_full.segment.rsc +32 -24
- package/.next/standalone/.next/server/app/scores.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/scores.segments/scores/__PAGE__.segment.rsc +23 -18
- package/.next/standalone/.next/server/app/settings/page.js +1 -1
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings.html +1 -1
- package/.next/standalone/.next/server/app/settings.rsc +32 -24
- package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +32 -24
- package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +20 -18
- package/.next/standalone/.next/server/app/setup/page.js +1 -1
- package/.next/standalone/.next/server/app/setup/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/setup.html +1 -1
- package/.next/standalone/.next/server/app/setup.rsc +32 -24
- package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +32 -24
- package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +21 -18
- package/.next/standalone/.next/server/app/social/page.js +1 -1
- package/.next/standalone/.next/server/app/social/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/social/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/social.html +1 -1
- package/.next/standalone/.next/server/app/social.rsc +32 -24
- package/.next/standalone/.next/server/app/social.segments/_full.segment.rsc +32 -24
- package/.next/standalone/.next/server/app/social.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/social.segments/social/__PAGE__.segment.rsc +23 -18
- package/.next/standalone/.next/server/app-paths-manifest.json +4 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__00la_y0._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__05_3-22._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__066rab1._.js +7 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__07t47cm._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cj5jqc._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e0fei3._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0fooke1._.js +7 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ljnyho._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o5-tcg._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qrnous._.js +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__15wc9e-._.js → [root-of-the-server]__0r-0t-9._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ra6xyg._.js +15 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__20rwfdw._.js → [root-of-the-server]__0rcpjad._.js} +6 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t3v1a1._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t6y79e._.js +7 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wmexuc._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0x29muh._.js +7 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0xu34sz._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__133knx1._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__15-17hl._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__19b7mig._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1a_6x37._.js +8 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1an_8pa._.js +7 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1bbcwub._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ducpz2._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1eris29._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1gjo_cq._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qcm08_._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tir0vc._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1w25q0m._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1xhyinn._.js +3 -0
- package/.next/standalone/.next/server/chunks/_072jl0y._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0lw8_i0._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0sqqpzb._.js +3 -0
- package/.next/standalone/.next/server/chunks/_1_fynia._.js +7 -7
- package/.next/standalone/.next/server/chunks/_1fn30_l._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1itd1o_._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1iwkh8t._.js +1 -1
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_backup_route_actions_0zoj04p.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_csv_route_actions_0l6m7lg.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_restore_route_actions_0-b05bv.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_02iz_9q._.js +4 -0
- package/.next/standalone/.next/server/chunks/lib_05agvk3._.js +4 -0
- package/.next/standalone/.next/server/chunks/lib_0v84u66._.js +4 -0
- package/.next/standalone/.next/server/chunks/lib_db-client_0_dch35.js +174 -0
- package/.next/standalone/.next/server/chunks/lib_linkedin-export_12imqxg.js +1 -1
- package/.next/standalone/.next/server/chunks/lib_rpc_00nndai.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_03ibb-x.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_03ri3ji.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_078ce48.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0a69mgr.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0c9d9ti.js +7 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0cej3t8.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0cmh4g6.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0nx2_pc.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0r79-w1.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0t552z6.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0yx8ynd.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_12p-o9-.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1466dnb.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1sryxv6.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1trn-x5.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1ygu_mv.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0egamyq._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qd8pzm._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0qdeuyo._.js → [root-of-the-server]__1-012q1._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_04am_h8._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_06rgzfh._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_07zb7lu._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0_79idq._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0gds903._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0hb-dhy._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0klqt9z._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_14jak5s._.js +7 -0
- package/.next/standalone/.next/server/chunks/ssr/_14nxd3q._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1cj2yog._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1fm1ih_._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_1hdqw0-._.js +7 -0
- package/.next/standalone/.next/server/chunks/ssr/_1k2nmbw._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_1r62six._.js +7 -0
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_insights_page_actions_0-0tf75.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_141w189._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_components_0uuff77._.js +25 -2
- package/.next/standalone/.next/server/chunks/ssr/app_components_1j3q-h5._.js +25 -2
- package/.next/standalone/.next/server/chunks/ssr/app_components_CompanyScores_1g0mytz.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_components_settings_SectorPicker_1c-29qw.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_components_ui_0pdmz2z.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_import_page_1fmu6_l.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_insights_page_1d_chja.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_launch_page_19t0dyd.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +26 -14
- package/.next/standalone/.next/server/chunks/ssr/app_paths_page_1ol90m7.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_profile_page_0u3-l5y.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_queue_page_0c6znd6.js +11 -11
- package/.next/standalone/.next/server/chunks/ssr/app_settings_page_1f8mjj_.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_setup_page_1-282zx.js +12 -13
- package/.next/standalone/.next/server/chunks/ssr/app_social_page_0h7zxda.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{lib_1c4ieuw._.js → lib_csv_1ttiu_h.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/lib_galaxy-lab_108_lu-.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/lib_separation_1305zsx.js +3 -0
- package/.next/standalone/.next/server/edge/chunks/[root-of-the-server]__0pco7a6._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/middleware-manifest.json +5 -5
- package/.next/standalone/.next/server/next-font-manifest.js +1 -1
- package/.next/standalone/.next/server/next-font-manifest.json +4 -0
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/prefetch-hints.json +14 -0
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/02wnf8dkxegxg.js +34 -0
- package/.next/standalone/.next/static/chunks/03-_esd2x_yk6.js +1 -0
- package/.next/standalone/.next/static/chunks/03-demj2iy-0p.js +44 -0
- package/.next/standalone/.next/static/chunks/0838_s6w-i_ik.js +1 -0
- package/.next/standalone/.next/static/chunks/0_1r-3csplxnj.js +1 -0
- package/.next/standalone/.next/static/chunks/0ka4prpk3w9wn.js +34 -0
- package/.next/standalone/.next/static/chunks/0kscsqnvfq3-r.js +1 -0
- package/.next/standalone/.next/static/chunks/0s_xxwp7z88vv.js +1 -0
- package/.next/standalone/.next/static/chunks/1-nnl8amfm4yh.js +57 -0
- package/.next/standalone/.next/static/chunks/112mv-com-mqa.js +21 -0
- package/.next/standalone/.next/static/chunks/1bkt_hhjzvbh8.js +1 -0
- package/.next/standalone/.next/static/chunks/1cmphb3kh2ers.css +3 -0
- package/.next/standalone/.next/static/chunks/1d8yv3k_atka7.js +1 -0
- package/.next/standalone/.next/static/chunks/{0ws7zy0w57ufi.js → 1eyajb9ntzlrl.js} +1 -1
- package/.next/standalone/.next/static/chunks/1z9lb-dbcg4aa.js +1 -0
- package/.next/standalone/.next/static/chunks/23hc51oa4vkhc.js +5 -0
- package/.next/standalone/.next/static/chunks/27n8k9wxlz5-7.js +1 -0
- package/.next/standalone/.next/static/chunks/2q9i7pcxcnph1.js +7 -0
- package/.next/standalone/.next/static/chunks/2w-y83mjlpnse.js +1 -0
- package/.next/standalone/.next/static/chunks/2ws1xf293j-tm.js +5 -0
- package/.next/standalone/.next/static/chunks/2z1-q0_vunbql.js +2 -0
- package/.next/standalone/.next/static/chunks/34g73qhayuevu.js +1 -0
- package/.next/standalone/.next/static/chunks/3cqn-r-y5rrw1.js +5 -0
- package/.next/standalone/.next/static/chunks/3opgg1efrx8q6.js +1 -0
- package/.next/standalone/.next/static/chunks/3p51fpxxi4d5y.js +34 -0
- package/.next/standalone/.next/static/chunks/3y40z6of3r9py.js +1 -0
- package/.next/standalone/.next/static/chunks/403dpflln8ah5.js +1 -0
- package/.next/standalone/.next/static/chunks/43pg2sursiypz.js +1 -0
- package/.next/standalone/CHANGELOG.md +203 -0
- package/.next/standalone/README.md +96 -50
- package/.next/standalone/SECURITY.md +25 -11
- package/.next/standalone/app/api/data/backup/route.js +25 -0
- package/.next/standalone/app/api/data/csv/route.js +74 -0
- package/.next/standalone/app/api/data/export/route.js +1 -1
- package/.next/standalone/app/api/data/restore/route.js +48 -0
- package/.next/standalone/app/api/data/reveal/route.js +19 -6
- package/.next/standalone/app/api/data/route.js +15 -4
- package/.next/standalone/app/api/ingest/route.js +1 -1
- package/.next/standalone/app/api/outreach/route.js +13 -73
- package/.next/standalone/app/api/queue/route.js +1 -1
- package/.next/standalone/app/api/scraper/route.js +217 -36
- package/.next/standalone/app/api/social/crm/route.js +2 -1
- package/.next/standalone/app/components/AppHeader.js +41 -21
- package/.next/standalone/app/components/AppTabs.js +12 -8
- package/.next/standalone/app/components/AutoConnect.js +286 -0
- package/.next/standalone/app/components/AutoScanButton.js +2 -2
- package/.next/standalone/app/components/Avatar.js +1 -1
- package/.next/standalone/app/components/ChainView.js +258 -113
- package/.next/standalone/app/components/CirclePanel.js +16 -16
- package/.next/standalone/app/components/ClusterSpinner.js +64 -0
- package/.next/standalone/app/components/CompanyScores.js +20 -20
- package/.next/standalone/app/components/EmptyState.js +39 -18
- package/.next/standalone/app/components/FieldStep.js +15 -13
- package/.next/standalone/app/components/FilterPanel.js +25 -18
- package/.next/standalone/app/components/ForceGraph.js +49 -14
- package/.next/standalone/app/components/GalaxyLab.js +33 -33
- package/.next/standalone/app/components/GridView.js +18 -18
- package/.next/standalone/app/components/LegacyScoresCard.js +10 -11
- package/.next/standalone/app/components/LinkedInLimits.js +57 -27
- package/.next/standalone/app/components/LiquidGlass.js +99 -0
- package/.next/standalone/app/components/ListView.js +20 -20
- package/.next/standalone/app/components/MapControls.js +5 -5
- package/.next/standalone/app/components/MappingProgress.js +16 -16
- package/.next/standalone/app/components/NoteDetail.js +13 -13
- package/.next/standalone/app/components/OnboardingGate.js +4 -4
- package/.next/standalone/app/components/OutlinkQuest.js +56 -35
- package/.next/standalone/app/components/PathsAnalyzer.js +37 -36
- package/.next/standalone/app/components/PeopleMap.js +21 -21
- package/.next/standalone/app/components/RingsView.js +11 -11
- package/.next/standalone/app/components/ScanRadar.js +84 -39
- package/.next/standalone/app/components/ScanStatusBar.js +40 -21
- package/.next/standalone/app/components/ScanTrail.js +21 -8
- package/.next/standalone/app/components/SeparationView.js +172 -124
- package/.next/standalone/app/components/Sidebar.js +308 -199
- package/.next/standalone/app/components/StaleServerBanner.js +4 -4
- package/.next/standalone/app/components/TheirCircle.js +26 -26
- package/.next/standalone/app/components/ThemeDefs.js +42 -0
- package/.next/standalone/app/components/ThemeLoader.js +20 -1
- package/.next/standalone/app/components/UpdatePanel.js +22 -22
- package/.next/standalone/app/components/UserProvider.js +22 -15
- package/.next/standalone/app/components/insights/Boards.js +275 -0
- package/.next/standalone/app/components/insights/PeopleView.js +266 -0
- package/.next/standalone/app/components/insights/Rail.js +156 -0
- package/.next/standalone/app/components/insights/Report.js +382 -0
- package/.next/standalone/app/components/insights/parts.js +239 -0
- package/.next/standalone/app/components/settings/AppearanceSection.js +47 -24
- package/.next/standalone/app/components/settings/DataSection.js +276 -109
- package/.next/standalone/app/components/settings/NetworkHealthSection.js +13 -13
- package/.next/standalone/app/components/settings/SectorPicker.js +12 -12
- package/.next/standalone/app/components/settings/SectorSection.js +13 -14
- package/.next/standalone/app/components/settings/TierSection.js +9 -9
- package/.next/standalone/app/components/settings/TitleSection.js +11 -11
- package/.next/standalone/app/components/settings/UsageSection.js +360 -0
- package/.next/standalone/app/components/ui.js +8 -8
- package/.next/standalone/app/globals.css +161 -5
- package/.next/standalone/app/import/page.js +94 -38
- package/.next/standalone/app/insights/page.js +220 -0
- package/.next/standalone/app/launch/page.js +5 -5
- package/.next/standalone/app/layout.js +6 -2
- package/.next/standalone/app/page.js +53 -53
- package/.next/standalone/app/paths/page.js +63 -63
- package/.next/standalone/app/profile/page.js +58 -58
- package/.next/standalone/app/queue/page.js +84 -72
- package/.next/standalone/app/scores/page.js +2 -2
- package/.next/standalone/app/settings/page.js +16 -13
- package/.next/standalone/app/setup/page.js +236 -133
- package/.next/standalone/app/social/Crm.js +63 -62
- package/.next/standalone/app/social/SocialHub.js +22 -22
- package/.next/standalone/app/social/Thread.js +7 -7
- package/.next/standalone/app/social/page.js +2 -2
- package/.next/standalone/lib/auto-connect.js +145 -0
- package/.next/standalone/lib/backups.js +458 -0
- package/.next/standalone/lib/chain-layout.js +32 -0
- package/.next/standalone/lib/companies.js +1 -1
- package/.next/standalone/lib/csv-store.js +131 -0
- package/.next/standalone/lib/csv.js +137 -39
- package/.next/standalone/lib/data-folder.js +19 -3
- package/.next/standalone/lib/data-import.js +5 -2
- package/.next/standalone/lib/db-client.js +78 -20
- package/.next/standalone/lib/demo.js +5 -4
- package/.next/standalone/lib/galaxy-export.js +9 -2
- package/.next/standalone/lib/galaxy-lab.js +19 -5
- package/.next/standalone/lib/galaxy-layouts.js +43 -0
- package/.next/standalone/lib/gate.js +10 -4
- package/.next/standalone/lib/in-progress.js +46 -0
- package/.next/standalone/lib/ingest.js +1 -1
- package/.next/standalone/lib/insights-board.js +613 -0
- package/.next/standalone/lib/linkedin-limits.js +240 -14
- package/.next/standalone/lib/liquid-glass.js +59 -0
- package/.next/standalone/lib/notifications.js +13 -0
- package/.next/standalone/lib/requests-client.js +10 -0
- package/.next/standalone/lib/requests.js +124 -0
- package/.next/standalone/lib/scan-pace.js +11 -0
- package/.next/standalone/lib/scan-progress.js +20 -0
- package/.next/standalone/lib/scan-risk.js +44 -0
- package/.next/standalone/lib/scan-state.js +1 -0
- package/.next/standalone/lib/scanner-setup.js +97 -15
- package/.next/standalone/lib/scraper-client.js +35 -8
- package/.next/standalone/lib/search-risk.js +7 -3
- package/.next/standalone/lib/settings-client.js +5 -3
- package/.next/standalone/lib/settings.js +13 -0
- package/.next/standalone/lib/social-store.js +3 -2
- package/.next/standalone/lib/synced-setting.js +46 -0
- package/.next/standalone/lib/theme-store.js +42 -10
- package/.next/standalone/lib/themes.js +111 -21
- package/.next/standalone/lib/usage.js +200 -0
- package/.next/standalone/package-lock.json +2 -2
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/scripts/scrape.py +595 -11
- package/.next/static/chunks/02wnf8dkxegxg.js +34 -0
- package/.next/static/chunks/03-_esd2x_yk6.js +1 -0
- package/.next/static/chunks/03-demj2iy-0p.js +44 -0
- package/.next/static/chunks/0838_s6w-i_ik.js +1 -0
- package/.next/static/chunks/0_1r-3csplxnj.js +1 -0
- package/.next/static/chunks/0ka4prpk3w9wn.js +34 -0
- package/.next/static/chunks/0kscsqnvfq3-r.js +1 -0
- package/.next/static/chunks/0s_xxwp7z88vv.js +1 -0
- package/.next/static/chunks/1-nnl8amfm4yh.js +57 -0
- package/.next/static/chunks/112mv-com-mqa.js +21 -0
- package/.next/static/chunks/1bkt_hhjzvbh8.js +1 -0
- package/.next/static/chunks/1cmphb3kh2ers.css +3 -0
- package/.next/static/chunks/1d8yv3k_atka7.js +1 -0
- package/.next/static/chunks/{0ws7zy0w57ufi.js → 1eyajb9ntzlrl.js} +1 -1
- package/.next/static/chunks/1z9lb-dbcg4aa.js +1 -0
- package/.next/static/chunks/23hc51oa4vkhc.js +5 -0
- package/.next/static/chunks/27n8k9wxlz5-7.js +1 -0
- package/.next/static/chunks/2q9i7pcxcnph1.js +7 -0
- package/.next/static/chunks/2w-y83mjlpnse.js +1 -0
- package/.next/static/chunks/2ws1xf293j-tm.js +5 -0
- package/.next/static/chunks/2z1-q0_vunbql.js +2 -0
- package/.next/static/chunks/34g73qhayuevu.js +1 -0
- package/.next/static/chunks/3cqn-r-y5rrw1.js +5 -0
- package/.next/static/chunks/3opgg1efrx8q6.js +1 -0
- package/.next/static/chunks/3p51fpxxi4d5y.js +34 -0
- package/.next/static/chunks/3y40z6of3r9py.js +1 -0
- package/.next/static/chunks/403dpflln8ah5.js +1 -0
- package/.next/static/chunks/43pg2sursiypz.js +1 -0
- package/CHANGELOG.md +203 -0
- package/README.md +96 -50
- package/SECURITY.md +25 -11
- package/lib/auto-connect.js +145 -0
- package/lib/backups.js +458 -0
- package/lib/chain-layout.js +32 -0
- package/lib/companies.js +1 -1
- package/lib/csv-store.js +131 -0
- package/lib/csv.js +137 -39
- package/lib/data-folder.js +19 -3
- package/lib/data-import.js +5 -2
- package/lib/db-client.js +78 -20
- package/lib/demo.js +5 -4
- package/lib/galaxy-export.js +9 -2
- package/lib/galaxy-lab.js +19 -5
- package/lib/galaxy-layouts.js +43 -0
- package/lib/gate.js +10 -4
- package/lib/in-progress.js +46 -0
- package/lib/ingest.js +1 -1
- package/lib/insights-board.js +613 -0
- package/lib/linkedin-limits.js +240 -14
- package/lib/liquid-glass.js +59 -0
- package/lib/notifications.js +13 -0
- package/lib/requests-client.js +10 -0
- package/lib/requests.js +124 -0
- package/lib/scan-pace.js +11 -0
- package/lib/scan-progress.js +20 -0
- package/lib/scan-risk.js +44 -0
- package/lib/scan-state.js +1 -0
- package/lib/scanner-setup.js +97 -15
- package/lib/scraper-client.js +35 -8
- package/lib/search-risk.js +7 -3
- package/lib/settings-client.js +5 -3
- package/lib/settings.js +13 -0
- package/lib/social-store.js +3 -2
- package/lib/synced-setting.js +46 -0
- package/lib/theme-store.js +42 -10
- package/lib/themes.js +111 -21
- package/lib/usage.js +200 -0
- package/package.json +1 -1
- package/scripts/scrape.py +595 -11
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-rnla2._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__13dx4sd._.js +0 -8
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__14ou7j5._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__16iu0hv._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1kbl21f._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rphsdk._.js +0 -3
- package/.next/standalone/.next/server/chunks/_02twlca._.js +0 -10
- package/.next/standalone/.next/server/chunks/lib_0851sk0._.js +0 -8
- package/.next/standalone/.next/server/chunks/lib_1q7p2ro._.js +0 -8
- package/.next/standalone/.next/server/chunks/lib_1r6l86l._.js +0 -8
- package/.next/standalone/.next/server/chunks/lib_db-client_15le7cw.js +0 -174
- package/.next/standalone/.next/server/chunks/lib_rpc_04s8mzr.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_053z7as.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0b_-2te.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0dhbxdm.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0dxlk31.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0f8b-qc.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0pzie7_.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0r76fq_.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0ut7pjp.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_15zyqaz.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_18zpjtq.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1a8xkiz.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1e_55xo.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1oxfd1_.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1s0lod0.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__08oxiqh._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_03l7vge._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_08g31gm._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0gk_ofx._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0nwsf93._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0vho1lb._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1-658fq._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1bc46kz._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1f_n00p._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_2105jz8._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/app_components_0t908t-._.js +0 -3
- package/.next/standalone/.next/static/chunks/02pq76u7y4v9-.js +0 -22
- package/.next/standalone/.next/static/chunks/0cmq0exd4d0h9.js +0 -1
- package/.next/standalone/.next/static/chunks/0i02yxppzds1o.js +0 -1
- package/.next/standalone/.next/static/chunks/0m_p4k-q2qh--.js +0 -1
- package/.next/standalone/.next/static/chunks/0oyslj62jkubd.js +0 -1
- package/.next/standalone/.next/static/chunks/0vo-l8hxneba6.css +0 -3
- package/.next/standalone/.next/static/chunks/0yh8z2tbrc5i_.js +0 -1
- package/.next/standalone/.next/static/chunks/17-rhp8sg4m1b.js +0 -44
- package/.next/standalone/.next/static/chunks/172e10mi-tpo_.js +0 -34
- package/.next/standalone/.next/static/chunks/1ei5vbe2uw6fl.js +0 -1
- package/.next/standalone/.next/static/chunks/1f7_pl_wq7lh3.js +0 -11
- package/.next/standalone/.next/static/chunks/1jzbe7zdx9vbj.js +0 -2
- package/.next/standalone/.next/static/chunks/1m3017gp790pw.js +0 -45
- package/.next/standalone/.next/static/chunks/1t20e8u0st7ep.js +0 -1
- package/.next/standalone/.next/static/chunks/2-ch9rm27eril.js +0 -11
- package/.next/standalone/.next/static/chunks/2ldv-v3s9yaif.js +0 -1
- package/.next/standalone/.next/static/chunks/3bp284gjf7dyq.js +0 -1
- package/.next/standalone/.next/static/chunks/3k1f6clbn3gj3.js +0 -7
- package/.next/standalone/.next/static/chunks/3l4t8je6iguzc.js +0 -1
- package/.next/standalone/.next/static/chunks/3tplzuc9jk-tl.js +0 -1
- package/.next/standalone/.next/static/chunks/42m0bqr8pbovz.js +0 -11
- package/.next/static/chunks/02pq76u7y4v9-.js +0 -22
- package/.next/static/chunks/0cmq0exd4d0h9.js +0 -1
- package/.next/static/chunks/0i02yxppzds1o.js +0 -1
- package/.next/static/chunks/0m_p4k-q2qh--.js +0 -1
- package/.next/static/chunks/0oyslj62jkubd.js +0 -1
- package/.next/static/chunks/0vo-l8hxneba6.css +0 -3
- package/.next/static/chunks/0yh8z2tbrc5i_.js +0 -1
- package/.next/static/chunks/17-rhp8sg4m1b.js +0 -44
- package/.next/static/chunks/172e10mi-tpo_.js +0 -34
- package/.next/static/chunks/1ei5vbe2uw6fl.js +0 -1
- package/.next/static/chunks/1f7_pl_wq7lh3.js +0 -11
- package/.next/static/chunks/1jzbe7zdx9vbj.js +0 -2
- package/.next/static/chunks/1m3017gp790pw.js +0 -45
- package/.next/static/chunks/1t20e8u0st7ep.js +0 -1
- package/.next/static/chunks/2-ch9rm27eril.js +0 -11
- package/.next/static/chunks/2ldv-v3s9yaif.js +0 -1
- package/.next/static/chunks/3bp284gjf7dyq.js +0 -1
- package/.next/static/chunks/3k1f6clbn3gj3.js +0 -7
- package/.next/static/chunks/3l4t8je6iguzc.js +0 -1
- package/.next/static/chunks/3tplzuc9jk-tl.js +0 -1
- package/.next/static/chunks/42m0bqr8pbovz.js +0 -11
- /package/.next/standalone/.next/static/{dQUvvVSXqbkEFC3-CNcwT → 3NCyJyAPDCEYsYTwF1Ieu}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{dQUvvVSXqbkEFC3-CNcwT → 3NCyJyAPDCEYsYTwF1Ieu}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{dQUvvVSXqbkEFC3-CNcwT → 3NCyJyAPDCEYsYTwF1Ieu}/_ssgManifest.js +0 -0
- /package/.next/static/{dQUvvVSXqbkEFC3-CNcwT → 3NCyJyAPDCEYsYTwF1Ieu}/_buildManifest.js +0 -0
- /package/.next/static/{dQUvvVSXqbkEFC3-CNcwT → 3NCyJyAPDCEYsYTwF1Ieu}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{dQUvvVSXqbkEFC3-CNcwT → 3NCyJyAPDCEYsYTwF1Ieu}/_ssgManifest.js +0 -0
package/scripts/scrape.py
CHANGED
|
@@ -19,6 +19,7 @@ Usage:
|
|
|
19
19
|
python3 scripts/scrape.py --auto-bridge --tiers=S,A --max-bridges=10
|
|
20
20
|
python3 scripts/scrape.py --rescrape "Name" # Delete + re-scrape a bridge
|
|
21
21
|
python3 scripts/scrape.py --auto-bridge --deeper # ...and finish lists read only partly
|
|
22
|
+
python3 scripts/scrape.py --connect URL # Auto: one connection request, no note
|
|
22
23
|
|
|
23
24
|
IMPORTANT: Only scrape ONE bridge at a time. Do NOT batch multiple bridges
|
|
24
25
|
in one session — LinkedIn detects automation and flags your account.
|
|
@@ -227,6 +228,19 @@ MAX_SCROLL_ROUNDS = 400 # ~10 people load per round
|
|
|
227
228
|
SCROLL_PAUSE_SECONDS = 0.9
|
|
228
229
|
SCROLL_STALL_LIMIT = 10 # rounds with no new names before stopping
|
|
229
230
|
LOGIN_POLL_SECONDS = 2
|
|
231
|
+
# The Scan page's "Signed in" (lib/scanner-setup.js SIGNED_IN_FILE, which a
|
|
232
|
+
# test keeps the same): true once the session is confirmed below, false while
|
|
233
|
+
# a sign-in is awaited. It went by Chrome's cookie file, which exists as soon
|
|
234
|
+
# as this window first opens, so closing it without signing in ticked the step.
|
|
235
|
+
SIGNED_IN_FILE = "signed-in.json"
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def _note_signed_in(ok):
|
|
239
|
+
"""Write down for the Scan page whether LinkedIn's session is confirmed. Only a note: never stops a run."""
|
|
240
|
+
try:
|
|
241
|
+
_write_json_atomic(_home() / SIGNED_IN_FILE, {"signedIn": bool(ok), "at": time.time()})
|
|
242
|
+
except Exception as exc:
|
|
243
|
+
print(f" (could not note the sign-in for the Scan page: {exc})")
|
|
230
244
|
|
|
231
245
|
|
|
232
246
|
def _has_session_cookie(target):
|
|
@@ -345,8 +359,10 @@ def ensure_logged_in(page, timeout_s=LOGIN_WAIT_SECONDS, log_fn=None, stop_on_ch
|
|
|
345
359
|
raise LinkedInPushedBack(0, reason)
|
|
346
360
|
|
|
347
361
|
if _has_session_cookie(context) and not _looks_logged_out(page) and not wall:
|
|
362
|
+
_note_signed_in(True)
|
|
348
363
|
return True
|
|
349
364
|
|
|
365
|
+
_note_signed_in(False)
|
|
350
366
|
say = log_fn or (lambda m: None)
|
|
351
367
|
if had_session and wall == "checkpoint":
|
|
352
368
|
print()
|
|
@@ -356,7 +372,10 @@ def ensure_logged_in(page, timeout_s=LOGIN_WAIT_SECONDS, log_fn=None, stop_on_ch
|
|
|
356
372
|
say("Waiting for you to finish LinkedIn's security check...")
|
|
357
373
|
else:
|
|
358
374
|
_print_sign_in_banner(say)
|
|
359
|
-
|
|
375
|
+
ok = _wait_for_sign_in(page, context, timeout_s, say)
|
|
376
|
+
if ok:
|
|
377
|
+
_note_signed_in(True)
|
|
378
|
+
return ok
|
|
360
379
|
|
|
361
380
|
|
|
362
381
|
def _print_sign_in_banner(say):
|
|
@@ -1407,16 +1426,26 @@ def note_unclear(profile_url, clear=False):
|
|
|
1407
1426
|
# profile in the app: three app profiles must not triple the budget. The app's
|
|
1408
1427
|
# Scan page reads and edits the same files (lib/linkedin-limits.js).
|
|
1409
1428
|
#
|
|
1410
|
-
# linkedin-activity.json {"searches": [epoch s, ...], "profiles": [...]
|
|
1429
|
+
# linkedin-activity.json {"searches": [epoch s, ...], "profiles": [...],
|
|
1430
|
+
# "invites": [...]} Auto's connection requests (--connect)
|
|
1411
1431
|
# scan-limits.json {"daily": 50, "monthly": 250, "profiles": 50}
|
|
1412
1432
|
# 0 = no cap on searches; profile views always have one
|
|
1413
1433
|
# linkedin-cooldown.json {"until": epoch s, "reason": "...", "set_at": ...}
|
|
1434
|
+
# lifted on the Scan page: "until" is when, plus
|
|
1435
|
+
# "lifted_at" and "was_until"; read here as ended
|
|
1414
1436
|
# ---------------------------------------------------------------------------
|
|
1415
1437
|
DEFAULT_DAILY_SEARCHES = 50
|
|
1416
1438
|
DEFAULT_MONTHLY_SEARCHES = 250
|
|
1417
1439
|
DEFAULT_DAILY_PROFILES = 50
|
|
1418
1440
|
PROFILE_GAP = 60 # seconds between any two profile opens, whatever opened them
|
|
1419
1441
|
DAY_SECONDS = 24 * 3600
|
|
1442
|
+
WEEK_SECONDS = 7 * DAY_SECONDS
|
|
1443
|
+
# Auto's connection requests (--connect), in any 24 hours and any 7 days. The
|
|
1444
|
+
# app shows and enforces the same two (lib/auto-connect.js INVITE_CAPS; a test
|
|
1445
|
+
# checks they match). LinkedIn doesn't publish its invitation limit; people
|
|
1446
|
+
# commonly report about 100 a week, so the week stays well under it.
|
|
1447
|
+
INVITE_DAY_CAP = 15
|
|
1448
|
+
INVITE_WEEK_CAP = 80
|
|
1420
1449
|
PACIFIC = "America/Los_Angeles"
|
|
1421
1450
|
|
|
1422
1451
|
|
|
@@ -1497,9 +1526,10 @@ def _read_activity():
|
|
|
1497
1526
|
if not isinstance(data, dict):
|
|
1498
1527
|
raise ValueError("not an object")
|
|
1499
1528
|
return {"searches": [float(x) for x in data.get("searches", [])],
|
|
1500
|
-
"profiles": [float(x) for x in data.get("profiles", [])]
|
|
1529
|
+
"profiles": [float(x) for x in data.get("profiles", [])],
|
|
1530
|
+
"invites": [float(x) for x in data.get("invites", [])]}
|
|
1501
1531
|
except FileNotFoundError:
|
|
1502
|
-
return {"searches": [], "profiles": []}
|
|
1532
|
+
return {"searches": [], "profiles": [], "invites": []}
|
|
1503
1533
|
except Exception:
|
|
1504
1534
|
# Kept aside, and replaced by a record that says today's budget is used —
|
|
1505
1535
|
# written, so it holds for the whole day rather than one check. (Failing
|
|
@@ -1511,7 +1541,8 @@ def _read_activity():
|
|
|
1511
1541
|
pass
|
|
1512
1542
|
print(" (the record of LinkedIn searches couldn't be read; counting today as used)")
|
|
1513
1543
|
lim = search_limits()
|
|
1514
|
-
fresh = {"searches": [now] * max(1, lim["daily"] or 1), "profiles": [now] * lim["profiles"]
|
|
1544
|
+
fresh = {"searches": [now] * max(1, lim["daily"] or 1), "profiles": [now] * lim["profiles"],
|
|
1545
|
+
"invites": [now] * INVITE_DAY_CAP}
|
|
1515
1546
|
try:
|
|
1516
1547
|
_write_json_atomic(path, fresh)
|
|
1517
1548
|
except Exception:
|
|
@@ -1520,7 +1551,7 @@ def _read_activity():
|
|
|
1520
1551
|
|
|
1521
1552
|
|
|
1522
1553
|
def charge_linkedin(kind="searches", n=1):
|
|
1523
|
-
"""Write down n searches (or profile views) made just now."""
|
|
1554
|
+
"""Write down n searches (or profile views, or connection requests) made just now."""
|
|
1524
1555
|
with _Locked("linkedin-activity"):
|
|
1525
1556
|
_charge(_read_activity(), kind, n, time.time())
|
|
1526
1557
|
|
|
@@ -1528,9 +1559,9 @@ def charge_linkedin(kind="searches", n=1):
|
|
|
1528
1559
|
def _charge(data, kind, n, now):
|
|
1529
1560
|
"""Add n of `kind` at `now` to the record and write it. The caller holds the lock."""
|
|
1530
1561
|
keep_from = month_start_pacific(now) - 32 * DAY_SECONDS
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
data[
|
|
1562
|
+
for each in ("searches", "profiles", "invites"):
|
|
1563
|
+
data[each] = [t for t in data.get(each, []) if t >= keep_from]
|
|
1564
|
+
data[kind] = data.get(kind, []) + [now] * n
|
|
1534
1565
|
try:
|
|
1535
1566
|
_write_json_atomic(_home() / "linkedin-activity.json", data)
|
|
1536
1567
|
except Exception as exc:
|
|
@@ -3376,7 +3407,11 @@ def scrape_bridge(bridge_name, headless=False, max_pages=LINKEDIN_MAX_PAGES, dee
|
|
|
3376
3407
|
raise SearchLimitReached(len(read))
|
|
3377
3408
|
if reach.get("pushed_back"):
|
|
3378
3409
|
why = reach.get("pushback_reason") or "a page that would not open"
|
|
3379
|
-
|
|
3410
|
+
# Auto scan rests two days after any check from LinkedIn, as the Scan
|
|
3411
|
+
# page promises and AUTO_PUSHBACK_REST says; a pushback partway through
|
|
3412
|
+
# a list used to rest it one day, like a scan you start yourself.
|
|
3413
|
+
set_cooldown(seconds=AUTO_PUSHBACK_REST if EXPERIMENT["on"] else DAY_SECONDS,
|
|
3414
|
+
reason=f"LinkedIn pushed back: {why}")
|
|
3380
3415
|
raise LinkedInPushedBack(len(read), why)
|
|
3381
3416
|
if reach.get("budget"):
|
|
3382
3417
|
raise BudgetReached(len(read), reach["budget"])
|
|
@@ -4109,6 +4144,529 @@ def rescrape_bridge(bridge_name, headless=False, max_pages=LINKEDIN_MAX_PAGES):
|
|
|
4109
4144
|
scrape_bridge(bridge_name, headless=headless, max_pages=max_pages, fresh=True)
|
|
4110
4145
|
|
|
4111
4146
|
|
|
4147
|
+
# ---------------------------------------------------------------------------
|
|
4148
|
+
# Auto: one connection request, for the person whose Auto was pressed (--connect)
|
|
4149
|
+
# ---------------------------------------------------------------------------
|
|
4150
|
+
# Blake, 2026-10-03: "auto add and basically adds the person for them in the
|
|
4151
|
+
# card or wherever its available ... sometimes when adding it'll prompt the user
|
|
4152
|
+
# to have a email from their work or to send a personal note if they have
|
|
4153
|
+
# premium so if thats the case then have it close out of that in the scanner
|
|
4154
|
+
# for adding but it should be seamless."
|
|
4155
|
+
#
|
|
4156
|
+
# This is the one thing the scanner ever does on LinkedIn besides reading, and
|
|
4157
|
+
# only because a person pressed Auto on one card: one person per run, never a
|
|
4158
|
+
# batch, never on a timer. It is openly slow like everything else here: fixed
|
|
4159
|
+
# waits, a profile view taken like any other (cap and gap), no "human" timing
|
|
4160
|
+
# and no mouse movement made up to look like someone (Blake's standing scanner
|
|
4161
|
+
# boundary). The app looks the person up by id and refuses first (cooldown,
|
|
4162
|
+
# caps, already connected or requested; app/api/scraper/route.js); this checks
|
|
4163
|
+
# the cooldown and the caps again before anything opens.
|
|
4164
|
+
#
|
|
4165
|
+
# How it finds things, without a CSS class (TRAPS §5): by role and accessible
|
|
4166
|
+
# name, the way a screen reader would. Their Connect is a button (or link, or
|
|
4167
|
+
# menu item) labelled "Invite <their name> to connect"; the name must be theirs,
|
|
4168
|
+
# word for word, because the same page lists other people with Connect buttons
|
|
4169
|
+
# of their own ("People also viewed"). When it isn't on the front of their
|
|
4170
|
+
# profile, it is under "More". A bare "Connect" with no name is only taken from
|
|
4171
|
+
# that menu, and only when the menu is what brought it on screen: on the page
|
|
4172
|
+
# itself, a nameless Connect could be anyone's.
|
|
4173
|
+
#
|
|
4174
|
+
# What LinkedIn asks next is answered like this:
|
|
4175
|
+
# a note? "Send without a note", or the only Send there is
|
|
4176
|
+
# a personal note (Premium) the same: never a note, never Premium
|
|
4177
|
+
# their email address closed, nothing sent ("email-needed")
|
|
4178
|
+
# its invitation limit closed, nothing sent ("linkedin-limit")
|
|
4179
|
+
# anything else closed, nothing sent ("not-sent")
|
|
4180
|
+
# It is "sent" only when their profile then shows it Pending (or LinkedIn says
|
|
4181
|
+
# the invitation to them was sent). Anything else after pressing Send is
|
|
4182
|
+
# "unclear", and the app doesn't mark it as sent: never a confident wrong answer
|
|
4183
|
+
# (TRAPS §7). A security check or a sign-in wall is LinkedIn pushing back, as in
|
|
4184
|
+
# every other run: the page is kept, everything pauses for a day, and it stops.
|
|
4185
|
+
#
|
|
4186
|
+
# None of this has been run against LinkedIn's real page: the labels above are
|
|
4187
|
+
# what LinkedIn is known to use, and tests/auto-connect.test.mjs runs it against
|
|
4188
|
+
# a stand-in page. Watch the first real one.
|
|
4189
|
+
|
|
4190
|
+
CONNECT_LOAD_ATTEMPTS = 6 # looks for their profile to render, CONNECT_LOAD_STEP apart
|
|
4191
|
+
CONNECT_LOAD_STEP = 5 # seconds
|
|
4192
|
+
CONNECT_STEP = 1 # seconds between looks for LinkedIn's answer
|
|
4193
|
+
DIALOG_WAIT = 10 # seconds to wait for the invitation window after Connect
|
|
4194
|
+
CONFIRM_WAIT = 12 # seconds to wait for Pending after Send
|
|
4195
|
+
|
|
4196
|
+
# Every result a run can end with, printed as "Connect result: <name>" for the
|
|
4197
|
+
# app (lib/auto-connect.js OUTCOMES has the same names and their words; a test
|
|
4198
|
+
# checks the two lists match).
|
|
4199
|
+
CONNECT_RESULTS = (
|
|
4200
|
+
"sent", "already-pending", "email-needed", "no-connect", "not-sent", "unclear", "not-loaded",
|
|
4201
|
+
"unavailable", "linkedin-limit", "pushback", "stopped", "not-signed-in", "cooldown",
|
|
4202
|
+
"invites-day", "invites-week", "profiles", "not-found",
|
|
4203
|
+
)
|
|
4204
|
+
|
|
4205
|
+
ACTION_ROLES = ("button", "link", "menuitem")
|
|
4206
|
+
INVITE_LABEL = re.compile(r"^\s*Invite\s+(.+?)\s+to\s+connect\s*$", re.I)
|
|
4207
|
+
PENDING_LABEL = re.compile(r"^\s*Pending\b", re.I)
|
|
4208
|
+
BARE_CONNECT = re.compile(r"^\s*Connect\s*$", re.I)
|
|
4209
|
+
BARE_PENDING = re.compile(r"^\s*Pending\s*$", re.I)
|
|
4210
|
+
MORE_LABEL = re.compile(r"^\s*More( actions)?\s*$", re.I)
|
|
4211
|
+
SEND_PLAIN = re.compile(r"^\s*Send without a note\s*$", re.I)
|
|
4212
|
+
SEND_ANY = re.compile(r"^\s*Send( now| invitation)?\s*$", re.I)
|
|
4213
|
+
CLOSE_LABEL = re.compile(r"^\s*(Dismiss|Close|Cancel|Got it|Not now)\s*$", re.I)
|
|
4214
|
+
EMAIL_BOX = re.compile(r"e-?mail", re.I)
|
|
4215
|
+
EMAIL_ASK = re.compile(r"enter (their|his|her|the member.?s) e-?mail|e-?mail( address)? to connect|knows you.{0,60}e-?mail", re.I)
|
|
4216
|
+
INVITE_LIMIT = re.compile(r"invitation limit|reached the (weekly )?limit|too many (pending )?invitations", re.I)
|
|
4217
|
+
PREMIUM_NOTE = re.compile(r"premium|personali[sz]ed (invitation|note)", re.I)
|
|
4218
|
+
SENT_NOTICE = re.compile(r"invitation to (.+?) (?:was|has been) sent", re.I)
|
|
4219
|
+
|
|
4220
|
+
|
|
4221
|
+
def invites_left(now=None):
|
|
4222
|
+
"""(how many more requests Auto may send, "day" | "week": whichever runs out first)."""
|
|
4223
|
+
now = now if now is not None else time.time()
|
|
4224
|
+
invites = _read_activity()["invites"]
|
|
4225
|
+
day = INVITE_DAY_CAP - sum(1 for t in invites if t > now - DAY_SECONDS)
|
|
4226
|
+
week = INVITE_WEEK_CAP - sum(1 for t in invites if t > now - WEEK_SECONDS)
|
|
4227
|
+
return (max(0, day), "day") if day <= week else (max(0, week), "week")
|
|
4228
|
+
|
|
4229
|
+
|
|
4230
|
+
def take_invite(now=None):
|
|
4231
|
+
"""Write down one connection request about to be sent, if the caps allow one.
|
|
4232
|
+
|
|
4233
|
+
None once it is written down; "day" or "week" when that cap is reached and
|
|
4234
|
+
nothing was written. The check and the write are one step under the lock.
|
|
4235
|
+
"""
|
|
4236
|
+
with _Locked("linkedin-activity"):
|
|
4237
|
+
now = now if now is not None else time.time()
|
|
4238
|
+
data = _read_activity()
|
|
4239
|
+
invites = data["invites"]
|
|
4240
|
+
if sum(1 for t in invites if t > now - DAY_SECONDS) >= INVITE_DAY_CAP:
|
|
4241
|
+
return "day"
|
|
4242
|
+
if sum(1 for t in invites if t > now - WEEK_SECONDS) >= INVITE_WEEK_CAP:
|
|
4243
|
+
return "week"
|
|
4244
|
+
_charge(data, "invites", 1, now)
|
|
4245
|
+
return None
|
|
4246
|
+
|
|
4247
|
+
|
|
4248
|
+
def invite_message(kind):
|
|
4249
|
+
"""Why Auto sent nothing: a cap on its requests is reached, and when one frees up."""
|
|
4250
|
+
now = time.time()
|
|
4251
|
+
window = WEEK_SECONDS if kind == "week" else DAY_SECONDS
|
|
4252
|
+
cap = INVITE_WEEK_CAP if kind == "week" else INVITE_DAY_CAP
|
|
4253
|
+
sent = sorted(t for t in _read_activity()["invites"] if t > now - window)
|
|
4254
|
+
extra = len(sent) - cap
|
|
4255
|
+
free = f" The next one frees up at {_when(sent[extra] + window)}." if extra >= 0 else ""
|
|
4256
|
+
span = "7 days" if kind == "week" else "24 hours"
|
|
4257
|
+
return f"Auto has sent {cap} connection requests in the last {span}, its limit.{free} Nothing was opened or sent."
|
|
4258
|
+
|
|
4259
|
+
|
|
4260
|
+
def _names_words(text):
|
|
4261
|
+
"""The words of a name, lower case, letters only (any alphabet)."""
|
|
4262
|
+
return re.findall(r"[^\W\d_]+", str(text or "").lower())
|
|
4263
|
+
|
|
4264
|
+
|
|
4265
|
+
def _same_person(shown, name):
|
|
4266
|
+
"""Does what LinkedIn shows (a label, a heading) name this person: their first and last name, as whole words?"""
|
|
4267
|
+
want = _names_words(str(name or "").split(",")[0])
|
|
4268
|
+
have = set(_names_words(shown))
|
|
4269
|
+
return bool(want) and want[0] in have and want[-1] in have
|
|
4270
|
+
|
|
4271
|
+
|
|
4272
|
+
def _shown(loc, limit=40):
|
|
4273
|
+
"""The items of a locator that are on screen."""
|
|
4274
|
+
out = []
|
|
4275
|
+
try:
|
|
4276
|
+
n = loc.count()
|
|
4277
|
+
except Exception:
|
|
4278
|
+
return out
|
|
4279
|
+
for i in range(min(n, limit)):
|
|
4280
|
+
item = loc.nth(i)
|
|
4281
|
+
try:
|
|
4282
|
+
if item.is_visible():
|
|
4283
|
+
out.append(item)
|
|
4284
|
+
except Exception:
|
|
4285
|
+
pass
|
|
4286
|
+
return out
|
|
4287
|
+
|
|
4288
|
+
|
|
4289
|
+
def _label(item):
|
|
4290
|
+
"""An element's accessible name as LinkedIn wrote it: its aria-label, else its text."""
|
|
4291
|
+
try:
|
|
4292
|
+
label = item.get_attribute("aria-label")
|
|
4293
|
+
if label:
|
|
4294
|
+
return label
|
|
4295
|
+
except Exception:
|
|
4296
|
+
pass
|
|
4297
|
+
try:
|
|
4298
|
+
return item.inner_text() or ""
|
|
4299
|
+
except Exception:
|
|
4300
|
+
return ""
|
|
4301
|
+
|
|
4302
|
+
|
|
4303
|
+
def _enabled(item):
|
|
4304
|
+
try:
|
|
4305
|
+
return item.is_enabled()
|
|
4306
|
+
except Exception:
|
|
4307
|
+
return False
|
|
4308
|
+
|
|
4309
|
+
|
|
4310
|
+
def _in_main(page):
|
|
4311
|
+
"""The profile's <main>, where its own buttons are, or the page if there is none."""
|
|
4312
|
+
try:
|
|
4313
|
+
main = page.locator("main")
|
|
4314
|
+
if main.count() > 0:
|
|
4315
|
+
return main.first
|
|
4316
|
+
except Exception:
|
|
4317
|
+
pass
|
|
4318
|
+
return page
|
|
4319
|
+
|
|
4320
|
+
|
|
4321
|
+
def _actions(scope, name_pattern):
|
|
4322
|
+
"""Every button, link or menu item on screen whose accessible name matches."""
|
|
4323
|
+
found = []
|
|
4324
|
+
for role in ACTION_ROLES:
|
|
4325
|
+
try:
|
|
4326
|
+
found.extend(_shown(scope.get_by_role(role, name=name_pattern)))
|
|
4327
|
+
except Exception:
|
|
4328
|
+
pass
|
|
4329
|
+
return found
|
|
4330
|
+
|
|
4331
|
+
|
|
4332
|
+
def _invite_for(page, name):
|
|
4333
|
+
"""Their own Connect: "Invite <their name> to connect", never someone else's."""
|
|
4334
|
+
for item in _actions(page, INVITE_LABEL):
|
|
4335
|
+
m = INVITE_LABEL.match(_label(item))
|
|
4336
|
+
if m and _same_person(m.group(1), name):
|
|
4337
|
+
return item
|
|
4338
|
+
return None
|
|
4339
|
+
|
|
4340
|
+
|
|
4341
|
+
def _pending_for(page, name):
|
|
4342
|
+
"""Their profile says a request to them is pending, naming them."""
|
|
4343
|
+
return any(_same_person(_label(item), name) for item in _actions(page, PENDING_LABEL))
|
|
4344
|
+
|
|
4345
|
+
|
|
4346
|
+
def _bare_pending(page):
|
|
4347
|
+
"""How many nameless "Pending" buttons their profile shows."""
|
|
4348
|
+
return len(_actions(_in_main(page), BARE_PENDING))
|
|
4349
|
+
|
|
4350
|
+
|
|
4351
|
+
def _sent_shown(page, name, bare_before):
|
|
4352
|
+
"""LinkedIn shows the request to them as sent: Pending naming them, a new
|
|
4353
|
+
"Pending" on their profile, or its notice that the invitation to them was sent."""
|
|
4354
|
+
if _pending_for(page, name):
|
|
4355
|
+
return True
|
|
4356
|
+
if _bare_pending(page) > bare_before:
|
|
4357
|
+
return True
|
|
4358
|
+
try:
|
|
4359
|
+
for item in _shown(page.get_by_text(SENT_NOTICE)):
|
|
4360
|
+
m = SENT_NOTICE.search(_label(item))
|
|
4361
|
+
if m and _same_person(m.group(1), name):
|
|
4362
|
+
return True
|
|
4363
|
+
except Exception:
|
|
4364
|
+
pass
|
|
4365
|
+
return False
|
|
4366
|
+
|
|
4367
|
+
|
|
4368
|
+
def _press_escape(page):
|
|
4369
|
+
try:
|
|
4370
|
+
page.keyboard.press("Escape")
|
|
4371
|
+
except Exception:
|
|
4372
|
+
pass
|
|
4373
|
+
|
|
4374
|
+
|
|
4375
|
+
def _connect_under_more(page, name):
|
|
4376
|
+
"""Connect from their profile's More menu, or None (the menu is closed again)."""
|
|
4377
|
+
more = _actions(_in_main(page), MORE_LABEL)
|
|
4378
|
+
if not more:
|
|
4379
|
+
return None
|
|
4380
|
+
bare_before = len(_actions(page, BARE_CONNECT))
|
|
4381
|
+
print(" Connect isn't on the front of their profile; looking under More...")
|
|
4382
|
+
try:
|
|
4383
|
+
more[0].click(timeout=10000)
|
|
4384
|
+
except Exception:
|
|
4385
|
+
return None
|
|
4386
|
+
time.sleep(CONNECT_STEP)
|
|
4387
|
+
found = _invite_for(page, name)
|
|
4388
|
+
if found:
|
|
4389
|
+
return found
|
|
4390
|
+
# A nameless "Connect" only when opening the menu is what brought it on screen.
|
|
4391
|
+
bare = _actions(page, BARE_CONNECT)
|
|
4392
|
+
if bare_before == 0 and len(bare) == 1:
|
|
4393
|
+
return bare[0]
|
|
4394
|
+
_press_escape(page)
|
|
4395
|
+
return None
|
|
4396
|
+
|
|
4397
|
+
|
|
4398
|
+
def _dialog(page):
|
|
4399
|
+
"""LinkedIn's window on top of the page (the newest), or None."""
|
|
4400
|
+
shown = []
|
|
4401
|
+
for role in ("dialog", "alertdialog"):
|
|
4402
|
+
try:
|
|
4403
|
+
shown.extend(_shown(page.get_by_role(role)))
|
|
4404
|
+
except Exception:
|
|
4405
|
+
pass
|
|
4406
|
+
return shown[-1] if shown else None
|
|
4407
|
+
|
|
4408
|
+
|
|
4409
|
+
def _close_dialog(page, dialog):
|
|
4410
|
+
"""Close LinkedIn's window without answering it: its Dismiss (or Close, Cancel), else Escape."""
|
|
4411
|
+
try:
|
|
4412
|
+
close = _shown(dialog.get_by_role("button", name=CLOSE_LABEL))
|
|
4413
|
+
if close:
|
|
4414
|
+
close[0].click(timeout=5000)
|
|
4415
|
+
else:
|
|
4416
|
+
_press_escape(page)
|
|
4417
|
+
except Exception:
|
|
4418
|
+
_press_escape(page)
|
|
4419
|
+
time.sleep(CONNECT_STEP)
|
|
4420
|
+
|
|
4421
|
+
|
|
4422
|
+
def _asks_for_email(dialog, text):
|
|
4423
|
+
"""The invitation window wants their email address before it sends."""
|
|
4424
|
+
for loc in (lambda: dialog.get_by_role("textbox", name=EMAIL_BOX), lambda: dialog.locator("input[type=email]")):
|
|
4425
|
+
try:
|
|
4426
|
+
if _shown(loc()):
|
|
4427
|
+
return True
|
|
4428
|
+
except Exception:
|
|
4429
|
+
pass
|
|
4430
|
+
return bool(EMAIL_ASK.search(text or ""))
|
|
4431
|
+
|
|
4432
|
+
|
|
4433
|
+
def _send_button(dialog):
|
|
4434
|
+
""""Send without a note", or the one Send there is. Never "Add a note", never Premium."""
|
|
4435
|
+
plain = [b for b in _shown(dialog.get_by_role("button", name=SEND_PLAIN)) if _enabled(b)]
|
|
4436
|
+
if plain:
|
|
4437
|
+
return plain[0]
|
|
4438
|
+
sends = [b for b in _shown(dialog.get_by_role("button", name=SEND_ANY)) if _enabled(b)]
|
|
4439
|
+
return sends[0] if len(sends) == 1 else None
|
|
4440
|
+
|
|
4441
|
+
|
|
4442
|
+
def _dialog_text(dialog):
|
|
4443
|
+
try:
|
|
4444
|
+
return dialog.inner_text() or ""
|
|
4445
|
+
except Exception:
|
|
4446
|
+
return ""
|
|
4447
|
+
|
|
4448
|
+
|
|
4449
|
+
def _connect_pushback(page, why):
|
|
4450
|
+
"""LinkedIn pushed back while Auto was on their profile: keep the page, pause for a day."""
|
|
4451
|
+
print(f" LinkedIn is pushing back ({why}). Stopping here.")
|
|
4452
|
+
_keep_pushback_evidence(page, why)
|
|
4453
|
+
set_cooldown(seconds=DAY_SECONDS, reason=f"LinkedIn pushed back: {why}")
|
|
4454
|
+
|
|
4455
|
+
|
|
4456
|
+
def _confirm_sent(page, name, bare_before):
|
|
4457
|
+
"""After Send: "sent" once their profile shows it, else "unclear" (or "pushback", "linkedin-limit")."""
|
|
4458
|
+
waited = 0
|
|
4459
|
+
while waited < CONFIRM_WAIT:
|
|
4460
|
+
time.sleep(CONNECT_STEP)
|
|
4461
|
+
waited += CONNECT_STEP
|
|
4462
|
+
why = _pushback(page)
|
|
4463
|
+
if why:
|
|
4464
|
+
_connect_pushback(page, why)
|
|
4465
|
+
return "pushback"
|
|
4466
|
+
dialog = _dialog(page)
|
|
4467
|
+
if dialog is not None and INVITE_LIMIT.search(_dialog_text(dialog)):
|
|
4468
|
+
_close_dialog(page, dialog)
|
|
4469
|
+
print(" LinkedIn says this account has reached its invitation limit.")
|
|
4470
|
+
return "linkedin-limit"
|
|
4471
|
+
if _sent_shown(page, name, bare_before):
|
|
4472
|
+
return "sent"
|
|
4473
|
+
leftover = _dialog(page)
|
|
4474
|
+
if leftover is not None:
|
|
4475
|
+
_close_dialog(page, leftover)
|
|
4476
|
+
return "unclear"
|
|
4477
|
+
|
|
4478
|
+
|
|
4479
|
+
def _answer_invitation(page, name, bare_before):
|
|
4480
|
+
"""What LinkedIn asks once Connect is pressed, answered without a note."""
|
|
4481
|
+
dialog = None
|
|
4482
|
+
waited = 0
|
|
4483
|
+
while waited < DIALOG_WAIT:
|
|
4484
|
+
time.sleep(CONNECT_STEP)
|
|
4485
|
+
waited += CONNECT_STEP
|
|
4486
|
+
dialog = _dialog(page)
|
|
4487
|
+
if dialog is not None:
|
|
4488
|
+
break
|
|
4489
|
+
if _sent_shown(page, name, bare_before):
|
|
4490
|
+
# Some accounts send straight from Connect, with nothing to answer.
|
|
4491
|
+
charge_linkedin("invites")
|
|
4492
|
+
print(" LinkedIn sent it straight from Connect; their profile shows it pending.")
|
|
4493
|
+
return "sent"
|
|
4494
|
+
if dialog is None:
|
|
4495
|
+
# Nothing came up and nothing shows it pending. It may have gone, so it
|
|
4496
|
+
# counts toward Auto's caps; it isn't called sent.
|
|
4497
|
+
charge_linkedin("invites")
|
|
4498
|
+
print(" Nothing came up after Connect, and their profile doesn't show it pending.")
|
|
4499
|
+
return "unclear"
|
|
4500
|
+
|
|
4501
|
+
text = _dialog_text(dialog)
|
|
4502
|
+
if _asks_for_email(dialog, text):
|
|
4503
|
+
_close_dialog(page, dialog)
|
|
4504
|
+
print(" LinkedIn wants their email address before it sends this one. Closed that; nothing was sent.")
|
|
4505
|
+
return "email-needed"
|
|
4506
|
+
if INVITE_LIMIT.search(text):
|
|
4507
|
+
_close_dialog(page, dialog)
|
|
4508
|
+
print(" LinkedIn says this account has reached its invitation limit. Closed that; nothing was sent.")
|
|
4509
|
+
return "linkedin-limit"
|
|
4510
|
+
send = _send_button(dialog)
|
|
4511
|
+
if send is None:
|
|
4512
|
+
_close_dialog(page, dialog)
|
|
4513
|
+
print(" LinkedIn's invitation window had no way to send without a note. Closed it; nothing was sent.")
|
|
4514
|
+
return "not-sent"
|
|
4515
|
+
if PREMIUM_NOTE.search(text):
|
|
4516
|
+
print(" LinkedIn offered a personal note (Premium). Sending without one.")
|
|
4517
|
+
if stop_requested() or _window_closed(page):
|
|
4518
|
+
_close_dialog(page, dialog)
|
|
4519
|
+
return "stopped"
|
|
4520
|
+
taken = take_invite()
|
|
4521
|
+
if taken:
|
|
4522
|
+
_close_dialog(page, dialog)
|
|
4523
|
+
print(" " + invite_message(taken))
|
|
4524
|
+
return f"invites-{taken}"
|
|
4525
|
+
print(" Sending without a note...")
|
|
4526
|
+
try:
|
|
4527
|
+
send.click(timeout=10000)
|
|
4528
|
+
except Exception as exc:
|
|
4529
|
+
print(f" Send couldn't be pressed ({str(exc)[:60]}).")
|
|
4530
|
+
_close_dialog(page, dialog)
|
|
4531
|
+
return "unclear"
|
|
4532
|
+
result = _confirm_sent(page, name, bare_before)
|
|
4533
|
+
if result == "sent":
|
|
4534
|
+
print(f" Sent. {name}'s profile shows the request pending.")
|
|
4535
|
+
elif result == "unclear":
|
|
4536
|
+
print(" Send was pressed, but their profile doesn't show the request pending. Not calling it sent.")
|
|
4537
|
+
return result
|
|
4538
|
+
|
|
4539
|
+
|
|
4540
|
+
def _connect_on_page(page, profile_url, name):
|
|
4541
|
+
"""Open their profile (one profile view) and send the request. Returns a CONNECT_RESULTS name."""
|
|
4542
|
+
why = _wait_for_profile_view(page)
|
|
4543
|
+
if why == "budget":
|
|
4544
|
+
print(budget_message("profiles"))
|
|
4545
|
+
return "profiles"
|
|
4546
|
+
if why:
|
|
4547
|
+
return "stopped"
|
|
4548
|
+
|
|
4549
|
+
print(f" Opening {name}'s profile...")
|
|
4550
|
+
try:
|
|
4551
|
+
page.goto(profile_url, wait_until="commit")
|
|
4552
|
+
except Exception as exc:
|
|
4553
|
+
print(f" Navigation slow: {str(exc)[:50]}... carrying on")
|
|
4554
|
+
|
|
4555
|
+
shown = False
|
|
4556
|
+
for _ in range(CONNECT_LOAD_ATTEMPTS):
|
|
4557
|
+
time.sleep(CONNECT_LOAD_STEP)
|
|
4558
|
+
if stop_requested() or _window_closed(page):
|
|
4559
|
+
return "stopped"
|
|
4560
|
+
why = _pushback(page)
|
|
4561
|
+
if why:
|
|
4562
|
+
_connect_pushback(page, why)
|
|
4563
|
+
return "pushback"
|
|
4564
|
+
if _profile_unavailable(page):
|
|
4565
|
+
print(" LinkedIn says their profile isn't available. Nothing was sent.")
|
|
4566
|
+
return "unavailable"
|
|
4567
|
+
try:
|
|
4568
|
+
shown = bool(page.evaluate(PROFILE_SHOWN_JS, name))
|
|
4569
|
+
except Exception:
|
|
4570
|
+
shown = False
|
|
4571
|
+
if shown:
|
|
4572
|
+
break
|
|
4573
|
+
if not shown:
|
|
4574
|
+
print(" Their profile didn't load properly, so nothing was pressed.")
|
|
4575
|
+
return "not-loaded"
|
|
4576
|
+
|
|
4577
|
+
if _pending_for(page, name):
|
|
4578
|
+
print(f" A request to {name} is already pending on LinkedIn. Nothing new was sent.")
|
|
4579
|
+
return "already-pending"
|
|
4580
|
+
bare_before = _bare_pending(page)
|
|
4581
|
+
target = _invite_for(page, name) or _connect_under_more(page, name)
|
|
4582
|
+
if target is None:
|
|
4583
|
+
print(" LinkedIn shows no Connect for them here (only Follow or Message, say). Nothing was sent.")
|
|
4584
|
+
return "no-connect"
|
|
4585
|
+
if stop_requested() or _window_closed(page):
|
|
4586
|
+
return "stopped"
|
|
4587
|
+
left, kind = invites_left()
|
|
4588
|
+
if left <= 0:
|
|
4589
|
+
print(" " + invite_message(kind))
|
|
4590
|
+
return f"invites-{kind}"
|
|
4591
|
+
print(f" Pressing Connect for {name}...")
|
|
4592
|
+
try:
|
|
4593
|
+
target.click(timeout=10000)
|
|
4594
|
+
except Exception as exc:
|
|
4595
|
+
print(f" Connect couldn't be pressed ({str(exc)[:60]}). Nothing was sent.")
|
|
4596
|
+
return "not-sent"
|
|
4597
|
+
return _answer_invitation(page, name, bare_before)
|
|
4598
|
+
|
|
4599
|
+
|
|
4600
|
+
def connect_person(profile_url, name=None, headless=False):
|
|
4601
|
+
"""Send one connection request, without a note, to the person at profile_url.
|
|
4602
|
+
|
|
4603
|
+
Returns one of CONNECT_RESULTS; main() prints it as "Connect result: ...".
|
|
4604
|
+
Nothing opens during a cooldown, with Auto's caps reached, or with no
|
|
4605
|
+
profile view left: each is checked before a browser starts.
|
|
4606
|
+
"""
|
|
4607
|
+
from playwright.sync_api import sync_playwright
|
|
4608
|
+
|
|
4609
|
+
cd = read_cooldown()
|
|
4610
|
+
if cd:
|
|
4611
|
+
print(cooldown_message(cd))
|
|
4612
|
+
return "cooldown"
|
|
4613
|
+
left, kind = invites_left()
|
|
4614
|
+
if left <= 0:
|
|
4615
|
+
print(invite_message(kind))
|
|
4616
|
+
return f"invites-{kind}"
|
|
4617
|
+
if profiles_left() <= 0:
|
|
4618
|
+
print(budget_message("profiles"))
|
|
4619
|
+
return "profiles"
|
|
4620
|
+
if not name:
|
|
4621
|
+
params = {"profile_url": f"eq.{profile_url}", "limit": "1"}
|
|
4622
|
+
if _active_user_id:
|
|
4623
|
+
params["user_id"] = f"eq.{_active_user_id}"
|
|
4624
|
+
rows = read_connections(params=params)
|
|
4625
|
+
if not rows:
|
|
4626
|
+
print(f" {profile_url} isn't in your network on this computer. Nothing was sent.")
|
|
4627
|
+
return "not-found"
|
|
4628
|
+
name = rows[0].get("name") or ""
|
|
4629
|
+
|
|
4630
|
+
print(f"\n=== Sending {name} a connection request, without a note ===\n")
|
|
4631
|
+
result = None
|
|
4632
|
+
try:
|
|
4633
|
+
with sync_playwright() as p:
|
|
4634
|
+
browser = p.chromium.launch_persistent_context(
|
|
4635
|
+
user_data_dir=get_scraper_profile_path(),
|
|
4636
|
+
headless=headless,
|
|
4637
|
+
channel="chrome",
|
|
4638
|
+
args=["--disable-blink-features=AutomationControlled"],
|
|
4639
|
+
timeout=120000,
|
|
4640
|
+
)
|
|
4641
|
+
try:
|
|
4642
|
+
page = browser.pages[0] if browser.pages else browser.new_page()
|
|
4643
|
+
page.set_default_timeout(120000)
|
|
4644
|
+
page.set_default_navigation_timeout(120000)
|
|
4645
|
+
# A security check or a sign-out here is LinkedIn pushing back,
|
|
4646
|
+
# as for a circle scan: it raises, after pausing everything.
|
|
4647
|
+
if not ensure_logged_in(page, stop_on_checkpoint=True):
|
|
4648
|
+
result = "stopped" if stop_requested() else "not-signed-in"
|
|
4649
|
+
else:
|
|
4650
|
+
result = _connect_on_page(page, profile_url, name)
|
|
4651
|
+
finally:
|
|
4652
|
+
try:
|
|
4653
|
+
browser.close()
|
|
4654
|
+
except Exception:
|
|
4655
|
+
pass
|
|
4656
|
+
except LinkedInPushedBack as exc:
|
|
4657
|
+
print(f" LinkedIn pushed back ({exc.reason}). Nothing was sent.")
|
|
4658
|
+
result = "pushback"
|
|
4659
|
+
except Exception:
|
|
4660
|
+
# A stop takes the browser down with it. Anything else is a failure
|
|
4661
|
+
# with its reason, never a result that could read as sent.
|
|
4662
|
+
if result is None:
|
|
4663
|
+
if stop_requested():
|
|
4664
|
+
result = "stopped"
|
|
4665
|
+
else:
|
|
4666
|
+
raise
|
|
4667
|
+
return result
|
|
4668
|
+
|
|
4669
|
+
|
|
4112
4670
|
def run_server(port=5555):
|
|
4113
4671
|
"""
|
|
4114
4672
|
Run a local HTTP server that the website's Setup page can talk to.
|
|
@@ -4373,6 +4931,12 @@ Examples:
|
|
|
4373
4931
|
"The app's Scan buttons use it, since two connections can share a name")
|
|
4374
4932
|
parser.add_argument("--only-unfinished", action="store_true",
|
|
4375
4933
|
help="With --auto-bridge: only people whose read was cut short (Resume all)")
|
|
4934
|
+
parser.add_argument("--connect", type=str,
|
|
4935
|
+
help="Auto: send one connection request, without a note, to the person at this LinkedIn "
|
|
4936
|
+
f"profile URL. Never with a note; at most {INVITE_DAY_CAP} in any 24 hours and "
|
|
4937
|
+
f"{INVITE_WEEK_CAP} in any 7 days")
|
|
4938
|
+
parser.add_argument("--connect-name", type=str, default="",
|
|
4939
|
+
help="With --connect: their name as the app has it (else it is looked up in the app)")
|
|
4376
4940
|
parser.add_argument("--save-photos", action="store_true",
|
|
4377
4941
|
help="Save the profile photos still kept as links to LinkedIn, then exit "
|
|
4378
4942
|
"(every scan also does this at its end)")
|
|
@@ -4384,7 +4948,10 @@ Examples:
|
|
|
4384
4948
|
args.max_pages = max(1, min(LINKEDIN_MAX_PAGES, args.max_pages))
|
|
4385
4949
|
# The Scan page's speed. Signing in searches nothing, so it isn't said there.
|
|
4386
4950
|
_pace = apply_pace()
|
|
4387
|
-
if
|
|
4951
|
+
if args.connect:
|
|
4952
|
+
# Auto reads no pages: only the gap before opening their profile applies.
|
|
4953
|
+
print(f"Speed: {_pace.capitalize()}. Profiles at least {PROFILE_GAP}s apart.")
|
|
4954
|
+
elif not args.login:
|
|
4388
4955
|
print(f"Speed: {_pace.capitalize()}. {PAGE_PAUSE}s before each page of results, {CHUNK_COOLDOWN}s more after "
|
|
4389
4956
|
f"every {SAVE_EVERY_PAGES}, and profiles at least {PROFILE_GAP}s apart.")
|
|
4390
4957
|
|
|
@@ -4430,6 +4997,23 @@ Examples:
|
|
|
4430
4997
|
# A budget or a cooldown ending a run is the design working, not a failure:
|
|
4431
4998
|
# say why and exit 0, so the Scan page doesn't show it as a red error.
|
|
4432
4999
|
try:
|
|
5000
|
+
if args.connect:
|
|
5001
|
+
# Auto (lib/auto-connect.js): one request, then out. Its last line is
|
|
5002
|
+
# the result the app reads; no photos are saved after it, since it
|
|
5003
|
+
# read no one. A pushback or no sign-in ends it as a failure, with why.
|
|
5004
|
+
if not re.match(r"^https?://([a-z]{2,3}\.|www\.)?linkedin\.com/in/[^/?#\s]+/?$", args.connect, re.I):
|
|
5005
|
+
print(" --connect takes a LinkedIn profile URL (https://www.linkedin.com/in/...).", file=sys.stderr)
|
|
5006
|
+
raise SystemExit(2)
|
|
5007
|
+
result = connect_person(args.connect, name=args.connect_name.strip() or None, headless=args.headless)
|
|
5008
|
+
print(f"Connect result: {result}", flush=True)
|
|
5009
|
+
if result == "pushback":
|
|
5010
|
+
print(f"\n LinkedIn pushed back, so nothing more is sent. {_pushback_advice('')}\n", file=sys.stderr)
|
|
5011
|
+
raise SystemExit(1)
|
|
5012
|
+
if result == "not-signed-in":
|
|
5013
|
+
print("\n LinkedIn isn't signed in, so nothing was sent. Sign in with --login (or the Scan page), "
|
|
5014
|
+
"then try again.\n", file=sys.stderr)
|
|
5015
|
+
raise SystemExit(1)
|
|
5016
|
+
raise SystemExit(0)
|
|
4433
5017
|
if args.company:
|
|
4434
5018
|
# The server mode scraped and pushed as one step; the CLI has to do the
|
|
4435
5019
|
# same or the scan appears to work and saves nothing.
|