six-degrees 0.6.0 → 0.7.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 +3 -0
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +14 -14
- package/.next/standalone/.next/routes-manifest.json +18 -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 +2 -2
- 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 +4 -2
- 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/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 +20 -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 +3 -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]__15wc9e-._.js → [root-of-the-server]__063s0x7._.js} +2 -2
- 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]__13dx4sd._.js → [root-of-the-server]__0_4y8z7._.js} +3 -3
- 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]__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/[root-of-the-server]__20rwfdw._.js +1 -1
- package/.next/standalone/.next/server/chunks/_02twlca._.js +1 -1
- 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_005abye.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0b17r6v.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0c9d9ti.js +7 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0doq0t-.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0fd2rlw.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0is4qoc.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0jnfp2e.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0nef_n7.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0plrzra.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_13a4m0c.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1if17c-.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1j-zw7v.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1sngt-q.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1v2sgme.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1vh-tgx.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1zaubz7.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/_01o3i5y._.js +7 -0
- package/.next/standalone/.next/server/chunks/ssr/_02sband._.js +7 -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/_0gy11ar._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0hb-dhy._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_14nxd3q._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_189g8lg._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1f_n00p._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1fm1ih_._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_1k2nmbw._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_1k9qfsk._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_141w189._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_components_0t908t-._.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_import_page_1fmu6_l.js +1 -1
- 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 +25 -13
- 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/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- 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/03-_esd2x_yk6.js +1 -0
- package/.next/standalone/.next/static/chunks/03-demj2iy-0p.js +44 -0
- package/.next/standalone/.next/static/chunks/0_1r-3csplxnj.js +1 -0
- package/.next/standalone/.next/static/chunks/0an_b6zi1r_qq.js +5 -0
- package/.next/standalone/.next/static/chunks/0e3g0sil79cus.js +21 -0
- package/.next/standalone/.next/static/chunks/0kscsqnvfq3-r.js +1 -0
- package/.next/standalone/.next/static/chunks/0p3g5tfostsep.js +7 -0
- package/.next/standalone/.next/static/chunks/0zd0t7e60bn4z.js +1 -0
- package/.next/standalone/.next/static/chunks/163b-20vwa06i.js +34 -0
- package/.next/standalone/.next/static/chunks/{0ws7zy0w57ufi.js → 1eyajb9ntzlrl.js} +1 -1
- package/.next/standalone/.next/static/chunks/1pa-2v1ajvrko.js +1 -0
- package/.next/standalone/.next/static/chunks/1qbjermbf68xj.js +1 -0
- package/.next/standalone/.next/static/chunks/1z9lb-dbcg4aa.js +1 -0
- package/.next/standalone/.next/static/chunks/23_1z47al92nz.js +57 -0
- package/.next/standalone/.next/static/chunks/260bomtr214m8.js +34 -0
- package/.next/standalone/.next/static/chunks/2eo9pqq9gay3r.js +34 -0
- package/.next/standalone/.next/static/chunks/2xk2ra4piiuod.js +34 -0
- package/.next/standalone/.next/static/chunks/2z1-q0_vunbql.js +2 -0
- package/.next/standalone/.next/static/chunks/2zf4jmz9l3li2.js +1 -0
- package/.next/standalone/.next/static/chunks/34g73qhayuevu.js +1 -0
- package/.next/standalone/.next/static/chunks/3b0-14cxqsprt.js +1 -0
- package/.next/standalone/.next/static/chunks/3jarus1_38s2z.js +1 -0
- package/.next/standalone/.next/static/chunks/3ssu341hav_sq.css +3 -0
- package/.next/standalone/.next/static/chunks/3v1qd3sqhqn0d.js +1 -0
- package/.next/standalone/.next/static/chunks/43pg2sursiypz.js +1 -0
- package/.next/standalone/.next/static/chunks/44yn0tcd9dfk3.js +1 -0
- package/.next/standalone/CHANGELOG.md +143 -0
- package/.next/standalone/README.md +71 -49
- package/.next/standalone/SECURITY.md +17 -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/queue/route.js +1 -1
- package/.next/standalone/app/api/scraper/route.js +120 -32
- package/.next/standalone/app/api/social/crm/route.js +2 -1
- package/.next/standalone/app/components/AppHeader.js +20 -16
- package/.next/standalone/app/components/AppTabs.js +8 -8
- 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 +184 -112
- 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 +17 -17
- 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 +24 -19
- 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 +25 -25
- 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 +22 -18
- package/.next/standalone/app/components/ScanTrail.js +8 -5
- package/.next/standalone/app/components/SeparationView.js +168 -104
- package/.next/standalone/app/components/Sidebar.js +161 -161
- 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/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 +313 -0
- package/.next/standalone/app/components/ui.js +8 -8
- package/.next/standalone/app/globals.css +159 -2
- package/.next/standalone/app/import/page.js +94 -38
- package/.next/standalone/app/launch/page.js +5 -5
- package/.next/standalone/app/layout.js +6 -2
- package/.next/standalone/app/page.js +53 -37
- 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 +54 -54
- 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 +221 -125
- 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/backups.js +458 -0
- package/.next/standalone/lib/chain-layout.js +32 -0
- 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/ingest.js +1 -1
- package/.next/standalone/lib/linkedin-limits.js +212 -11
- package/.next/standalone/lib/liquid-glass.js +59 -0
- package/.next/standalone/lib/notifications.js +13 -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/scanner-setup.js +97 -15
- package/.next/standalone/lib/scraper-client.js +17 -3
- package/.next/standalone/lib/search-risk.js +7 -3
- package/.next/standalone/lib/settings-client.js +5 -3
- package/.next/standalone/lib/settings.js +10 -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 +195 -0
- package/.next/standalone/package-lock.json +2 -2
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/scripts/scrape.py +26 -2
- package/.next/static/chunks/03-_esd2x_yk6.js +1 -0
- package/.next/static/chunks/03-demj2iy-0p.js +44 -0
- package/.next/static/chunks/0_1r-3csplxnj.js +1 -0
- package/.next/static/chunks/0an_b6zi1r_qq.js +5 -0
- package/.next/static/chunks/0e3g0sil79cus.js +21 -0
- package/.next/static/chunks/0kscsqnvfq3-r.js +1 -0
- package/.next/static/chunks/0p3g5tfostsep.js +7 -0
- package/.next/static/chunks/0zd0t7e60bn4z.js +1 -0
- package/.next/static/chunks/163b-20vwa06i.js +34 -0
- package/.next/static/chunks/{0ws7zy0w57ufi.js → 1eyajb9ntzlrl.js} +1 -1
- package/.next/static/chunks/1pa-2v1ajvrko.js +1 -0
- package/.next/static/chunks/1qbjermbf68xj.js +1 -0
- package/.next/static/chunks/1z9lb-dbcg4aa.js +1 -0
- package/.next/static/chunks/23_1z47al92nz.js +57 -0
- package/.next/static/chunks/260bomtr214m8.js +34 -0
- package/.next/static/chunks/2eo9pqq9gay3r.js +34 -0
- package/.next/static/chunks/2xk2ra4piiuod.js +34 -0
- package/.next/static/chunks/2z1-q0_vunbql.js +2 -0
- package/.next/static/chunks/2zf4jmz9l3li2.js +1 -0
- package/.next/static/chunks/34g73qhayuevu.js +1 -0
- package/.next/static/chunks/3b0-14cxqsprt.js +1 -0
- package/.next/static/chunks/3jarus1_38s2z.js +1 -0
- package/.next/static/chunks/3ssu341hav_sq.css +3 -0
- package/.next/static/chunks/3v1qd3sqhqn0d.js +1 -0
- package/.next/static/chunks/43pg2sursiypz.js +1 -0
- package/.next/static/chunks/44yn0tcd9dfk3.js +1 -0
- package/CHANGELOG.md +143 -0
- package/README.md +71 -49
- package/SECURITY.md +17 -11
- package/lib/backups.js +458 -0
- package/lib/chain-layout.js +32 -0
- 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/ingest.js +1 -1
- package/lib/linkedin-limits.js +212 -11
- package/lib/liquid-glass.js +59 -0
- package/lib/notifications.js +13 -0
- package/lib/scan-pace.js +11 -0
- package/lib/scan-progress.js +20 -0
- package/lib/scan-risk.js +44 -0
- package/lib/scanner-setup.js +97 -15
- package/lib/scraper-client.js +17 -3
- package/lib/search-risk.js +7 -3
- package/lib/settings-client.js +5 -3
- package/lib/settings.js +10 -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 +195 -0
- package/package.json +1 -1
- package/scripts/scrape.py +26 -2
- 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]__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/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/_2105jz8._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/app_components_settings_SectorPicker_1c-29qw.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 → ZVpLBK-2vpllv2HxOFs2d}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{dQUvvVSXqbkEFC3-CNcwT → ZVpLBK-2vpllv2HxOFs2d}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{dQUvvVSXqbkEFC3-CNcwT → ZVpLBK-2vpllv2HxOFs2d}/_ssgManifest.js +0 -0
- /package/.next/static/{dQUvvVSXqbkEFC3-CNcwT → ZVpLBK-2vpllv2HxOFs2d}/_buildManifest.js +0 -0
- /package/.next/static/{dQUvvVSXqbkEFC3-CNcwT → ZVpLBK-2vpllv2HxOFs2d}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{dQUvvVSXqbkEFC3-CNcwT → ZVpLBK-2vpllv2HxOFs2d}/_ssgManifest.js +0 -0
|
@@ -12,21 +12,25 @@ This app is designed to run **on your own machine, against your own network**.
|
|
|
12
12
|
|
|
13
13
|
- The web UI binds to localhost. It is not hardened for exposure to the
|
|
14
14
|
internet, and it has no multi-user authentication or per-user authorization.
|
|
15
|
-
-
|
|
16
|
-
`setup-profile`, `scraper`, `update`,
|
|
17
|
-
`data/export`, `data/import`, `data/restart`, `data/reveal`
|
|
18
|
-
can irreversibly destroy or rewrite data,
|
|
19
|
-
`update` changes the code that runs next. `data/export` hands over the whole
|
|
15
|
+
- Thirteen API routes are gated (`admin-delete`, `admin-update`, `delete-cluster`,
|
|
16
|
+
`setup-profile`, `scraper`, `update`, Settings → Your data's
|
|
17
|
+
`data/export`, `data/import`, `data/restart`, `data/reveal`, `data/backup`,
|
|
18
|
+
`data/restore`, and `data/csv`). The first four can irreversibly destroy or rewrite data,
|
|
19
|
+
`scraper` starts processes, and `update` changes the code that runs next. `data/export` hands over the whole
|
|
20
20
|
network in one file, `data/import` replaces it, `data/restart` stops the
|
|
21
|
-
server,
|
|
22
|
-
browser, on the data folder's own path
|
|
21
|
+
server, `data/reveal` starts a process (Finder, or the Linux file
|
|
22
|
+
browser, on the data folder's own path or a backup in it), `data/backup`
|
|
23
|
+
writes the whole network to a file in `backups/`, `data/restore`
|
|
24
|
+
replaces the network with one of those backups, named as `backups/` lists
|
|
25
|
+
it, never by a path from the request, and `data/csv` keeps, hands over and
|
|
26
|
+
removes a LinkedIn CSV import kept in the data folder. While the server is bound to
|
|
23
27
|
127.0.0.1 they need no token — anyone who can reach it can already open the
|
|
24
28
|
database file directly, so a token there adds friction rather than safety. If
|
|
25
29
|
it is bound to any other address, every caller must send `ADMIN_TOKEN` as a
|
|
26
30
|
bearer, including this machine and the app's own buttons, and the routes
|
|
27
31
|
refuse to run when it is unset. Reading the data folder's facts
|
|
28
|
-
(`GET /api/data`: its path and
|
|
29
|
-
every other read.
|
|
32
|
+
(`GET /api/data`: its path, sizes and backups) changes nothing and stays
|
|
33
|
+
open, like every other read.
|
|
30
34
|
- A localhost-bound service is still reachable by any web page you visit — the
|
|
31
35
|
binding keeps other machines out, not your own browser. Every mutating API
|
|
32
36
|
request is therefore refused when the browser reports it came from another
|
|
@@ -113,8 +117,10 @@ This app is designed to run **on your own machine, against your own network**.
|
|
|
113
117
|
|
|
114
118
|
Everything stays local:
|
|
115
119
|
|
|
116
|
-
- A CSV import is parsed in the browser
|
|
117
|
-
|
|
120
|
+
- A CSV import is parsed in the browser. Only what the map needs about each
|
|
121
|
+
person (no email addresses) goes to the app on this computer, which keeps it
|
|
122
|
+
in the data folder as `csv-network.json` until you remove it, apart from the
|
|
123
|
+
database. It is never uploaded anywhere.
|
|
118
124
|
- Scanned data and cached avatars are written to your machine and are gitignored.
|
|
119
125
|
The app shows photos only from those files, so looking at your network never
|
|
120
126
|
contacts LinkedIn.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { getDb, backupOptions } from '../../../../lib/db-client';
|
|
2
|
+
import { makeBackup, noteBackupFailure } from '../../../../lib/backups';
|
|
3
|
+
import { countPeople } from '../../../../lib/data-export';
|
|
4
|
+
|
|
5
|
+
// Settings → Your data → Back up now: a backup in backups/ like the daily ones
|
|
6
|
+
// (lib/backups.js), kept until the person deletes it. Nothing is taken from
|
|
7
|
+
// the request. Gated (lib/gate.js) with the routes that hand over or replace
|
|
8
|
+
// the whole network: it writes all of it to a file.
|
|
9
|
+
|
|
10
|
+
export async function POST() {
|
|
11
|
+
const db = getDb();
|
|
12
|
+
if (countPeople(db) === 0) {
|
|
13
|
+
return Response.json({ error: 'There’s no network here to back up yet.' }, { status: 409 });
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const made = makeBackup('manual', backupOptions(db));
|
|
17
|
+
return Response.json({
|
|
18
|
+
ok: true,
|
|
19
|
+
backup: { name: made.name, bytes: made.bytes, people: made.people, photos: made.photos, verified: made.verified },
|
|
20
|
+
});
|
|
21
|
+
} catch (err) {
|
|
22
|
+
noteBackupFailure('manual', err);
|
|
23
|
+
return Response.json({ error: `The backup couldn’t be made: ${err.message}` }, { status: 500 });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { dataDir } from '../../../../lib/db-client';
|
|
2
|
+
import { pendingImport } from '../../../../lib/data-import';
|
|
3
|
+
import { resolveProfile, networkCounts } from '../../../../lib/profile';
|
|
4
|
+
import {
|
|
5
|
+
readCsvNetwork, writeCsvNetwork, removeCsvNetwork, CsvStoreError, CSV_NETWORK_FILE,
|
|
6
|
+
} from '../../../../lib/csv-store';
|
|
7
|
+
|
|
8
|
+
// A LinkedIn Connections.csv import, kept in the data folder so it is still
|
|
9
|
+
// there after the window closes (lib/csv-store.js). The page reads the CSV and
|
|
10
|
+
// sends only what the map needs (lib/csv.js packConnections); nothing here
|
|
11
|
+
// sees the file itself.
|
|
12
|
+
//
|
|
13
|
+
// Gated with the other routes under /api/data (lib/gate.js): POST replaces the
|
|
14
|
+
// kept import, DELETE removes it, and GET hands it over, so all three answer
|
|
15
|
+
// only on this computer, as the server's bind address proves, never a header
|
|
16
|
+
// (TRAPS §2). POST and DELETE are writes, so middleware.js also refuses them
|
|
17
|
+
// from another site.
|
|
18
|
+
|
|
19
|
+
export async function GET() {
|
|
20
|
+
const { csv, problem } = readCsvNetwork(dataDir());
|
|
21
|
+
// Your scanned 1st-degree connections, under the profile the map shows
|
|
22
|
+
// (lib/profile.js): once there are any, pages show them instead of a kept
|
|
23
|
+
// CSV (lib/csv.js openNetworkSource).
|
|
24
|
+
let scanned;
|
|
25
|
+
try {
|
|
26
|
+
const me = resolveProfile({ create: false });
|
|
27
|
+
scanned = me ? networkCounts(me.id).first : 0;
|
|
28
|
+
} catch (err) {
|
|
29
|
+
return Response.json({ error: `Your network couldn't be read (${err.message}).` }, { status: 500 });
|
|
30
|
+
}
|
|
31
|
+
return Response.json({
|
|
32
|
+
csv,
|
|
33
|
+
scanned,
|
|
34
|
+
// Said, never shown as no import at all (TRAPS §7): the welcome screen
|
|
35
|
+
// puts this on the CSV card.
|
|
36
|
+
problem: problem ? `Your kept CSV import couldn't be read: ${problem}. Import Connections.csv again to replace it.` : null,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function POST(request) {
|
|
41
|
+
const dir = dataDir();
|
|
42
|
+
// An import from another computer waiting for the next start replaces the
|
|
43
|
+
// network's files, this one included: a CSV kept now would be set aside
|
|
44
|
+
// with what it replaces.
|
|
45
|
+
if (pendingImport(dir)) {
|
|
46
|
+
return Response.json({
|
|
47
|
+
error: 'A copy of a network is waiting to finish importing. Restart Six Degrees to finish it first (Settings → Your data says how), then import the CSV.',
|
|
48
|
+
}, { status: 409 });
|
|
49
|
+
}
|
|
50
|
+
let body;
|
|
51
|
+
try {
|
|
52
|
+
body = await request.json();
|
|
53
|
+
} catch {
|
|
54
|
+
return Response.json({ error: "The import didn't arrive whole, so nothing was kept. Try again." }, { status: 400 });
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
return Response.json({ ok: true, ...writeCsvNetwork(dir, body?.connections) });
|
|
58
|
+
} catch (err) {
|
|
59
|
+
if (err instanceof CsvStoreError) {
|
|
60
|
+
return Response.json({ error: `This import can't be kept (${err.message}), so nothing was saved.` }, { status: 400 });
|
|
61
|
+
}
|
|
62
|
+
return Response.json({ error: `The import couldn't be saved on this computer (${err.message}).` }, { status: 500 });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export async function DELETE() {
|
|
67
|
+
try {
|
|
68
|
+
return Response.json({ ok: true, removed: removeCsvNetwork(dataDir()) });
|
|
69
|
+
} catch (err) {
|
|
70
|
+
return Response.json({
|
|
71
|
+
error: `The import couldn't be removed (${err.message}). It is ${CSV_NETWORK_FILE} in your data folder.`,
|
|
72
|
+
}, { status: 500 });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -7,7 +7,7 @@ import { EXPORT_WORK_PREFIX, sweepLeftovers } from '../../../../lib/data-folder'
|
|
|
7
7
|
import { SCHEMA_SQL } from '../../../../db/schema';
|
|
8
8
|
import { APP_VERSION } from '../../../../lib/app-version';
|
|
9
9
|
|
|
10
|
-
//
|
|
10
|
+
// Export backup file…: a copy of the network to carry to another computer, one .sixdegrees
|
|
11
11
|
// file (lib/data-export.js), sent back as a download. A POST, so it takes a
|
|
12
12
|
// click on the app's own page (the cross-site guard applies), and gated with
|
|
13
13
|
// the other routes that hand over or replace everything (lib/gate.js).
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { getDb, dataDir, applySchema, backupsFolder } from '../../../../lib/db-client';
|
|
3
|
+
import { SCHEMA_SQL } from '../../../../db/schema';
|
|
4
|
+
import { APP_VERSION } from '../../../../lib/app-version';
|
|
5
|
+
import { countPeople } from '../../../../lib/data-export';
|
|
6
|
+
import { ImportError, pendingImport } from '../../../../lib/data-import';
|
|
7
|
+
import { findBackup, restoreBackup, restorePreflight } from '../../../../lib/backups';
|
|
8
|
+
import { scannerJob } from '../../../../lib/scan-state';
|
|
9
|
+
|
|
10
|
+
// Settings → Your data → Restore, on one backup: put that backup's network
|
|
11
|
+
// back. The same as importing it (lib/backups.js restoreBackup, through
|
|
12
|
+
// stageImport): checked first, applied at the next start (Restart now), and
|
|
13
|
+
// what is here kept in backups/ before anything is replaced.
|
|
14
|
+
//
|
|
15
|
+
// The body names a backup, {name, replace}: a name from backups/' own listing
|
|
16
|
+
// (lib/data-folder.js listBackups), never a path. Anything else is refused.
|
|
17
|
+
// `replace` is the number of people the person agreed to replace. Gated
|
|
18
|
+
// (lib/gate.js): it replaces the network.
|
|
19
|
+
|
|
20
|
+
export async function POST(request) {
|
|
21
|
+
let body = {};
|
|
22
|
+
try { body = await request.json(); } catch { /* refused below */ }
|
|
23
|
+
const name = typeof body?.name === 'string' ? body.name : '';
|
|
24
|
+
|
|
25
|
+
// The name first: one the folder doesn't hold is refused before anything else is asked.
|
|
26
|
+
if (!findBackup(backupsFolder(), name)) {
|
|
27
|
+
return Response.json({ error: 'There is no backup by that name in the backups folder.' }, { status: 404 });
|
|
28
|
+
}
|
|
29
|
+
const dir = path.resolve(dataDir());
|
|
30
|
+
const currentPeople = countPeople(getDb());
|
|
31
|
+
const refusal = restorePreflight({
|
|
32
|
+
scanRunning: scannerJob(),
|
|
33
|
+
pending: pendingImport(dir),
|
|
34
|
+
currentPeople,
|
|
35
|
+
confirmedPeople: Number(body?.replace),
|
|
36
|
+
});
|
|
37
|
+
if (refusal) return Response.json({ error: refusal.message, ...refusal.extra }, { status: refusal.status });
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const pending = restoreBackup(name, {
|
|
41
|
+
dir, backupsDir: backupsFolder(), applySchema, schemaSql: SCHEMA_SQL, appVersion: APP_VERSION, replacedPeople: currentPeople,
|
|
42
|
+
});
|
|
43
|
+
return Response.json({ ok: true, pending });
|
|
44
|
+
} catch (err) {
|
|
45
|
+
if (err instanceof ImportError) return Response.json({ error: err.message, ...err.extra }, { status: err.status });
|
|
46
|
+
return Response.json({ error: `The backup couldn’t be restored: ${err.message}` }, { status: 500 });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { dataDir } from '../../../../lib/db-client';
|
|
2
|
+
import { dataDir, backupsFolder } from '../../../../lib/db-client';
|
|
3
3
|
import { revealFolder } from '../../../../lib/data-folder';
|
|
4
|
+
import { findBackup } from '../../../../lib/backups';
|
|
4
5
|
|
|
5
|
-
// Show the data folder in Finder (or the Linux file browser)
|
|
6
|
-
//
|
|
7
|
-
//
|
|
6
|
+
// Show the data folder in Finder (or the Linux file browser), or one backup in
|
|
7
|
+
// it, selected: {backup: name}, a name from backups/' own listing, never a
|
|
8
|
+
// path (lib/backups.js findBackup). Nothing else is taken from the request.
|
|
9
|
+
// Gated (lib/gate.js) like every route that starts a process.
|
|
8
10
|
|
|
9
|
-
export async function POST() {
|
|
11
|
+
export async function POST(request) {
|
|
12
|
+
let body = {};
|
|
13
|
+
try { body = await request.json(); } catch { /* no body: the data folder */ }
|
|
14
|
+
if (body?.backup !== undefined) {
|
|
15
|
+
const folder = path.resolve(backupsFolder());
|
|
16
|
+
const found = findBackup(folder, body.backup, { restorable: false });
|
|
17
|
+
if (!found) return Response.json({ error: 'There is no backup by that name in the backups folder.' }, { status: 404 });
|
|
18
|
+
const file = path.join(folder, found.name);
|
|
19
|
+
const result = await revealFolder(folder, { select: file });
|
|
20
|
+
if (result.ok) return Response.json({ ok: true });
|
|
21
|
+
return Response.json({ error: `${result.message} The backup is ${file}`, path: file }, { status: 500 });
|
|
22
|
+
}
|
|
10
23
|
const dir = path.resolve(dataDir());
|
|
11
24
|
const result = await revealFolder(dir);
|
|
12
25
|
if (result.ok) return Response.json({ ok: true });
|
|
13
|
-
return Response.json({ error: `${result.message} The folder is ${dir}
|
|
26
|
+
return Response.json({ error: `${result.message} The folder is ${dir}`, path: dir }, { status: 500 });
|
|
14
27
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
|
-
import { getDb, dataDir, dbFile, AUTO_BACKUP_PREFIX } from '../../../lib/db-client';
|
|
3
|
+
import { getDb, dataDir, dbFile, backupsFolder, applySchema, AUTO_BACKUP_PREFIX } from '../../../lib/db-client';
|
|
4
4
|
import { folderReport } from '../../../lib/data-folder';
|
|
5
|
+
import { backupReport } from '../../../lib/backups';
|
|
6
|
+
import { SCHEMA_SQL } from '../../../db/schema';
|
|
7
|
+
import { APP_VERSION } from '../../../lib/app-version';
|
|
5
8
|
import { countPeople, referencedPhotos } from '../../../lib/data-export';
|
|
6
9
|
import {
|
|
7
10
|
pendingImport, lastImport, restartCodeFrom, restartAdvice, MAX_IMPORT_BYTES,
|
|
@@ -9,9 +12,11 @@ import {
|
|
|
9
12
|
import { projectRoot, isGitCheckout } from '../../../lib/paths';
|
|
10
13
|
import { installKind } from '../../../lib/release';
|
|
11
14
|
|
|
12
|
-
// Settings → Your data: where the network is kept, what it takes up,
|
|
13
|
-
// import waiting to finish. Sizes come from the file system
|
|
14
|
-
//
|
|
15
|
+
// Settings → Your data: where the network is kept, what it takes up, the
|
|
16
|
+
// backups, and any import waiting to finish. Sizes come from the file system,
|
|
17
|
+
// and chrome-profile/ is only reported as there or not. The one file read is
|
|
18
|
+
// the newest backup, checked as the importer would check it (once per file per
|
|
19
|
+
// server, lib/backups.js backupReport), so "verified" is never a guess. A read
|
|
15
20
|
// that changes nothing, so it stays open like every other read. The actions
|
|
16
21
|
// live under /api/data/… and are gated (lib/gate.js).
|
|
17
22
|
|
|
@@ -22,8 +27,14 @@ export async function GET() {
|
|
|
22
27
|
// A git checkout is its own kind here, as on the rest of the Settings page.
|
|
23
28
|
const kind = isGitCheckout() ? 'git' : installKind(process.env, projectRoot());
|
|
24
29
|
const custom = dir !== path.join(homedir(), '.six-degrees');
|
|
30
|
+
// One entry per backup (a database copy and its folder of photos are one), newest first.
|
|
31
|
+
const { backups, ...backupStatus } = backupReport(path.resolve(backupsFolder()), {
|
|
32
|
+
applySchema, schemaSql: SCHEMA_SQL, appVersion: APP_VERSION,
|
|
33
|
+
});
|
|
25
34
|
return Response.json({
|
|
26
35
|
...folderReport({ dir, dbFile: path.resolve(dbFile()), autoPrefix: AUTO_BACKUP_PREFIX, inNetwork: referencedPhotos(db) }),
|
|
36
|
+
backups,
|
|
37
|
+
backupStatus,
|
|
27
38
|
people: countPeople(db),
|
|
28
39
|
platform: process.platform,
|
|
29
40
|
kind,
|
|
@@ -322,7 +322,7 @@ export async function POST(request) {
|
|
|
322
322
|
user_id: userId || null,
|
|
323
323
|
type: 'request_accepted',
|
|
324
324
|
title: `${p.name} accepted! +${XP_ACCEPT[p.tier] || 5} XP`,
|
|
325
|
-
message: `${p.tier}-Tier connection
|
|
325
|
+
message: `${p.tier}-Tier connection: bridge their cluster to reach D3`,
|
|
326
326
|
icon: '🤝',
|
|
327
327
|
data: { personId: p.id, viaId: p.source_connection_id ?? null, tier: p.tier ?? null },
|
|
328
328
|
}))
|
|
@@ -59,7 +59,7 @@ export async function POST(request) {
|
|
|
59
59
|
await supabase.from('notifications').insert([{
|
|
60
60
|
type: 'connection_accepted',
|
|
61
61
|
title: `${item.name} accepted!`,
|
|
62
|
-
message: `+${item.xp_reward} XP
|
|
62
|
+
message: `+${item.xp_reward} XP · Ready to scan their cluster`,
|
|
63
63
|
icon: '🎉',
|
|
64
64
|
}]);
|
|
65
65
|
}
|
|
@@ -3,16 +3,19 @@ import { existsSync, readFileSync, mkdirSync, mkdtempSync, rmSync } from 'node:f
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { projectRoot, dataDir } from '../../../lib/paths';
|
|
5
5
|
import { resolveProfile, networkCounts } from '../../../lib/profile';
|
|
6
|
-
import { scanProgress } from '../../../lib/scan-progress';
|
|
7
|
-
import { linkedinState, writeLimits, liftCooldown } from '../../../lib/linkedin-limits';
|
|
6
|
+
import { scanProgress, mappingNow } from '../../../lib/scan-progress';
|
|
7
|
+
import { linkedinState, linkedinUsage, writeLimits, liftCooldown } from '../../../lib/linkedin-limits';
|
|
8
8
|
import { pausedList, readProgress, readUnclear } from '../../../lib/paused';
|
|
9
|
-
import { getDb } from '../../../lib/db-client';
|
|
9
|
+
import { getDb, backUpDailyIfDue } from '../../../lib/db-client';
|
|
10
10
|
import { db as notesDb } from '../../../lib/db';
|
|
11
11
|
import { scanDoneNotification } from '../../../lib/notifications';
|
|
12
12
|
import { registerScanState } from '../../../lib/scan-state';
|
|
13
13
|
import { pendingImport } from '../../../lib/data-import';
|
|
14
14
|
import { waitingPhotoCount } from '../../../lib/photos';
|
|
15
|
+
import { readSettings } from '../../../lib/settings';
|
|
16
|
+
import { riskAccepted, touchesLinkedIn, RISK_REFUSAL } from '../../../lib/scan-risk';
|
|
15
17
|
import { reachIndex, circleState } from '../../../lib/reach';
|
|
18
|
+
import { chromeInstalled, signedInFrom, SIGNED_IN_FILE, CHROME_REFUSAL } from '../../../lib/scanner-setup';
|
|
16
19
|
import {
|
|
17
20
|
pythonLooker, thisHostKey, scannerCommand, installSteps, downloadedPython, downloadVerified,
|
|
18
21
|
placeDownloadedPython, sweepSetupLeftovers, megabytes, SETUP_WORK_PREFIX, ScannerSetupError,
|
|
@@ -47,6 +50,7 @@ const state = registerScanState({
|
|
|
47
50
|
stderrTail: [],
|
|
48
51
|
failure: null, // the last lines of stderr from a run that failed — its reason
|
|
49
52
|
pages: 0, // pages the running scan has read: the dots along the header's line (app/components/ScanTrail.js)
|
|
53
|
+
found: [], // how many people each of those pages found: the Scan page's cluster (app/components/ScanRadar.js)
|
|
50
54
|
});
|
|
51
55
|
|
|
52
56
|
// A page read, as scripts/scrape.py prints it: " Page 3... " as a circle or a
|
|
@@ -54,6 +58,10 @@ const state = registerScanState({
|
|
|
54
58
|
// people of your own connections list. Counted as the lines arrive, since the
|
|
55
59
|
// log only keeps its last MAX_LOG lines.
|
|
56
60
|
const PAGE_READ = /^\s*Page \d+\.\.\.|\d+\s*\/\s*\d+\s+collected/;
|
|
61
|
+
// What a page found, which the scanner prints after "Page N... " once it's read:
|
|
62
|
+
// "10 found (total: 30)" in a circle, "7 found (2 with images)" for a company.
|
|
63
|
+
const PAGE_FOUND = /(\d+) found \((?:total: \d+|\d+ with images)\)/;
|
|
64
|
+
const MAX_PAGES_KEPT = 400;
|
|
57
65
|
|
|
58
66
|
/** Stop the running job without orphaning the browser it opened.
|
|
59
67
|
*
|
|
@@ -83,7 +91,7 @@ function stopChild() {
|
|
|
83
91
|
spawn('taskkill', ['/pid', String(pid), '/T'], { stdio: 'ignore', windowsHide: true }).on('error', () => {});
|
|
84
92
|
setTimeout(() => {
|
|
85
93
|
if (state.child && state.child.pid === pid) {
|
|
86
|
-
push('Still running
|
|
94
|
+
push('Still running. Forcing it to stop.');
|
|
87
95
|
spawn('taskkill', ['/pid', String(pid), '/T', '/F'], { stdio: 'ignore', windowsHide: true }).on('error', () => {});
|
|
88
96
|
}
|
|
89
97
|
}, 5000);
|
|
@@ -94,7 +102,7 @@ function stopChild() {
|
|
|
94
102
|
|
|
95
103
|
setTimeout(() => {
|
|
96
104
|
if (state.child && state.child.pid === pid) {
|
|
97
|
-
push('Still running
|
|
105
|
+
push('Still running. Forcing it to stop.');
|
|
98
106
|
try { process.kill(-pid, 'SIGKILL'); }
|
|
99
107
|
catch { try { child.kill('SIGKILL'); } catch {} }
|
|
100
108
|
}
|
|
@@ -106,7 +114,14 @@ function push(line) {
|
|
|
106
114
|
const t = part.replace(/\s+$/, '');
|
|
107
115
|
if (!t) continue;
|
|
108
116
|
state.log.push(t);
|
|
109
|
-
if (PAGE_READ.test(t))
|
|
117
|
+
if (PAGE_READ.test(t)) {
|
|
118
|
+
state.pages += 1;
|
|
119
|
+
// Fifty of your own list at a time; a page's count comes on its next line.
|
|
120
|
+
state.found.push(/collected/.test(t) ? 50 : 0);
|
|
121
|
+
if (state.found.length > MAX_PAGES_KEPT) state.found.splice(0, state.found.length - MAX_PAGES_KEPT);
|
|
122
|
+
}
|
|
123
|
+
const got = t.match(PAGE_FOUND);
|
|
124
|
+
if (got && state.found.length) state.found[state.found.length - 1] = Number(got[1]);
|
|
110
125
|
}
|
|
111
126
|
if (state.log.length > MAX_LOG) state.log.splice(0, state.log.length - MAX_LOG);
|
|
112
127
|
}
|
|
@@ -208,12 +223,12 @@ function pickedPerson(id) {
|
|
|
208
223
|
}
|
|
209
224
|
}
|
|
210
225
|
|
|
211
|
-
// The
|
|
212
|
-
//
|
|
213
|
-
//
|
|
214
|
-
// running job
|
|
215
|
-
// every call: the page polls every 1.5 s,
|
|
216
|
-
// 4 s looks stuck.
|
|
226
|
+
// The look for a Python spawns processes, so it is cached for a few seconds,
|
|
227
|
+
// and callers that arrive while a look is under way share it rather than each
|
|
228
|
+
// starting their own Pythons. Everything else (Chrome and signed in, which are
|
|
229
|
+
// file checks; the running job, its log, how far it has got; the counts) is
|
|
230
|
+
// read fresh on every call: the page polls every 1.5 s, a progress bar that
|
|
231
|
+
// moves every 4 s looks stuck, and step 1 ticks the moment Chrome is installed.
|
|
217
232
|
let cached = { at: 0, value: null };
|
|
218
233
|
let looking = null;
|
|
219
234
|
let lookGeneration = 0;
|
|
@@ -251,26 +266,38 @@ async function look() {
|
|
|
251
266
|
host: hostOnce(),
|
|
252
267
|
});
|
|
253
268
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
process.platform === 'darwin' ? existsSync('/Applications/Google Chrome.app')
|
|
257
|
-
: process.platform === 'linux' ? existsSync('/opt/google/chrome/chrome')
|
|
258
|
-
: process.platform === 'win32' ? windowsChrome()
|
|
259
|
-
: true; // elsewhere Playwright resolves the channel itself
|
|
269
|
+
return { root, python };
|
|
270
|
+
}
|
|
260
271
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
272
|
+
/** Google Chrome, where Playwright's "chrome" channel looks (lib/scanner-setup.js). A file check, so cheap enough for every POST. */
|
|
273
|
+
function chromeHere() {
|
|
274
|
+
return chromeInstalled({ platform: process.platform, env: process.env, exists: existsSync });
|
|
275
|
+
}
|
|
264
276
|
|
|
265
|
-
|
|
277
|
+
/**
|
|
278
|
+
* Signed in to LinkedIn in the scanner's Chrome: the scanner's own note once
|
|
279
|
+
* it has confirmed the session (lib/scanner-setup.js signedInFrom). A folder
|
|
280
|
+
* from before the note goes by Chrome's cookie file, as it always did; Windows'
|
|
281
|
+
* Chrome keeps that one folder down, in Default\Network.
|
|
282
|
+
*/
|
|
283
|
+
function signedIn() {
|
|
284
|
+
const data = dataDir();
|
|
285
|
+
let note = null;
|
|
286
|
+
try { note = JSON.parse(readFileSync(path.join(data, SIGNED_IN_FILE), 'utf8')); } catch { /* none yet, or unreadable: the old check */ }
|
|
287
|
+
const profile = path.join(data, 'chrome-profile', 'Default');
|
|
288
|
+
return signedInFrom({
|
|
289
|
+
note,
|
|
290
|
+
profile: existsSync(path.join(data, 'chrome-profile')),
|
|
291
|
+
cookies: existsSync(path.join(profile, 'Cookies')) || existsSync(path.join(profile, 'Network', 'Cookies')),
|
|
292
|
+
});
|
|
266
293
|
}
|
|
267
294
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
295
|
+
// The "I understand" before the first scan: given on the Scan page, or implied by
|
|
296
|
+
// the scanner's own Chrome profile, which only a scan before it could have made.
|
|
297
|
+
function scanRisk() {
|
|
298
|
+
let acceptedAt = null;
|
|
299
|
+
try { acceptedAt = readSettings(getDb()).scanRiskAccepted; } catch { /* unreadable: ask */ }
|
|
300
|
+
return riskAccepted({ acceptedAt, scannedBefore: existsSync(path.join(dataDir(), 'chrome-profile')) });
|
|
274
301
|
}
|
|
275
302
|
|
|
276
303
|
function machineChecks() {
|
|
@@ -309,6 +336,7 @@ function paused(userId) {
|
|
|
309
336
|
|
|
310
337
|
async function status() {
|
|
311
338
|
const m = await machineChecks();
|
|
339
|
+
const chrome = chromeHere();
|
|
312
340
|
|
|
313
341
|
// How much is already mapped, by degree, so the page can mark the scan step
|
|
314
342
|
// done and offer the way to the galaxy instead of leaving someone on a form.
|
|
@@ -325,7 +353,9 @@ async function status() {
|
|
|
325
353
|
|
|
326
354
|
const py = m.python;
|
|
327
355
|
return {
|
|
328
|
-
ready: Boolean(m.root && py.run &&
|
|
356
|
+
ready: Boolean(m.root && py.run && chrome),
|
|
357
|
+
// Whose circle is being read now, for the Scan page's "Watch it fill in".
|
|
358
|
+
mapping: mappingWho(me?.id),
|
|
329
359
|
checks: {
|
|
330
360
|
scriptsFound: Boolean(m.root),
|
|
331
361
|
// A Python that runs the scanner, or one Install can build its environment from.
|
|
@@ -344,8 +374,10 @@ async function status() {
|
|
|
344
374
|
systemPython: py.systemFound,
|
|
345
375
|
// What "Set up the scanner" would download, when there is nothing to install from.
|
|
346
376
|
download: py.download ? { version: py.download.version, size: py.download.size, from: 'github.com' } : null,
|
|
347
|
-
chrome
|
|
348
|
-
signedIn:
|
|
377
|
+
chrome,
|
|
378
|
+
signedIn: signedIn(),
|
|
379
|
+
// The one-time "I understand" before the first scan (lib/scan-risk.js).
|
|
380
|
+
riskAccepted: scanRisk(),
|
|
349
381
|
},
|
|
350
382
|
network,
|
|
351
383
|
photosWaiting,
|
|
@@ -356,6 +388,28 @@ async function status() {
|
|
|
356
388
|
};
|
|
357
389
|
}
|
|
358
390
|
|
|
391
|
+
/**
|
|
392
|
+
* Whose circle the running scan is reading: { id, name } of one of your
|
|
393
|
+
* connections, or null. A scan of one person knows its target; a batch (Map
|
|
394
|
+
* 2nd degree, every paused list) prints each person's name as it starts
|
|
395
|
+
* (lib/scan-progress.js mappingNow), found here among your connections. Two
|
|
396
|
+
* with that name can't be told apart that way, so neither is named.
|
|
397
|
+
*/
|
|
398
|
+
function mappingWho(userId) {
|
|
399
|
+
if (!state.running) return null;
|
|
400
|
+
if (state.target?.id && ['bridge', 'rescrape', 'resume'].includes(state.action)) return { id: state.target.id, name: state.target.name };
|
|
401
|
+
const name = mappingNow(state.log, state.action);
|
|
402
|
+
if (!name || !userId) return null;
|
|
403
|
+
try {
|
|
404
|
+
const rows = getDb().prepare(
|
|
405
|
+
'SELECT id FROM linkedin_connections WHERE user_id = ? AND degree = 1 AND name = ? LIMIT 2',
|
|
406
|
+
).all(userId, name);
|
|
407
|
+
return rows.length === 1 ? { id: rows[0].id, name } : null;
|
|
408
|
+
} catch {
|
|
409
|
+
return null;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
359
413
|
/**
|
|
360
414
|
* The running job alone, from memory: no checks, no database. Every Scan
|
|
361
415
|
* button in the app asks this (lib/scraper-client.js watchScanner), every few
|
|
@@ -375,6 +429,7 @@ function job() {
|
|
|
375
429
|
failure: state.running ? null : state.failure,
|
|
376
430
|
progress: state.running ? scanProgress(state.log, state.action) : null,
|
|
377
431
|
pages: state.running ? state.pages : 0,
|
|
432
|
+
found: state.running ? state.found : [],
|
|
378
433
|
log: state.log.slice(-120),
|
|
379
434
|
recent: state.recent,
|
|
380
435
|
budget: state.running ? budgetNow() : null,
|
|
@@ -425,6 +480,16 @@ export async function GET(request) {
|
|
|
425
480
|
if (q.has('job')) return Response.json(job());
|
|
426
481
|
if (q.has('resume')) return Response.json({ resume: resumePoint(q.get('resume')) });
|
|
427
482
|
if (q.has('reach')) return Response.json(scanNotes());
|
|
483
|
+
// Settings → LinkedIn usage: the scanner's record of searches, profile views
|
|
484
|
+
// and pauses, counted (lib/linkedin-limits.js linkedinUsage). Reads only; no
|
|
485
|
+
// checks, no Python, nothing written.
|
|
486
|
+
if (q.has('usage')) {
|
|
487
|
+
try {
|
|
488
|
+
return Response.json(linkedinUsage(dataDir()));
|
|
489
|
+
} catch {
|
|
490
|
+
return Response.json({ error: 'The record of LinkedIn searches on this computer could not be read.' }, { status: 500 });
|
|
491
|
+
}
|
|
492
|
+
}
|
|
428
493
|
if (q.has('person')) return Response.json(pickedPerson(q.get('person')));
|
|
429
494
|
return Response.json(await status());
|
|
430
495
|
}
|
|
@@ -586,6 +651,17 @@ export async function POST(request) {
|
|
|
586
651
|
if (!Object.hasOwn(ACTIONS, action)) {
|
|
587
652
|
return Response.json({ error: `Unknown action '${action}'` }, { status: 400 });
|
|
588
653
|
}
|
|
654
|
+
// Nothing opens LinkedIn before the one-time "I understand" on the Scan page,
|
|
655
|
+
// whichever button asked (lib/scan-risk.js).
|
|
656
|
+
if (touchesLinkedIn(action) && !scanRisk()) {
|
|
657
|
+
return Response.json({ error: RISK_REFUSAL, needsRiskAcceptance: true }, { status: 409 });
|
|
658
|
+
}
|
|
659
|
+
// Nor without Google Chrome, which the scanner drives: the Scan page's step 1
|
|
660
|
+
// says so in the same words, and every other button is told here, before
|
|
661
|
+
// anything starts, rather than by a Playwright error at the end of a log.
|
|
662
|
+
if (touchesLinkedIn(action) && !chromeHere()) {
|
|
663
|
+
return Response.json({ error: CHROME_REFUSAL, needsChrome: true }, { status: 409 });
|
|
664
|
+
}
|
|
589
665
|
|
|
590
666
|
const spec = ACTIONS[action];
|
|
591
667
|
const maxBridges = Number.isInteger(body.maxBridges) && body.maxBridges > 0
|
|
@@ -645,7 +721,7 @@ export async function POST(request) {
|
|
|
645
721
|
}
|
|
646
722
|
const cooldown = linkedinState(dataDir()).cooldown;
|
|
647
723
|
if (searches && cooldown) {
|
|
648
|
-
return Response.json({ error: `Scanning is paused until ${new Date(cooldown.until).toLocaleString()}
|
|
724
|
+
return Response.json({ error: `Scanning is paused until ${new Date(cooldown.until).toLocaleString()}: ${cooldown.reason}.`, cooldown }, { status: 409 });
|
|
649
725
|
}
|
|
650
726
|
if (state.running) {
|
|
651
727
|
return Response.json({ error: 'Something is already running.', action: state.action }, { status: 409 });
|
|
@@ -714,6 +790,7 @@ export async function POST(request) {
|
|
|
714
790
|
state.startedAt = Date.now();
|
|
715
791
|
state.log = [spec.label + (target?.name ? ` ${target.name}…` : '…')];
|
|
716
792
|
state.pages = 0;
|
|
793
|
+
state.found = [];
|
|
717
794
|
state.stderrTail = [];
|
|
718
795
|
state.failure = null;
|
|
719
796
|
forgetChecks();
|
|
@@ -766,6 +843,17 @@ export async function POST(request) {
|
|
|
766
843
|
try { cleanup(); } catch { /* swept at the next setup (sweepSetupLeftovers) */ }
|
|
767
844
|
}
|
|
768
845
|
forgetChecks();
|
|
846
|
+
// The daily backup, once a scan may have changed the network (lib/backups.js):
|
|
847
|
+
// checked here and when the server starts, never on a timer. Setting the
|
|
848
|
+
// scanner up and signing in change nothing in it.
|
|
849
|
+
if (!['install', 'setup', 'login'].includes(state.action)) {
|
|
850
|
+
try {
|
|
851
|
+
const daily = backUpDailyIfDue();
|
|
852
|
+
if (daily) push('Made today’s backup of your network (Settings → Your data).');
|
|
853
|
+
} catch (err) {
|
|
854
|
+
push(`Today’s backup couldn’t be made: ${err.message}`);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
769
857
|
}
|
|
770
858
|
|
|
771
859
|
function runStep(i) {
|
|
@@ -5,7 +5,8 @@ import { socialFiles, readJson, writeJsonAtomic } from '../../../../lib/social-s
|
|
|
5
5
|
// The Social tab's CRM: your own stage, tags, notes and next follow-up for each
|
|
6
6
|
// person, in crm-<profile>.json in the data folder (lib/social-crm.js has the
|
|
7
7
|
// shape). Yours, so always kept, whatever Keep my messages says; never sent
|
|
8
|
-
// anywhere,
|
|
8
|
+
// anywhere, never in Six Degrees' own backups (lib/backups.js BACKUP_SOCIAL),
|
|
9
|
+
// and in "Export backup file…" only when its Social box is ticked.
|
|
9
10
|
//
|
|
10
11
|
// GET the whole store
|
|
11
12
|
// PATCH { key, set: { stage?, tags?, notes?, followUp? } } one person's
|