six-degrees 0.2.1 → 0.3.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 +10 -0
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +39 -11
- package/.next/standalone/.next/required-server-files.json +4 -1
- package/.next/standalone/.next/routes-manifest.json +60 -0
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- 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.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 +10 -10
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +9 -9
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/admin-delete/route.js +3 -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 +3 -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 +3 -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 +3 -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/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/company-scores/legacy/route/build-manifest.json +12 -0
- package/.next/standalone/.next/server/app/api/company-scores/legacy/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js +9 -0
- package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/company-scores/legacy/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/company-scores/route.js +3 -2
- 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 +3 -2
- package/.next/standalone/.next/server/app/api/connections/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/export/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/data/export/route/build-manifest.json +12 -0
- package/.next/standalone/.next/server/app/api/data/export/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/data/export/route.js +7 -0
- package/.next/standalone/.next/server/app/api/data/export/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/data/export/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/data/export/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/data/import/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/data/import/route/build-manifest.json +12 -0
- package/.next/standalone/.next/server/app/api/data/import/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/data/import/route.js +8 -0
- package/.next/standalone/.next/server/app/api/data/import/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/data/import/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/data/import/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/data/restart/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/data/restart/route/build-manifest.json +12 -0
- package/.next/standalone/.next/server/app/api/data/restart/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/data/restart/route.js +8 -0
- package/.next/standalone/.next/server/app/api/data/restart/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/data/restart/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/data/restart/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/data/reveal/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/data/reveal/route/build-manifest.json +12 -0
- package/.next/standalone/.next/server/app/api/data/reveal/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/data/reveal/route.js +7 -0
- package/.next/standalone/.next/server/app/api/data/reveal/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/data/reveal/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/data/reveal/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/data/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/data/route/build-manifest.json +12 -0
- package/.next/standalone/.next/server/app/api/data/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/data/route.js +7 -0
- package/.next/standalone/.next/server/app/api/data/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/data/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/data/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/delete-cluster/route.js +3 -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 +3 -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 +3 -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 -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 +3 -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 +3 -2
- package/.next/standalone/.next/server/app/api/scraper/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/settings/route/build-manifest.json +12 -0
- package/.next/standalone/.next/server/app/api/settings/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/settings/route.js +9 -0
- package/.next/standalone/.next/server/app/api/settings/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/settings/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/settings/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/settings/sector-preview/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/settings/sector-preview/route/build-manifest.json +12 -0
- package/.next/standalone/.next/server/app/api/settings/sector-preview/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js +8 -0
- package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/settings/sector-preview/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route/build-manifest.json +12 -0
- package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js +8 -0
- package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/setup-profile/route.js +3 -2
- package/.next/standalone/.next/server/app/api/setup-profile/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/unlock/route.js +3 -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 +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 +3 -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 +3 -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 +2 -1
- package/.next/standalone/.next/server/app/avatars/[file]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/favicon.ico/route.js +2 -1
- package/.next/standalone/.next/server/app/favicon.ico/route.js.nft.json +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 +12 -12
- package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/import.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/import.segments/import/__PAGE__.segment.rsc +11 -11
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +12 -12
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +11 -11
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +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 +12 -12
- package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/launch.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/launch.segments/launch/__PAGE__.segment.rsc +11 -11
- 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.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 +12 -12
- package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/paths.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/paths.segments/paths/__PAGE__.segment.rsc +11 -11
- 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 +12 -12
- package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/profile.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/profile.segments/profile/__PAGE__.segment.rsc +11 -11
- 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 +12 -12
- package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/queue.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/queue.segments/queue/__PAGE__.segment.rsc +11 -11
- package/.next/standalone/.next/server/app/settings/page/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/settings/page/build-manifest.json +20 -0
- package/.next/standalone/.next/server/app/settings/page/next-font-manifest.json +11 -0
- package/.next/standalone/.next/server/app/settings/page/react-loadable-manifest.json +1 -0
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/settings/page.js +13 -0
- package/.next/standalone/.next/server/app/settings/page.js.map +5 -0
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/settings.html +1 -0
- package/.next/standalone/.next/server/app/settings.meta +26 -0
- package/.next/standalone/.next/server/app/settings.rsc +24 -0
- package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +24 -0
- package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +4 -0
- package/.next/standalone/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +28 -0
- 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 +12 -12
- package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +11 -11
- package/.next/standalone/.next/server/app-paths-manifest.json +10 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-rnla2._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__00la_y0._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__07t47cm._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cj5jqc._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e0fei3._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0i5hdu4._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ljcioj._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ljnyho._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o5-tcg._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qrnous._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t3v1a1._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0uag-k5._.js +8 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0um1uey._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wmexuc._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0xu34sz._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__133knx1._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__14ou7j5._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__15-17hl._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__16iu0hv._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__19b7mig._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1bbcwub._.js +8 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1eris29._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1gjo_cq._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1kbl21f._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qcm08_._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rphsdk._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1t3rugi._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1w25q0m._.js +3 -0
- package/.next/standalone/.next/server/chunks/_072jl0y._.js +3 -0
- package/.next/standalone/.next/server/chunks/_0lw8_i0._.js +3 -0
- package/.next/standalone/.next/server/chunks/_1_fynia._.js +21 -3
- package/.next/standalone/.next/server/chunks/_1fn30_l._.js +3 -0
- package/.next/standalone/.next/server/chunks/_1itd1o_._.js +2 -1
- package/.next/standalone/.next/server/chunks/_1iwkh8t._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1mxn_lb._.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_company-scores_legacy_route_actions_1ncspu_.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_export_route_actions_1lkimty.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_import_route_actions_1eji0kd.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_restart_route_actions_00_-u6o.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_reveal_route_actions_0-moqtn.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_route_actions_0j0w5ep.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_settings_route_actions_1bpm9ac.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_settings_sector-preview_route_actions_0w79454.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_settings_sector-suggestions_route_actions_1eoqugp.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_db-client_15le7cw.js +155 -0
- package/.next/standalone/.next/server/chunks/{lib_rpc_0mc73lk.js → lib_rpc_00tx2sm.js} +1 -1
- package/.next/standalone/.next/server/chunks/lib_rpc_02-qa4d.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_02ndsg2.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_08q5vp6.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0_8i3ft.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0c9d9ti.js +5 -2
- package/.next/standalone/.next/server/chunks/lib_rpc_0huvw-3.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0ip2vdh.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0jzisgh.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0yi9xvd.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1jyhd0o.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1kn59-i.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1q2jkza.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1vpm1sk.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1x6p_31.js +3 -0
- package/.next/standalone/.next/server/chunks/node_modules_next_1zc5q0a._.js +158 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0mocm6d._.js → [root-of-the-server]__0an6blh._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1m0255u._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0bipr5s._.js → [root-of-the-server]__1z1j3ek._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_07u8byv._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_08r_mlf._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{_0ggabjc._.js → _0942v8n._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_1djpk8t._.js → _0hl_t7r._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_0tb83dw._.js +132 -0
- package/.next/standalone/.next/server/chunks/ssr/_1-87bs1._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_17gui6a._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_settings_page_actions_11x4dq5.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_launch_page_19t0dyd.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +4 -4
- 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 +5 -5
- package/.next/standalone/.next/server/chunks/ssr/app_settings_page_1f8mjj_.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_setup_page_1-282zx.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/lib_0i8v-s3._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_1f8t_rp._.js +23 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_1nkgb45._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules_01xbj_9._.js → node_modules_1wax83z._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_00nap8h._.js → node_modules_next_dist_1bunoni._.js} +2 -2
- package/.next/standalone/.next/server/edge/chunks/[root-of-the-server]__0pco7a6._.js +2 -2
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/middleware-manifest.json +15 -7
- 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/06x3jiiz96m5t.js +1 -0
- package/.next/standalone/.next/static/chunks/{34at5d2ifl62i.js → 0ngx9s6-zgshe.js} +5 -5
- package/.next/standalone/.next/static/chunks/0q-_khndfxubv.js +2 -0
- package/.next/standalone/.next/static/chunks/1c79veqedvubt.js +1 -0
- package/.next/standalone/.next/static/chunks/1chp3nx45meg5.js +44 -0
- package/.next/standalone/.next/static/chunks/1irqj0lf-fu3d.js +1 -0
- package/.next/standalone/.next/static/chunks/1uadqylrod5_v.js +1 -0
- package/.next/standalone/.next/static/chunks/23u0zclgwpc4d.js +1 -0
- package/.next/standalone/.next/static/chunks/289ktj97di6zg.js +1 -0
- package/.next/standalone/.next/static/chunks/2b3lmf8e6uj8m.js +16 -0
- package/.next/standalone/.next/static/chunks/2jz311xl1pp_8.js +1 -0
- package/.next/standalone/.next/static/chunks/3npq5yd7c4dmn.js +2 -0
- package/.next/standalone/.next/static/qqqcxvzBUizkECrT4swyK/_clientMiddlewareManifest.js +14 -0
- package/.next/standalone/CHANGELOG.md +298 -0
- package/.next/standalone/CONTRIBUTING.md +5 -2
- package/.next/standalone/README.md +138 -30
- package/.next/standalone/SECURITY.md +117 -10
- package/.next/standalone/app/api/company-scores/legacy/route.js +32 -0
- package/.next/standalone/app/api/company-scores/route.js +20 -11
- package/.next/standalone/app/api/data/export/route.js +49 -0
- package/.next/standalone/app/api/data/import/route.js +83 -0
- package/.next/standalone/app/api/data/restart/route.js +37 -0
- package/.next/standalone/app/api/data/reveal/route.js +14 -0
- package/.next/standalone/app/api/data/route.js +39 -0
- package/.next/standalone/app/api/ingest/route.js +15 -47
- package/.next/standalone/app/api/scraper/route.js +264 -125
- package/.next/standalone/app/api/settings/route.js +58 -0
- package/.next/standalone/app/api/settings/sector-preview/route.js +38 -0
- package/.next/standalone/app/api/settings/sector-suggestions/route.js +20 -0
- package/.next/standalone/app/api/update/route.js +188 -23
- package/.next/standalone/app/avatars/[file]/route.js +4 -2
- package/.next/standalone/app/components/CompanyScores.js +28 -7
- package/.next/standalone/app/components/EmptyState.js +8 -0
- package/.next/standalone/app/components/ForceGraph.js +39 -35
- package/.next/standalone/app/components/LegacyScoresCard.js +129 -0
- package/.next/standalone/app/components/Sidebar.js +11 -10
- package/.next/standalone/app/components/UpdatePanel.js +306 -119
- package/.next/standalone/app/components/UserProvider.js +4 -3
- package/.next/standalone/app/components/settings/DataSection.js +437 -0
- package/.next/standalone/app/components/settings/SectorSection.js +445 -0
- package/.next/standalone/app/components/ui.js +62 -0
- package/.next/standalone/app/launch/page.js +30 -20
- package/.next/standalone/app/page.js +13 -0
- package/.next/standalone/app/paths/page.js +12 -4
- package/.next/standalone/app/profile/page.js +41 -8
- package/.next/standalone/app/queue/page.js +8 -2
- package/.next/standalone/app/settings/page.js +96 -0
- package/.next/standalone/app/setup/page.js +32 -16
- package/.next/standalone/bin/args.mjs +44 -0
- package/.next/standalone/bin/six-degrees.mjs +9 -15
- package/.next/standalone/lib/companies.js +44 -119
- package/.next/standalone/lib/csv.js +8 -0
- package/.next/standalone/lib/data-export.js +170 -0
- package/.next/standalone/lib/data-folder.js +238 -0
- package/.next/standalone/lib/data-import.js +878 -0
- package/.next/standalone/lib/db-client.js +48 -3
- package/.next/standalone/lib/durable.js +73 -0
- package/.next/standalone/lib/gate.js +90 -1
- package/.next/standalone/lib/ingest.js +40 -0
- package/.next/standalone/lib/legacy-offer.js +185 -0
- package/.next/standalone/lib/legacy-scores.js +77 -0
- package/.next/standalone/lib/linkedin-limits.js +124 -1
- package/.next/standalone/lib/rpc.js +121 -13
- package/.next/standalone/lib/sample-stats.js +16 -0
- package/.next/standalone/lib/scan-progress.js +13 -0
- package/.next/standalone/lib/scan-state.js +53 -0
- package/.next/standalone/lib/scanner-python.js +685 -0
- package/.next/standalone/lib/scanner-setup.js +104 -0
- package/.next/standalone/lib/scoring.js +747 -138
- package/.next/standalone/lib/scraper-client.js +9 -5
- package/.next/standalone/lib/sector-directory.js +1532 -0
- package/.next/standalone/lib/sector-focus.js +163 -0
- package/.next/standalone/lib/sector-labels.js +81 -0
- package/.next/standalone/lib/settings-effects.js +59 -0
- package/.next/standalone/lib/settings.js +83 -0
- package/.next/standalone/lib/updater-job.js +838 -0
- package/.next/standalone/lib/updater.js +494 -0
- package/.next/standalone/middleware.js +25 -28
- package/.next/standalone/next.config.mjs +19 -3
- package/.next/standalone/package-lock.json +2 -2
- package/.next/standalone/package.json +1 -2
- package/.next/standalone/scripts/apply-update.sh +482 -0
- package/.next/standalone/scripts/build-app.mjs +251 -9
- package/.next/standalone/scripts/requirements.txt +106 -4
- package/.next/standalone/scripts/test-release-server.mjs +143 -0
- package/.next/standalone/server.js +1 -1
- package/.next/static/chunks/06x3jiiz96m5t.js +1 -0
- package/.next/static/chunks/{34at5d2ifl62i.js → 0ngx9s6-zgshe.js} +5 -5
- package/.next/static/chunks/0q-_khndfxubv.js +2 -0
- package/.next/static/chunks/1c79veqedvubt.js +1 -0
- package/.next/static/chunks/1chp3nx45meg5.js +44 -0
- package/.next/static/chunks/1irqj0lf-fu3d.js +1 -0
- package/.next/static/chunks/1uadqylrod5_v.js +1 -0
- package/.next/static/chunks/23u0zclgwpc4d.js +1 -0
- package/.next/static/chunks/289ktj97di6zg.js +1 -0
- package/.next/static/chunks/2b3lmf8e6uj8m.js +16 -0
- package/.next/static/chunks/2jz311xl1pp_8.js +1 -0
- package/.next/static/chunks/3npq5yd7c4dmn.js +2 -0
- package/.next/static/qqqcxvzBUizkECrT4swyK/_clientMiddlewareManifest.js +14 -0
- package/CHANGELOG.md +298 -0
- package/README.md +138 -30
- package/SECURITY.md +117 -10
- package/bin/args.mjs +44 -0
- package/bin/six-degrees.mjs +9 -15
- package/lib/companies.js +44 -119
- package/lib/csv.js +8 -0
- package/lib/data-export.js +170 -0
- package/lib/data-folder.js +238 -0
- package/lib/data-import.js +878 -0
- package/lib/db-client.js +48 -3
- package/lib/durable.js +73 -0
- package/lib/gate.js +90 -1
- package/lib/ingest.js +40 -0
- package/lib/legacy-offer.js +185 -0
- package/lib/legacy-scores.js +77 -0
- package/lib/linkedin-limits.js +124 -1
- package/lib/rpc.js +121 -13
- package/lib/sample-stats.js +16 -0
- package/lib/scan-progress.js +13 -0
- package/lib/scan-state.js +53 -0
- package/lib/scanner-python.js +685 -0
- package/lib/scanner-setup.js +104 -0
- package/lib/scoring.js +747 -138
- package/lib/scraper-client.js +9 -5
- package/lib/sector-directory.js +1532 -0
- package/lib/sector-focus.js +163 -0
- package/lib/sector-labels.js +81 -0
- package/lib/settings-effects.js +59 -0
- package/lib/settings.js +83 -0
- package/lib/updater-job.js +838 -0
- package/lib/updater.js +494 -0
- package/package.json +1 -2
- package/scripts/requirements.txt +106 -4
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jrmmj-._.js +0 -150
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qx548g._.js +0 -151
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1an3leo._.js +0 -150
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1m8zedk._.js +0 -155
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1zor0ys._.js +0 -3
- package/.next/standalone/.next/server/chunks/_0_rp-01._.js +0 -3
- package/.next/standalone/.next/server/chunks/_0hzdk79._.js +0 -3
- package/.next/standalone/.next/server/chunks/_0ow7u5r._.js +0 -3
- package/.next/standalone/.next/server/chunks/_0t0zc2d._.js +0 -3
- package/.next/standalone/.next/server/chunks/_0wa631d._.js +0 -3
- package/.next/standalone/.next/server/chunks/_13ccnao._.js +0 -3
- package/.next/standalone/.next/server/chunks/_13es063._.js +0 -3
- package/.next/standalone/.next/server/chunks/_142872j._.js +0 -3
- package/.next/standalone/.next/server/chunks/_18wsb_a._.js +0 -8
- package/.next/standalone/.next/server/chunks/_1e-4h5h._.js +0 -3
- package/.next/standalone/.next/server/chunks/_1gvvd7n._.js +0 -158
- package/.next/standalone/.next/server/chunks/_1moda66._.js +0 -3
- package/.next/standalone/.next/server/chunks/_1p6ghzv._.js +0 -3
- package/.next/standalone/.next/server/chunks/_1xmmi_v._.js +0 -3
- package/.next/standalone/.next/server/chunks/_1z-yrlf._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0bf3x4q._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/app_paths_page_1ol90m7.js +0 -4
- package/.next/standalone/.next/static/ZGTiDrZ5NHGETgGdlhssu/_clientMiddlewareManifest.js +0 -6
- package/.next/standalone/.next/static/chunks/0jk64vo17avsb.js +0 -1
- package/.next/standalone/.next/static/chunks/0s65dsrthylo6.js +0 -2
- package/.next/standalone/.next/static/chunks/0uyfdhi8dek85.js +0 -16
- package/.next/standalone/.next/static/chunks/220-ne82aus0c.js +0 -44
- package/.next/standalone/.next/static/chunks/229haorf0f19b.js +0 -2
- package/.next/standalone/.next/static/chunks/2g54uafnwuakc.js +0 -1
- package/.next/standalone/.next/static/chunks/2spwqs6b6dx13.js +0 -1
- package/.next/standalone/.next/static/chunks/38dlepuubiox0.js +0 -1
- package/.next/standalone/scripts/score-connections.sql +0 -80
- package/.next/standalone/scripts/score_new_connections.sql +0 -77
- package/.next/standalone/site/app.js +0 -84
- package/.next/standalone/site/index.html +0 -221
- package/.next/standalone/site/style.css +0 -155
- package/.next/standalone/site/video/install-mac-poster.jpg +0 -0
- package/.next/standalone/site/video/install-mac.mp4 +0 -0
- package/.next/standalone/site/video/linux-poster.jpg +0 -0
- package/.next/standalone/site/video/linux.mp4 +0 -0
- package/.next/standalone/site/video/scan-poster.jpg +0 -0
- package/.next/standalone/site/video/scan.mp4 +0 -0
- package/.next/static/ZGTiDrZ5NHGETgGdlhssu/_clientMiddlewareManifest.js +0 -6
- package/.next/static/chunks/0jk64vo17avsb.js +0 -1
- package/.next/static/chunks/0s65dsrthylo6.js +0 -2
- package/.next/static/chunks/0uyfdhi8dek85.js +0 -16
- package/.next/static/chunks/220-ne82aus0c.js +0 -44
- package/.next/static/chunks/229haorf0f19b.js +0 -2
- package/.next/static/chunks/2g54uafnwuakc.js +0 -1
- package/.next/static/chunks/2spwqs6b6dx13.js +0 -1
- package/.next/static/chunks/38dlepuubiox0.js +0 -1
- package/scripts/score_new_connections.sql +0 -77
- /package/.next/standalone/.next/static/{ZGTiDrZ5NHGETgGdlhssu → qqqcxvzBUizkECrT4swyK}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{ZGTiDrZ5NHGETgGdlhssu → qqqcxvzBUizkECrT4swyK}/_ssgManifest.js +0 -0
- /package/.next/static/{ZGTiDrZ5NHGETgGdlhssu → qqqcxvzBUizkECrT4swyK}/_buildManifest.js +0 -0
- /package/.next/static/{ZGTiDrZ5NHGETgGdlhssu → qqqcxvzBUizkECrT4swyK}/_ssgManifest.js +0 -0
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
//
|
|
7
7
|
// They belong to the LinkedIn account, not to a profile in the app. TRAPS §35.
|
|
8
8
|
|
|
9
|
-
import { readFileSync, writeFileSync, renameSync, unlinkSync, existsSync } from 'node:fs';
|
|
9
|
+
import { readFileSync, writeFileSync, renameSync, unlinkSync, existsSync, lstatSync } from 'node:fs';
|
|
10
10
|
import path from 'node:path';
|
|
11
|
+
import { durable } from './durable.js';
|
|
11
12
|
|
|
12
13
|
export const DEFAULT_LIMITS = { daily: 50, monthly: 250 };
|
|
13
14
|
export const DAILY_CHOICES = [25, 50, 100, 200, 500];
|
|
@@ -116,3 +117,125 @@ export function linkedinState(dir, now = Date.now()) {
|
|
|
116
117
|
cooldown: readCooldown(dir, now),
|
|
117
118
|
};
|
|
118
119
|
}
|
|
120
|
+
|
|
121
|
+
// ── another computer's budget (Settings → Your data → Import) ───────────────
|
|
122
|
+
// An import carries these three files from the other computer. They describe
|
|
123
|
+
// the same LinkedIn account, so they are merged with the ones here, never put
|
|
124
|
+
// in their place: replacing them would forget the searches made here (and lift
|
|
125
|
+
// a cooldown nobody chose to lift), and the account would be asked for more
|
|
126
|
+
// than its budget (TRAPS §35).
|
|
127
|
+
|
|
128
|
+
const ACTIVITY = 'linkedin-activity.json';
|
|
129
|
+
const COOLDOWN = 'linkedin-cooldown.json';
|
|
130
|
+
const LIMITS = 'scan-limits.json';
|
|
131
|
+
|
|
132
|
+
const isObject = (v) => Boolean(v) && typeof v === 'object' && !Array.isArray(v);
|
|
133
|
+
const isTimeList = (v) => v === undefined
|
|
134
|
+
|| (Array.isArray(v) && v.every((t) => typeof t === 'number' && Number.isFinite(t) && t >= 0));
|
|
135
|
+
const isTime = (v) => typeof v === 'number' && Number.isFinite(v) && v >= 0;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Why one of these files from another computer can't be used here, in words
|
|
139
|
+
* for the page, or null when it can. The limits follow writeLimits: only the
|
|
140
|
+
* menu's own choices. A value the app never offers is refused rather than
|
|
141
|
+
* passed to the scanner, which reads a daily limit of 0 as "no limit at all".
|
|
142
|
+
*/
|
|
143
|
+
export function budgetFileProblem(name, data) {
|
|
144
|
+
if (!isObject(data)) return 'it is not a JSON object';
|
|
145
|
+
if (name === ACTIVITY) {
|
|
146
|
+
if (!isTimeList(data.searches) || !isTimeList(data.profiles)) return 'its record of searches is not a list of times';
|
|
147
|
+
} else if (name === COOLDOWN) {
|
|
148
|
+
if (!isTime(data.until)) return 'its pause has no end time';
|
|
149
|
+
if (data.reason !== undefined && typeof data.reason !== 'string') return 'its pause has a reason that is not text';
|
|
150
|
+
if (data.set_at !== undefined && !isTime(data.set_at)) return 'its pause has a start time that is not a time';
|
|
151
|
+
} else if (name === LIMITS) {
|
|
152
|
+
if (data.daily !== undefined && !DAILY_CHOICES.includes(data.daily)) {
|
|
153
|
+
return `its daily limit (${String(data.daily).slice(0, 20)}) is not one Six Degrees offers`;
|
|
154
|
+
}
|
|
155
|
+
if (data.monthly !== undefined && !MONTHLY_CHOICES.includes(data.monthly)) {
|
|
156
|
+
return `its monthly limit (${String(data.monthly).slice(0, 20)}) is not one Six Degrees offers`;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Both lists of times, each time kept as many times as the list that has it
|
|
164
|
+
* most often. Not a plain union, and not a de-duplication: the scanner writes
|
|
165
|
+
* one time n times when a single click cost n searches (charge_linkedin), and
|
|
166
|
+
* those are n searches; and a history both computers already share (one was
|
|
167
|
+
* imported from the other before) must still count once, not twice.
|
|
168
|
+
*/
|
|
169
|
+
export function mergeTimes(mine = [], theirs = []) {
|
|
170
|
+
const counts = (list) => list.reduce((m, t) => m.set(t, (m.get(t) || 0) + 1), new Map());
|
|
171
|
+
const merged = counts(mine);
|
|
172
|
+
for (const [t, n] of counts(theirs)) if (n > (merged.get(t) || 0)) merged.set(t, n);
|
|
173
|
+
return [...merged].sort((a, b) => a[0] - b[0]).flatMap(([t, n]) => Array(n).fill(t));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** The scanner's own reading of a record: every entry a number (float() in scrape.py). */
|
|
177
|
+
function readableTimes(v) {
|
|
178
|
+
if (v === undefined) return [];
|
|
179
|
+
if (!Array.isArray(v)) return null;
|
|
180
|
+
const out = v.map(Number);
|
|
181
|
+
return out.every(Number.isFinite) ? out : null;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const hasFile = (p) => {
|
|
185
|
+
try { lstatSync(p); return true; } catch { return false; }
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Merge the budget files in `from` (an import's, already checked with
|
|
190
|
+
* budgetFileProblem) into the data folder `dir`:
|
|
191
|
+
* linkedin-activity.json both computers' searches and profile views (mergeTimes)
|
|
192
|
+
* linkedin-cooldown.json whichever pause ends later
|
|
193
|
+
* scan-limits.json this computer's, if it has one; the copy's otherwise.
|
|
194
|
+
* The limits are a choice someone made here, and an
|
|
195
|
+
* import never quietly changes it.
|
|
196
|
+
* A record here that can't be read is left as it is: the scanner reads it as
|
|
197
|
+
* "today's searches are used up" (scrape.py _read_activity), which is the safe
|
|
198
|
+
* way round. Running it twice gives the same files as running it once, so a
|
|
199
|
+
* start that stops part-way can simply do it again.
|
|
200
|
+
*/
|
|
201
|
+
export function mergeBudgetFiles({ dir, from }) {
|
|
202
|
+
const here = (name) => path.join(dir, name);
|
|
203
|
+
const theirs = (name) => {
|
|
204
|
+
const data = readJson(path.join(from, name));
|
|
205
|
+
return isObject(data) && !budgetFileProblem(name, data) ? data : null;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const activity = theirs(ACTIVITY);
|
|
209
|
+
if (activity) {
|
|
210
|
+
const mine = hasFile(here(ACTIVITY)) ? readJson(here(ACTIVITY)) : {};
|
|
211
|
+
const searches = isObject(mine) ? readableTimes(mine.searches) : null;
|
|
212
|
+
const profiles = isObject(mine) ? readableTimes(mine.profiles) : null;
|
|
213
|
+
if (searches && profiles) {
|
|
214
|
+
durable.writeJsonDurably(here(ACTIVITY), {
|
|
215
|
+
searches: mergeTimes(searches, activity.searches),
|
|
216
|
+
profiles: mergeTimes(profiles, activity.profiles),
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const cooldown = theirs(COOLDOWN);
|
|
222
|
+
if (cooldown) {
|
|
223
|
+
const mine = readJson(here(COOLDOWN));
|
|
224
|
+
const mineEnds = Number.isFinite(Number(mine?.until)) ? Number(mine.until) : -Infinity;
|
|
225
|
+
if (cooldown.until > mineEnds) {
|
|
226
|
+
durable.writeJsonDurably(here(COOLDOWN), {
|
|
227
|
+
until: cooldown.until,
|
|
228
|
+
reason: cooldown.reason ?? 'LinkedIn pushed back',
|
|
229
|
+
set_at: cooldown.set_at ?? null,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const limits = theirs(LIMITS);
|
|
235
|
+
if (limits && !hasFile(here(LIMITS))) {
|
|
236
|
+
durable.writeJsonDurably(here(LIMITS), {
|
|
237
|
+
daily: limits.daily ?? DEFAULT_LIMITS.daily,
|
|
238
|
+
monthly: limits.monthly ?? DEFAULT_LIMITS.monthly,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
@@ -1,52 +1,160 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { getDb, newId, nowIso } from './db-client.js';
|
|
2
3
|
|
|
3
4
|
// Replacements for the stored procedures the hosted database used to provide.
|
|
4
5
|
// Scoring lives in lib/scoring.js; this file only reads rows and writes the
|
|
5
|
-
// results back. (
|
|
6
|
+
// results back. rpc('score_new_connections') is that procedure's name, kept
|
|
7
|
+
// for the routes that call it; it rescores with lib/scoring.js like the rest.
|
|
6
8
|
|
|
7
|
-
import { scoreNetwork, explainScore, SCORING_VERSION } from './scoring.js';
|
|
8
|
-
import {
|
|
9
|
+
import { readNetwork, scoreNetwork, explainScore, SCORING_VERSION, KNOWN_COMPANIES, RULE_TABLES } from './scoring.js';
|
|
10
|
+
import { industryKeyOf, INDUSTRIES } from './companies.js';
|
|
11
|
+
import { readSettings } from './settings.js';
|
|
12
|
+
import { SECTOR_FOCUS_SETTING, focusFingerprint, previewSectorFocus } from './sector-focus.js';
|
|
13
|
+
import { LEGACY_OFFER_KEY } from './legacy-scores.js';
|
|
14
|
+
import { sectorMatcher, sectorGroup, sectorLabel } from './sector-directory.js';
|
|
15
|
+
|
|
16
|
+
// The word lists and rules the stored scores were computed with: a fingerprint
|
|
17
|
+
// of every entry on the curated company list (name, score, alias, industry),
|
|
18
|
+
// of the broad industries' words and labels (lib/companies.js INDUSTRIES), and
|
|
19
|
+
// of every rule table scoring reads headlines and names with (lib/scoring.js
|
|
20
|
+
// RULE_TABLES: titles, students and clubs, what isn't a company, the reach
|
|
21
|
+
// bonuses), stamped beside them in app_meta 'scoring_list'. The industries'
|
|
22
|
+
// words decide a company's one industry, which decides whether it is a school
|
|
23
|
+
// (no estimate) and whether a broad pick in Settings leans it; their labels
|
|
24
|
+
// are in the stored working ("4 + 1 your sector: Healthcare & Biotech").
|
|
25
|
+
// Editing any of them makes stored scores stale, as a new SCORING_VERSION
|
|
26
|
+
// does, with no number to remember to bump. Copies from before the list was
|
|
27
|
+
// made neutral stamped none, which is also how rescoreAll() knows to offer
|
|
28
|
+
// keeping their old scores (lib/legacy-offer.js).
|
|
29
|
+
export function scoringStamp({ known = KNOWN_COMPANIES, industries = INDUSTRIES, rules = RULE_TABLES } = {}) {
|
|
30
|
+
// JSON has no patterns or sets: a pattern counts by its source and flags, a set by its members.
|
|
31
|
+
const plain = (key, value) => (value instanceof RegExp ? String(value) : value instanceof Set ? [...value] : value);
|
|
32
|
+
return createHash('sha256')
|
|
33
|
+
.update(JSON.stringify([
|
|
34
|
+
known.map(([name, score, alias, industry]) => [name, score, String(alias), industry]),
|
|
35
|
+
industries.map(({ key, label, words }) => [key, label, String(words)]),
|
|
36
|
+
rules,
|
|
37
|
+
], plain))
|
|
38
|
+
.digest('hex').slice(0, 16);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const KNOWN_LIST_STAMP = scoringStamp();
|
|
9
42
|
|
|
10
43
|
export function companyOverrides(db = getDb()) {
|
|
11
44
|
return new Map(db.prepare('SELECT name, score FROM company_scores').all().map((r) => [r.name, r.score]));
|
|
12
45
|
}
|
|
13
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Set company scores as your own ([[name, score], …]), the way Paths → Scores
|
|
49
|
+
* does: one row per name, replacing any you had. Rescoring is the caller's
|
|
50
|
+
* job, so a batch rescores once.
|
|
51
|
+
*/
|
|
52
|
+
export function setCompanyScores(db, entries) {
|
|
53
|
+
const upsert = db.prepare(`INSERT INTO company_scores (id, name, score, updated_at) VALUES (?, ?, ?, ?)
|
|
54
|
+
ON CONFLICT(name) DO UPDATE SET score = excluded.score, updated_at = excluded.updated_at`);
|
|
55
|
+
const now = nowIso();
|
|
56
|
+
for (const [name, score] of entries) upsert.run(newId(), name, score, now);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** The sector focus saved in Settings (lib/sector-focus.js), or none. */
|
|
60
|
+
export function sectorFocusOf(db = getDb()) {
|
|
61
|
+
return readSettings(db, { sectorFocus: SECTOR_FOCUS_SETTING }).sectorFocus;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* What rescoring reads: every row, as scoring needs it. `withPeople` adds each
|
|
66
|
+
* row's name, for naming who a change would move.
|
|
67
|
+
*/
|
|
68
|
+
export function scoringRows(db = getDb(), { withPeople = false } = {}) {
|
|
69
|
+
return db.prepare(`SELECT id, degree, headline, role, company, scanned_company, profile_url, source_connection_id${withPeople ? ', name' : ''}
|
|
70
|
+
FROM linkedin_connections`).all();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Every headline read once, the way scoring reads it: each company's
|
|
75
|
+
* headcount, its one industry, the sector directory's sectors it matches and
|
|
76
|
+
* the industries those sit under. Rescoring, Settings' preview and
|
|
77
|
+
* suggestions, and Paths → Scores all read the rows through this, so they
|
|
78
|
+
* agree on which company is in which sector.
|
|
79
|
+
*/
|
|
80
|
+
export function readForScoring(rows) {
|
|
81
|
+
return readNetwork(rows, { industryOf: industryKeyOf, sectorsOf: sectorMatcher(), groupOf: sectorGroup });
|
|
82
|
+
}
|
|
83
|
+
|
|
14
84
|
/**
|
|
15
85
|
* Rescore everyone. The score depends on the whole network (how many of your
|
|
16
86
|
* people work at a company, how strong a bridge's circle is), so after any
|
|
17
87
|
* ingest or company-score change every row is recomputed — ~0.1s for 4,000.
|
|
88
|
+
* Your company scores and your sector focus are read here, not passed in, so
|
|
89
|
+
* every path that rescores (an import, a company score, Settings, a stale
|
|
90
|
+
* model) applies both.
|
|
91
|
+
*
|
|
92
|
+
* `compareWith` is another sector focus: Settings' save passes the one it
|
|
93
|
+
* replaced. The same rows are then also scored with it, in memory, and the
|
|
94
|
+
* answer says who changed tier between the two, counted by the preview's own
|
|
95
|
+
* function (lib/sector-focus.js), so a save reports what its preview said.
|
|
96
|
+
* That compares two fresh scorings rather than the stored tiers, which can be
|
|
97
|
+
* stale (a save whose rescore failed, a database from another computer).
|
|
98
|
+
* @returns { scored } rows written, plus { people, up, down } when comparing.
|
|
18
99
|
*/
|
|
19
|
-
export function rescoreAll() {
|
|
100
|
+
export function rescoreAll({ compareWith } = {}) {
|
|
20
101
|
const db = getDb();
|
|
21
|
-
const rows = db
|
|
22
|
-
const
|
|
102
|
+
const rows = scoringRows(db);
|
|
103
|
+
const overrides = companyOverrides(db);
|
|
104
|
+
const focus = sectorFocusOf(db);
|
|
105
|
+
// Every headline is read once, however many ways the rows are then scored.
|
|
106
|
+
const read = readForScoring(rows);
|
|
107
|
+
const { scores } = scoreNetwork(rows, { overrides, focus, read });
|
|
108
|
+
// Worked out before anything is written, so a failure leaves nothing half done.
|
|
109
|
+
const change = compareWith === undefined ? null
|
|
110
|
+
: previewSectorFocus(rows, { overrides, read, from: compareWith, to: focus, examples: 0 });
|
|
23
111
|
const update = db.prepare(`UPDATE linkedin_connections SET seniority_score = ?, company_prestige_score = ?, power_score = ?, tier = ?,
|
|
24
112
|
score_why = ?, circle_power = ?, circle_s_count = ?, circle_a_count = ?, circle_elite_pct = ?, is_catalyst = ?, catalyst_score = ?, updated_at = ?
|
|
25
113
|
WHERE id = ?`);
|
|
26
114
|
const now = nowIso();
|
|
27
115
|
db.exec('BEGIN');
|
|
28
116
|
try {
|
|
117
|
+
// Stored scores with no list stamp came from a copy whose curated list
|
|
118
|
+
// held one person's picks. The first time they are replaced, Paths →
|
|
119
|
+
// Scores offers once to keep the old ones as your own (lib/legacy-offer.js).
|
|
120
|
+
// A database nothing has scored yet never had them, so it is never offered.
|
|
121
|
+
const listed = db.prepare("SELECT 1 FROM app_meta WHERE key = 'scoring_list'").get();
|
|
122
|
+
if (!listed && db.prepare('SELECT 1 FROM linkedin_connections WHERE tier IS NOT NULL LIMIT 1').get()) {
|
|
123
|
+
db.prepare("INSERT OR IGNORE INTO app_meta (key, value) VALUES (?, 'open')").run(LEGACY_OFFER_KEY);
|
|
124
|
+
}
|
|
29
125
|
for (const r of rows) {
|
|
30
126
|
const s = scores.get(r.id);
|
|
31
127
|
const c = s.circle;
|
|
32
|
-
update.run(s.title.points, s.companyScore, s.power, s.tier, explainScore(s, s.boost),
|
|
128
|
+
update.run(s.title.points, s.companyScore, s.power, s.tier, explainScore(s, s.boost, { sectorLabel }),
|
|
33
129
|
c ? Math.round(c.circlePower * 100) / 100 : 0, c?.sCount || 0, c?.aCount || 0, c ? Math.round(c.elitePct * 100) / 100 : 0,
|
|
34
130
|
c?.isCatalyst ? 1 : 0, c?.isCatalyst ? c.sCount + c.aCount : 0, now, r.id);
|
|
35
131
|
}
|
|
36
|
-
db.prepare('INSERT INTO app_meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value')
|
|
132
|
+
const meta = db.prepare('INSERT INTO app_meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value');
|
|
133
|
+
meta.run('scoring_version', String(SCORING_VERSION));
|
|
134
|
+
// Which curated list and sector focus these scores were computed with (see rescoreIfStale).
|
|
135
|
+
meta.run('scoring_list', KNOWN_LIST_STAMP);
|
|
136
|
+
meta.run('scoring_focus', focusFingerprint(focus));
|
|
37
137
|
db.exec('COMMIT');
|
|
38
138
|
} catch (err) {
|
|
39
139
|
db.exec('ROLLBACK');
|
|
40
140
|
throw err;
|
|
41
141
|
}
|
|
42
|
-
return { scored: rows.length };
|
|
142
|
+
return change ? { scored: rows.length, people: change.people, up: change.up, down: change.down } : { scored: rows.length };
|
|
43
143
|
}
|
|
44
144
|
|
|
45
|
-
/**
|
|
145
|
+
/**
|
|
146
|
+
* Rescore once if the stored scores came from an older scoring model or
|
|
147
|
+
* curated list, or from a sector focus other than the one saved now: an
|
|
148
|
+
* update, a database restored or brought from another computer, or a Settings
|
|
149
|
+
* save whose rescore never finished.
|
|
150
|
+
*/
|
|
46
151
|
export function rescoreIfStale() {
|
|
47
152
|
const db = getDb();
|
|
48
|
-
const
|
|
49
|
-
|
|
153
|
+
const meta = (key) => db.prepare('SELECT value FROM app_meta WHERE key = ?').get(key)?.value;
|
|
154
|
+
const fresh = meta('scoring_version') === String(SCORING_VERSION)
|
|
155
|
+
&& meta('scoring_list') === KNOWN_LIST_STAMP
|
|
156
|
+
&& meta('scoring_focus') === focusFingerprint(sectorFocusOf(db));
|
|
157
|
+
return fresh ? { scored: 0 } : rescoreAll();
|
|
50
158
|
}
|
|
51
159
|
|
|
52
160
|
function incrementXp({ amount = 0 } = {}) {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// The sample network's own numbers, for the launch page (app/launch/page.js),
|
|
2
|
+
// which shows them rather than anyone's real network. Counted from
|
|
3
|
+
// public/demo-data.json, where every person is invented
|
|
4
|
+
// (scripts/gen-synthetic.mjs); tests/sample-stats.test.mjs counts them again,
|
|
5
|
+
// so regenerating the sample can't leave them stale. They're written here
|
|
6
|
+
// rather than read from the file so the page doesn't download the whole sample
|
|
7
|
+
// to show a few numbers.
|
|
8
|
+
export const SAMPLE_STATS = {
|
|
9
|
+
connections: 873, // rows: the 1st degree and the circles of the bridges
|
|
10
|
+
degree1: 150,
|
|
11
|
+
degree2: 723,
|
|
12
|
+
people: 748, // each person once, however many circles they're in
|
|
13
|
+
bridges: 14, // 1st-degree people whose circle is mapped
|
|
14
|
+
companies: 19, // where people work now, as Paths groups them
|
|
15
|
+
recommendations: 474, // the Queue's list: 2nd-degree S, A and B you aren't connected to
|
|
16
|
+
};
|
|
@@ -9,8 +9,13 @@
|
|
|
9
9
|
// " 350 / 817 collected" (every fifty people)
|
|
10
10
|
// " Collected all 817 connections." (the end)
|
|
11
11
|
// 2nd degree: "[3/10] Some Name (A-tier, score 6.2)" (as each person starts)
|
|
12
|
+
//
|
|
13
|
+
// And one from the app itself (app/api/scraper/route.js setupPlan), while
|
|
14
|
+
// "Set up the scanner" downloads its Python:
|
|
15
|
+
// "Downloading Python 3.12.14: 12.0 of 24.0 MB"
|
|
12
16
|
|
|
13
17
|
const REPORTED = /LinkedIn reports (\d+) connections/;
|
|
18
|
+
const DOWNLOADING = /^Downloading Python [\d.]+: ([\d.]+) of ([\d.]+) MB$/;
|
|
14
19
|
const COLLECTED = /(\d+)\s*\/\s*(\d+)\s+collected/;
|
|
15
20
|
const COLLECTED_ALL = /Collected all (\d+) connections/;
|
|
16
21
|
const BRIDGE_STEP = /\[(\d+)\/(\d+)\]/;
|
|
@@ -26,6 +31,14 @@ const SAVING = /^(Collected \d+ connections|Pushing \d+ connections|\s*Sent \d+
|
|
|
26
31
|
export function scanProgress(log, action) {
|
|
27
32
|
if (!Array.isArray(log) || log.length === 0) return null;
|
|
28
33
|
|
|
34
|
+
// Only while the download is the step under way: once the log has moved on
|
|
35
|
+
// (unpacking, installing), a bar left at 100% would look stuck.
|
|
36
|
+
if (action === 'setup') {
|
|
37
|
+
const m = String(log[log.length - 1]).match(DOWNLOADING);
|
|
38
|
+
if (!m || !Number(m[2])) return null;
|
|
39
|
+
return { done: Math.min(Number(m[1]), Number(m[2])), total: Number(m[2]), kind: 'download' };
|
|
40
|
+
}
|
|
41
|
+
|
|
29
42
|
if (action === 'full' || action === 'refresh') {
|
|
30
43
|
for (let i = log.length - 1; i >= 0; i--) {
|
|
31
44
|
const line = String(log[i]);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Whether the scanner is running, for routes other than the one that runs it.
|
|
2
|
+
//
|
|
3
|
+
// app/api/scraper/route.js owns the job and its state. It registers that state
|
|
4
|
+
// here, on globalThis, so a route that must not act mid-scan (an import that
|
|
5
|
+
// replaces the database, a restart) can ask without an HTTP call to its own
|
|
6
|
+
// server, and gets the same answer however the bundler splits route modules.
|
|
7
|
+
//
|
|
8
|
+
// The scanner's route runs more than scans: Install, Set up the scanner and
|
|
9
|
+
// the LinkedIn sign-in window take the same slot. A refusal says which one is
|
|
10
|
+
// running (runningNow): "A scan is running" while Install ran sent people
|
|
11
|
+
// looking for a scan that wasn't there.
|
|
12
|
+
|
|
13
|
+
const KEY = Symbol.for('six-degrees.scan-state');
|
|
14
|
+
|
|
15
|
+
/** The scanner's state object: the one already registered in this server, or `initial`. */
|
|
16
|
+
export function registerScanState(initial) {
|
|
17
|
+
if (!globalThis[KEY]) globalThis[KEY] = initial;
|
|
18
|
+
return globalThis[KEY];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** What the scanner's route is running: its action ('full', 'install', 'setup', 'login', …), or null. */
|
|
22
|
+
export function scannerJob() {
|
|
23
|
+
const state = globalThis[KEY];
|
|
24
|
+
if (state?.running !== true) return null;
|
|
25
|
+
return typeof state.action === 'string' && state.action ? state.action : 'scan';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Is a scan, or the scanner's setup, running in this server? */
|
|
29
|
+
export function scanIsRunning() {
|
|
30
|
+
return scannerJob() !== null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* What is running, in words that start a refusal: "A scan is running", "The
|
|
35
|
+
* scanner is being set up", … `job` is scannerJob()'s answer; `true` (a caller
|
|
36
|
+
* that only knows something runs) reads as a scan.
|
|
37
|
+
*/
|
|
38
|
+
export function runningNow(job) {
|
|
39
|
+
switch (job) {
|
|
40
|
+
case 'install': return 'The scanner\'s packages are being installed';
|
|
41
|
+
case 'setup': return 'The scanner is being set up';
|
|
42
|
+
case 'login': return 'The LinkedIn sign-in window is open';
|
|
43
|
+
default: return 'A scan is running';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* A refusal while the scanner's route runs something: "<what runs>. <then>",
|
|
49
|
+
* or null when nothing runs.
|
|
50
|
+
*/
|
|
51
|
+
export function busyRefusal(then, job = scannerJob()) {
|
|
52
|
+
return job ? `${runningNow(job)}. ${then}` : null;
|
|
53
|
+
}
|