six-degrees 0.2.0 → 0.3.0-beta.1

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.
Files changed (478) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +10 -0
  3. package/.next/standalone/.next/build-manifest.json +3 -3
  4. package/.next/standalone/.next/prerender-manifest.json +39 -11
  5. package/.next/standalone/.next/required-server-files.json +4 -1
  6. package/.next/standalone/.next/routes-manifest.json +60 -0
  7. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  17. package/.next/standalone/.next/server/app/_not-found.rsc +11 -11
  18. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +11 -11
  19. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +9 -9
  20. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  21. package/.next/standalone/.next/server/app/api/admin-delete/route.js +3 -2
  22. package/.next/standalone/.next/server/app/api/admin-delete/route.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/api/admin-update/route.js +3 -2
  24. package/.next/standalone/.next/server/app/api/admin-update/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/bridges/route.js +3 -2
  26. package/.next/standalone/.next/server/app/api/bridges/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/bulk-import/route.js +3 -2
  28. package/.next/standalone/.next/server/app/api/bulk-import/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/company-scores/legacy/route/app-paths-manifest.json +3 -0
  30. package/.next/standalone/.next/server/app/api/company-scores/legacy/route/build-manifest.json +12 -0
  31. package/.next/standalone/.next/server/app/api/company-scores/legacy/route/server-reference-manifest.json +4 -0
  32. package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js +9 -0
  33. package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.map +5 -0
  34. package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.nft.json +1 -0
  35. package/.next/standalone/.next/server/app/api/company-scores/legacy/route_client-reference-manifest.js +3 -0
  36. package/.next/standalone/.next/server/app/api/company-scores/route.js +3 -2
  37. package/.next/standalone/.next/server/app/api/company-scores/route.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/api/connections/route.js +3 -2
  39. package/.next/standalone/.next/server/app/api/connections/route.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/api/data/export/route/app-paths-manifest.json +3 -0
  41. package/.next/standalone/.next/server/app/api/data/export/route/build-manifest.json +12 -0
  42. package/.next/standalone/.next/server/app/api/data/export/route/server-reference-manifest.json +4 -0
  43. package/.next/standalone/.next/server/app/api/data/export/route.js +7 -0
  44. package/.next/standalone/.next/server/app/api/data/export/route.js.map +5 -0
  45. package/.next/standalone/.next/server/app/api/data/export/route.js.nft.json +1 -0
  46. package/.next/standalone/.next/server/app/api/data/export/route_client-reference-manifest.js +3 -0
  47. package/.next/standalone/.next/server/app/api/data/import/route/app-paths-manifest.json +3 -0
  48. package/.next/standalone/.next/server/app/api/data/import/route/build-manifest.json +12 -0
  49. package/.next/standalone/.next/server/app/api/data/import/route/server-reference-manifest.json +4 -0
  50. package/.next/standalone/.next/server/app/api/data/import/route.js +8 -0
  51. package/.next/standalone/.next/server/app/api/data/import/route.js.map +5 -0
  52. package/.next/standalone/.next/server/app/api/data/import/route.js.nft.json +1 -0
  53. package/.next/standalone/.next/server/app/api/data/import/route_client-reference-manifest.js +3 -0
  54. package/.next/standalone/.next/server/app/api/data/restart/route/app-paths-manifest.json +3 -0
  55. package/.next/standalone/.next/server/app/api/data/restart/route/build-manifest.json +12 -0
  56. package/.next/standalone/.next/server/app/api/data/restart/route/server-reference-manifest.json +4 -0
  57. package/.next/standalone/.next/server/app/api/data/restart/route.js +8 -0
  58. package/.next/standalone/.next/server/app/api/data/restart/route.js.map +5 -0
  59. package/.next/standalone/.next/server/app/api/data/restart/route.js.nft.json +1 -0
  60. package/.next/standalone/.next/server/app/api/data/restart/route_client-reference-manifest.js +3 -0
  61. package/.next/standalone/.next/server/app/api/data/reveal/route/app-paths-manifest.json +3 -0
  62. package/.next/standalone/.next/server/app/api/data/reveal/route/build-manifest.json +12 -0
  63. package/.next/standalone/.next/server/app/api/data/reveal/route/server-reference-manifest.json +4 -0
  64. package/.next/standalone/.next/server/app/api/data/reveal/route.js +7 -0
  65. package/.next/standalone/.next/server/app/api/data/reveal/route.js.map +5 -0
  66. package/.next/standalone/.next/server/app/api/data/reveal/route.js.nft.json +1 -0
  67. package/.next/standalone/.next/server/app/api/data/reveal/route_client-reference-manifest.js +3 -0
  68. package/.next/standalone/.next/server/app/api/data/route/app-paths-manifest.json +3 -0
  69. package/.next/standalone/.next/server/app/api/data/route/build-manifest.json +12 -0
  70. package/.next/standalone/.next/server/app/api/data/route/server-reference-manifest.json +4 -0
  71. package/.next/standalone/.next/server/app/api/data/route.js +7 -0
  72. package/.next/standalone/.next/server/app/api/data/route.js.map +5 -0
  73. package/.next/standalone/.next/server/app/api/data/route.js.nft.json +1 -0
  74. package/.next/standalone/.next/server/app/api/data/route_client-reference-manifest.js +3 -0
  75. package/.next/standalone/.next/server/app/api/delete-cluster/route.js +3 -2
  76. package/.next/standalone/.next/server/app/api/delete-cluster/route.js.nft.json +1 -1
  77. package/.next/standalone/.next/server/app/api/ingest/route.js +2 -2
  78. package/.next/standalone/.next/server/app/api/ingest/route.js.nft.json +1 -1
  79. package/.next/standalone/.next/server/app/api/network/route.js +3 -2
  80. package/.next/standalone/.next/server/app/api/network/route.js.nft.json +1 -1
  81. package/.next/standalone/.next/server/app/api/notifications/route.js +3 -2
  82. package/.next/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  83. package/.next/standalone/.next/server/app/api/outreach/route.js +3 -2
  84. package/.next/standalone/.next/server/app/api/outreach/route.js.nft.json +1 -1
  85. package/.next/standalone/.next/server/app/api/queue/route.js +3 -2
  86. package/.next/standalone/.next/server/app/api/queue/route.js.nft.json +1 -1
  87. package/.next/standalone/.next/server/app/api/scraper/route.js +3 -2
  88. package/.next/standalone/.next/server/app/api/scraper/route.js.nft.json +1 -1
  89. package/.next/standalone/.next/server/app/api/settings/route/app-paths-manifest.json +3 -0
  90. package/.next/standalone/.next/server/app/api/settings/route/build-manifest.json +12 -0
  91. package/.next/standalone/.next/server/app/api/settings/route/server-reference-manifest.json +4 -0
  92. package/.next/standalone/.next/server/app/api/settings/route.js +9 -0
  93. package/.next/standalone/.next/server/app/api/settings/route.js.map +5 -0
  94. package/.next/standalone/.next/server/app/api/settings/route.js.nft.json +1 -0
  95. package/.next/standalone/.next/server/app/api/settings/route_client-reference-manifest.js +3 -0
  96. package/.next/standalone/.next/server/app/api/settings/sector-preview/route/app-paths-manifest.json +3 -0
  97. package/.next/standalone/.next/server/app/api/settings/sector-preview/route/build-manifest.json +12 -0
  98. package/.next/standalone/.next/server/app/api/settings/sector-preview/route/server-reference-manifest.json +4 -0
  99. package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js +8 -0
  100. package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.map +5 -0
  101. package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.nft.json +1 -0
  102. package/.next/standalone/.next/server/app/api/settings/sector-preview/route_client-reference-manifest.js +3 -0
  103. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route/app-paths-manifest.json +3 -0
  104. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route/build-manifest.json +12 -0
  105. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route/server-reference-manifest.json +4 -0
  106. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js +8 -0
  107. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.map +5 -0
  108. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.nft.json +1 -0
  109. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route_client-reference-manifest.js +3 -0
  110. package/.next/standalone/.next/server/app/api/setup-profile/route.js +3 -2
  111. package/.next/standalone/.next/server/app/api/setup-profile/route.js.nft.json +1 -1
  112. package/.next/standalone/.next/server/app/api/unlock/route.js +3 -2
  113. package/.next/standalone/.next/server/app/api/unlock/route.js.nft.json +1 -1
  114. package/.next/standalone/.next/server/app/api/update/route.js +1 -1
  115. package/.next/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  116. package/.next/standalone/.next/server/app/api/update-images/route.js +3 -2
  117. package/.next/standalone/.next/server/app/api/update-images/route.js.nft.json +1 -1
  118. package/.next/standalone/.next/server/app/api/users/route.js +3 -2
  119. package/.next/standalone/.next/server/app/api/users/route.js.nft.json +1 -1
  120. package/.next/standalone/.next/server/app/avatars/[file]/route.js +2 -1
  121. package/.next/standalone/.next/server/app/avatars/[file]/route.js.nft.json +1 -1
  122. package/.next/standalone/.next/server/app/favicon.ico/route.js +2 -1
  123. package/.next/standalone/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  124. package/.next/standalone/.next/server/app/import/page.js.nft.json +1 -1
  125. package/.next/standalone/.next/server/app/import/page_client-reference-manifest.js +1 -1
  126. package/.next/standalone/.next/server/app/import.html +1 -1
  127. package/.next/standalone/.next/server/app/import.rsc +13 -13
  128. package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +13 -13
  129. package/.next/standalone/.next/server/app/import.segments/_tree.segment.rsc +1 -1
  130. package/.next/standalone/.next/server/app/import.segments/import/__PAGE__.segment.rsc +11 -11
  131. package/.next/standalone/.next/server/app/index.html +1 -1
  132. package/.next/standalone/.next/server/app/index.rsc +13 -13
  133. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +11 -11
  134. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +13 -13
  135. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  136. package/.next/standalone/.next/server/app/launch/page.js.nft.json +1 -1
  137. package/.next/standalone/.next/server/app/launch/page_client-reference-manifest.js +1 -1
  138. package/.next/standalone/.next/server/app/launch.html +2 -2
  139. package/.next/standalone/.next/server/app/launch.rsc +13 -13
  140. package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +13 -13
  141. package/.next/standalone/.next/server/app/launch.segments/_tree.segment.rsc +1 -1
  142. package/.next/standalone/.next/server/app/launch.segments/launch/__PAGE__.segment.rsc +11 -11
  143. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  144. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  145. package/.next/standalone/.next/server/app/paths/page.js.nft.json +1 -1
  146. package/.next/standalone/.next/server/app/paths/page_client-reference-manifest.js +1 -1
  147. package/.next/standalone/.next/server/app/paths.html +1 -1
  148. package/.next/standalone/.next/server/app/paths.rsc +13 -13
  149. package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +13 -13
  150. package/.next/standalone/.next/server/app/paths.segments/_tree.segment.rsc +1 -1
  151. package/.next/standalone/.next/server/app/paths.segments/paths/__PAGE__.segment.rsc +11 -11
  152. package/.next/standalone/.next/server/app/profile/page.js.nft.json +1 -1
  153. package/.next/standalone/.next/server/app/profile/page_client-reference-manifest.js +1 -1
  154. package/.next/standalone/.next/server/app/profile.html +1 -1
  155. package/.next/standalone/.next/server/app/profile.rsc +13 -13
  156. package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +13 -13
  157. package/.next/standalone/.next/server/app/profile.segments/_tree.segment.rsc +1 -1
  158. package/.next/standalone/.next/server/app/profile.segments/profile/__PAGE__.segment.rsc +11 -11
  159. package/.next/standalone/.next/server/app/queue/page.js.nft.json +1 -1
  160. package/.next/standalone/.next/server/app/queue/page_client-reference-manifest.js +1 -1
  161. package/.next/standalone/.next/server/app/queue.html +1 -1
  162. package/.next/standalone/.next/server/app/queue.rsc +13 -13
  163. package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +13 -13
  164. package/.next/standalone/.next/server/app/queue.segments/_tree.segment.rsc +1 -1
  165. package/.next/standalone/.next/server/app/queue.segments/queue/__PAGE__.segment.rsc +11 -11
  166. package/.next/standalone/.next/server/app/settings/page/app-paths-manifest.json +3 -0
  167. package/.next/standalone/.next/server/app/settings/page/build-manifest.json +20 -0
  168. package/.next/standalone/.next/server/app/settings/page/next-font-manifest.json +11 -0
  169. package/.next/standalone/.next/server/app/settings/page/react-loadable-manifest.json +1 -0
  170. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -0
  171. package/.next/standalone/.next/server/app/settings/page.js +13 -0
  172. package/.next/standalone/.next/server/app/settings/page.js.map +5 -0
  173. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -0
  174. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +3 -0
  175. package/.next/standalone/.next/server/app/settings.html +1 -0
  176. package/.next/standalone/.next/server/app/settings.meta +26 -0
  177. package/.next/standalone/.next/server/app/settings.rsc +24 -0
  178. package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +24 -0
  179. package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +4 -0
  180. package/.next/standalone/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +28 -0
  181. package/.next/standalone/.next/server/app/setup/page.js.nft.json +1 -1
  182. package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  183. package/.next/standalone/.next/server/app/setup.html +1 -1
  184. package/.next/standalone/.next/server/app/setup.rsc +13 -13
  185. package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +13 -13
  186. package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +1 -1
  187. package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +11 -11
  188. package/.next/standalone/.next/server/app-paths-manifest.json +10 -0
  189. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-rnla2._.js +3 -0
  190. package/.next/standalone/.next/server/chunks/[root-of-the-server]__00la_y0._.js +3 -0
  191. package/.next/standalone/.next/server/chunks/[root-of-the-server]__07t47cm._.js +3 -0
  192. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cj5jqc._.js +3 -0
  193. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e0fei3._.js +3 -0
  194. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0i5hdu4._.js +3 -0
  195. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ljcioj._.js +3 -0
  196. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ljnyho._.js +3 -0
  197. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o5-tcg._.js +3 -0
  198. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qrnous._.js +3 -0
  199. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t3v1a1._.js +3 -0
  200. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0uag-k5._.js +8 -0
  201. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0um1uey._.js +3 -0
  202. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wmexuc._.js +3 -0
  203. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0xu34sz._.js +3 -0
  204. package/.next/standalone/.next/server/chunks/[root-of-the-server]__133knx1._.js +3 -0
  205. package/.next/standalone/.next/server/chunks/[root-of-the-server]__14ou7j5._.js +3 -0
  206. package/.next/standalone/.next/server/chunks/[root-of-the-server]__15-17hl._.js +3 -0
  207. package/.next/standalone/.next/server/chunks/[root-of-the-server]__16iu0hv._.js +3 -0
  208. package/.next/standalone/.next/server/chunks/[root-of-the-server]__19b7mig._.js +3 -0
  209. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1bbcwub._.js +8 -0
  210. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1eris29._.js +3 -0
  211. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1gjo_cq._.js +3 -0
  212. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1kbl21f._.js +3 -0
  213. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qcm08_._.js +3 -0
  214. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rphsdk._.js +3 -0
  215. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1t3rugi._.js +3 -0
  216. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1w25q0m._.js +3 -0
  217. package/.next/standalone/.next/server/chunks/_072jl0y._.js +3 -0
  218. package/.next/standalone/.next/server/chunks/_0lw8_i0._.js +3 -0
  219. package/.next/standalone/.next/server/chunks/_1_fynia._.js +21 -3
  220. package/.next/standalone/.next/server/chunks/_1fn30_l._.js +3 -0
  221. package/.next/standalone/.next/server/chunks/_1itd1o_._.js +2 -1
  222. package/.next/standalone/.next/server/chunks/_1iwkh8t._.js +1 -1
  223. package/.next/standalone/.next/server/chunks/_1mxn_lb._.js +3 -0
  224. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_company-scores_legacy_route_actions_1ncspu_.js +3 -0
  225. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_export_route_actions_1lkimty.js +3 -0
  226. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_import_route_actions_1eji0kd.js +3 -0
  227. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_restart_route_actions_00_-u6o.js +3 -0
  228. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_reveal_route_actions_0-moqtn.js +3 -0
  229. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_route_actions_0j0w5ep.js +3 -0
  230. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_settings_route_actions_1bpm9ac.js +3 -0
  231. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_settings_sector-preview_route_actions_0w79454.js +3 -0
  232. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_settings_sector-suggestions_route_actions_1eoqugp.js +3 -0
  233. package/.next/standalone/.next/server/chunks/lib_db-client_15le7cw.js +155 -0
  234. package/.next/standalone/.next/server/chunks/{lib_rpc_0mc73lk.js → lib_rpc_00tx2sm.js} +1 -1
  235. package/.next/standalone/.next/server/chunks/lib_rpc_02-qa4d.js +3 -0
  236. package/.next/standalone/.next/server/chunks/lib_rpc_02ndsg2.js +3 -0
  237. package/.next/standalone/.next/server/chunks/lib_rpc_08q5vp6.js +3 -0
  238. package/.next/standalone/.next/server/chunks/lib_rpc_0_8i3ft.js +3 -0
  239. package/.next/standalone/.next/server/chunks/lib_rpc_0c9d9ti.js +5 -2
  240. package/.next/standalone/.next/server/chunks/lib_rpc_0huvw-3.js +3 -0
  241. package/.next/standalone/.next/server/chunks/lib_rpc_0ip2vdh.js +3 -0
  242. package/.next/standalone/.next/server/chunks/lib_rpc_0jzisgh.js +3 -0
  243. package/.next/standalone/.next/server/chunks/lib_rpc_0yi9xvd.js +3 -0
  244. package/.next/standalone/.next/server/chunks/lib_rpc_1jyhd0o.js +3 -0
  245. package/.next/standalone/.next/server/chunks/lib_rpc_1kn59-i.js +3 -0
  246. package/.next/standalone/.next/server/chunks/lib_rpc_1q2jkza.js +3 -0
  247. package/.next/standalone/.next/server/chunks/lib_rpc_1vpm1sk.js +3 -0
  248. package/.next/standalone/.next/server/chunks/lib_rpc_1x6p_31.js +3 -0
  249. package/.next/standalone/.next/server/chunks/node_modules_next_1zc5q0a._.js +158 -0
  250. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0mocm6d._.js → [root-of-the-server]__0an6blh._.js} +3 -3
  251. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h1_f_2._.js +1 -1
  252. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1m0255u._.js +3 -0
  253. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0bipr5s._.js → [root-of-the-server]__1z1j3ek._.js} +2 -2
  254. package/.next/standalone/.next/server/chunks/ssr/_07u8byv._.js +3 -0
  255. package/.next/standalone/.next/server/chunks/ssr/_08r_mlf._.js +3 -0
  256. package/.next/standalone/.next/server/chunks/ssr/{_0ggabjc._.js → _0942v8n._.js} +1 -1
  257. package/.next/standalone/.next/server/chunks/ssr/{_1djpk8t._.js → _0hl_t7r._.js} +2 -2
  258. package/.next/standalone/.next/server/chunks/ssr/_0tb83dw._.js +132 -0
  259. package/.next/standalone/.next/server/chunks/ssr/_1-87bs1._.js +3 -0
  260. package/.next/standalone/.next/server/chunks/ssr/_17gui6a._.js +1 -1
  261. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_settings_page_actions_11x4dq5.js +3 -0
  262. package/.next/standalone/.next/server/chunks/ssr/app_import_page_1fmu6_l.js +1 -1
  263. package/.next/standalone/.next/server/chunks/ssr/app_launch_page_19t0dyd.js +2 -2
  264. package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +4 -4
  265. package/.next/standalone/.next/server/chunks/ssr/app_profile_page_0u3-l5y.js +1 -1
  266. package/.next/standalone/.next/server/chunks/ssr/app_queue_page_0c6znd6.js +5 -5
  267. package/.next/standalone/.next/server/chunks/ssr/app_settings_page_1f8mjj_.js +3 -0
  268. package/.next/standalone/.next/server/chunks/ssr/app_setup_page_1-282zx.js +2 -2
  269. package/.next/standalone/.next/server/chunks/ssr/lib_0i8v-s3._.js +1 -1
  270. package/.next/standalone/.next/server/chunks/ssr/node_modules_1f8t_rp._.js +23 -0
  271. package/.next/standalone/.next/server/chunks/ssr/node_modules_1nkgb45._.js +2 -2
  272. package/.next/standalone/.next/server/chunks/ssr/{node_modules_01xbj_9._.js → node_modules_1wax83z._.js} +3 -3
  273. package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_00nap8h._.js → node_modules_next_dist_1bunoni._.js} +2 -2
  274. package/.next/standalone/.next/server/edge/chunks/[root-of-the-server]__0pco7a6._.js +2 -2
  275. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  276. package/.next/standalone/.next/server/middleware-manifest.json +15 -7
  277. package/.next/standalone/.next/server/next-font-manifest.js +1 -1
  278. package/.next/standalone/.next/server/next-font-manifest.json +4 -0
  279. package/.next/standalone/.next/server/pages/404.html +1 -1
  280. package/.next/standalone/.next/server/pages/500.html +1 -1
  281. package/.next/standalone/.next/server/prefetch-hints.json +14 -0
  282. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  283. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  284. package/.next/standalone/.next/static/chunks/06x3jiiz96m5t.js +1 -0
  285. package/.next/{static/chunks/34at5d2ifl62i.js → standalone/.next/static/chunks/0ngx9s6-zgshe.js} +5 -5
  286. package/.next/standalone/.next/static/chunks/0q-_khndfxubv.js +2 -0
  287. package/.next/standalone/.next/static/chunks/1c79veqedvubt.js +1 -0
  288. package/.next/standalone/.next/static/chunks/1chp3nx45meg5.js +44 -0
  289. package/.next/standalone/.next/static/chunks/1irqj0lf-fu3d.js +1 -0
  290. package/.next/standalone/.next/static/chunks/1uadqylrod5_v.js +1 -0
  291. package/.next/standalone/.next/static/chunks/23u0zclgwpc4d.js +1 -0
  292. package/.next/standalone/.next/static/chunks/289ktj97di6zg.js +1 -0
  293. package/.next/standalone/.next/static/chunks/2b3lmf8e6uj8m.js +16 -0
  294. package/.next/standalone/.next/static/chunks/2jz311xl1pp_8.js +1 -0
  295. package/.next/standalone/.next/static/chunks/2ot61qsv6_0eq.js +1 -0
  296. package/.next/standalone/.next/static/chunks/3npq5yd7c4dmn.js +2 -0
  297. package/.next/standalone/.next/static/frfHFnRYTA0Wjrw8oZJtY/_clientMiddlewareManifest.js +14 -0
  298. package/.next/standalone/AGENTS.md +10 -0
  299. package/.next/standalone/CHANGELOG.md +325 -0
  300. package/.next/standalone/CONTRIBUTING.md +14 -2
  301. package/.next/standalone/README.md +181 -53
  302. package/.next/standalone/SECURITY.md +120 -10
  303. package/.next/standalone/app/api/company-scores/legacy/route.js +32 -0
  304. package/.next/standalone/app/api/company-scores/route.js +20 -11
  305. package/.next/standalone/app/api/data/export/route.js +49 -0
  306. package/.next/standalone/app/api/data/import/route.js +83 -0
  307. package/.next/standalone/app/api/data/restart/route.js +37 -0
  308. package/.next/standalone/app/api/data/reveal/route.js +14 -0
  309. package/.next/standalone/app/api/data/route.js +39 -0
  310. package/.next/standalone/app/api/ingest/route.js +15 -47
  311. package/.next/standalone/app/api/scraper/route.js +268 -128
  312. package/.next/standalone/app/api/settings/route.js +58 -0
  313. package/.next/standalone/app/api/settings/sector-preview/route.js +38 -0
  314. package/.next/standalone/app/api/settings/sector-suggestions/route.js +20 -0
  315. package/.next/standalone/app/api/update/route.js +197 -24
  316. package/.next/standalone/app/avatars/[file]/route.js +4 -2
  317. package/.next/standalone/app/components/CompanyScores.js +28 -7
  318. package/.next/standalone/app/components/EmptyState.js +8 -0
  319. package/.next/standalone/app/components/ForceGraph.js +40 -36
  320. package/.next/standalone/app/components/LegacyScoresCard.js +129 -0
  321. package/.next/standalone/app/components/Sidebar.js +19 -18
  322. package/.next/standalone/app/components/UpdatePanel.js +317 -99
  323. package/.next/standalone/app/components/UserProvider.js +4 -3
  324. package/.next/standalone/app/components/settings/DataSection.js +437 -0
  325. package/.next/standalone/app/components/settings/SectorSection.js +445 -0
  326. package/.next/standalone/app/components/ui.js +62 -0
  327. package/.next/standalone/app/import/page.js +3 -3
  328. package/.next/standalone/app/launch/page.js +30 -20
  329. package/.next/standalone/app/layout.js +2 -2
  330. package/.next/standalone/app/page.js +15 -2
  331. package/.next/standalone/app/paths/page.js +13 -5
  332. package/.next/standalone/app/profile/page.js +41 -186
  333. package/.next/standalone/app/queue/page.js +8 -2
  334. package/.next/standalone/app/settings/page.js +96 -0
  335. package/.next/standalone/app/setup/page.js +35 -19
  336. package/.next/standalone/bin/args.mjs +44 -0
  337. package/.next/standalone/bin/six-degrees.mjs +16 -17
  338. package/.next/standalone/install.sh +1 -1
  339. package/.next/standalone/lib/companies.js +44 -119
  340. package/.next/standalone/lib/csv.js +61 -27
  341. package/.next/standalone/lib/data-export.js +170 -0
  342. package/.next/standalone/lib/data-folder.js +238 -0
  343. package/.next/standalone/lib/data-import.js +878 -0
  344. package/.next/standalone/lib/db-client.js +48 -3
  345. package/.next/standalone/lib/durable.js +73 -0
  346. package/.next/standalone/lib/gate.js +90 -1
  347. package/.next/standalone/lib/ingest.js +40 -0
  348. package/.next/standalone/lib/legacy-offer.js +185 -0
  349. package/.next/standalone/lib/legacy-scores.js +77 -0
  350. package/.next/standalone/lib/linkedin-limits.js +124 -1
  351. package/.next/standalone/lib/release.js +5 -2
  352. package/.next/standalone/lib/rpc.js +121 -13
  353. package/.next/standalone/lib/sample-stats.js +16 -0
  354. package/.next/standalone/lib/scan-progress.js +13 -0
  355. package/.next/standalone/lib/scan-state.js +53 -0
  356. package/.next/standalone/lib/scanner-python.js +685 -0
  357. package/.next/standalone/lib/scanner-setup.js +104 -0
  358. package/.next/standalone/lib/scoring.js +747 -138
  359. package/.next/standalone/lib/scraper-client.js +10 -6
  360. package/.next/standalone/lib/sector-directory.js +1532 -0
  361. package/.next/standalone/lib/sector-focus.js +163 -0
  362. package/.next/standalone/lib/sector-labels.js +81 -0
  363. package/.next/standalone/lib/settings-effects.js +59 -0
  364. package/.next/standalone/lib/settings.js +83 -0
  365. package/.next/standalone/lib/updater-job.js +838 -0
  366. package/.next/standalone/lib/updater.js +494 -0
  367. package/.next/standalone/middleware.js +25 -28
  368. package/.next/standalone/next.config.mjs +19 -3
  369. package/.next/standalone/package-lock.json +103 -9
  370. package/.next/standalone/package.json +12 -11
  371. package/.next/standalone/public/demo-data.json +1 -1
  372. package/.next/standalone/scripts/apply-update.sh +482 -0
  373. package/.next/standalone/scripts/build-app.mjs +251 -9
  374. package/.next/standalone/scripts/gen-synthetic.mjs +16 -1
  375. package/.next/standalone/scripts/readme_buttons.py +89 -0
  376. package/.next/standalone/scripts/requirements.txt +106 -4
  377. package/.next/standalone/scripts/screenshots.py +2 -0
  378. package/.next/standalone/scripts/test-release-server.mjs +143 -0
  379. package/.next/standalone/server.js +1 -1
  380. package/.next/static/chunks/06x3jiiz96m5t.js +1 -0
  381. package/.next/{standalone/.next/static/chunks/34at5d2ifl62i.js → static/chunks/0ngx9s6-zgshe.js} +5 -5
  382. package/.next/static/chunks/0q-_khndfxubv.js +2 -0
  383. package/.next/static/chunks/1c79veqedvubt.js +1 -0
  384. package/.next/static/chunks/1chp3nx45meg5.js +44 -0
  385. package/.next/static/chunks/1irqj0lf-fu3d.js +1 -0
  386. package/.next/static/chunks/1uadqylrod5_v.js +1 -0
  387. package/.next/static/chunks/23u0zclgwpc4d.js +1 -0
  388. package/.next/static/chunks/289ktj97di6zg.js +1 -0
  389. package/.next/static/chunks/2b3lmf8e6uj8m.js +16 -0
  390. package/.next/static/chunks/2jz311xl1pp_8.js +1 -0
  391. package/.next/static/chunks/2ot61qsv6_0eq.js +1 -0
  392. package/.next/static/chunks/3npq5yd7c4dmn.js +2 -0
  393. package/.next/static/frfHFnRYTA0Wjrw8oZJtY/_clientMiddlewareManifest.js +14 -0
  394. package/CHANGELOG.md +325 -0
  395. package/README.md +181 -53
  396. package/SECURITY.md +120 -10
  397. package/bin/args.mjs +44 -0
  398. package/bin/six-degrees.mjs +16 -17
  399. package/lib/companies.js +44 -119
  400. package/lib/csv.js +61 -27
  401. package/lib/data-export.js +170 -0
  402. package/lib/data-folder.js +238 -0
  403. package/lib/data-import.js +878 -0
  404. package/lib/db-client.js +48 -3
  405. package/lib/durable.js +73 -0
  406. package/lib/gate.js +90 -1
  407. package/lib/ingest.js +40 -0
  408. package/lib/legacy-offer.js +185 -0
  409. package/lib/legacy-scores.js +77 -0
  410. package/lib/linkedin-limits.js +124 -1
  411. package/lib/release.js +5 -2
  412. package/lib/rpc.js +121 -13
  413. package/lib/sample-stats.js +16 -0
  414. package/lib/scan-progress.js +13 -0
  415. package/lib/scan-state.js +53 -0
  416. package/lib/scanner-python.js +685 -0
  417. package/lib/scanner-setup.js +104 -0
  418. package/lib/scoring.js +747 -138
  419. package/lib/scraper-client.js +10 -6
  420. package/lib/sector-directory.js +1532 -0
  421. package/lib/sector-focus.js +163 -0
  422. package/lib/sector-labels.js +81 -0
  423. package/lib/settings-effects.js +59 -0
  424. package/lib/settings.js +83 -0
  425. package/lib/updater-job.js +838 -0
  426. package/lib/updater.js +494 -0
  427. package/package.json +12 -11
  428. package/public/demo-data.json +1 -1
  429. package/scripts/requirements.txt +106 -4
  430. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jrmmj-._.js +0 -150
  431. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qx548g._.js +0 -151
  432. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1an3leo._.js +0 -150
  433. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1m8zedk._.js +0 -155
  434. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1zor0ys._.js +0 -3
  435. package/.next/standalone/.next/server/chunks/_0_rp-01._.js +0 -3
  436. package/.next/standalone/.next/server/chunks/_0hzdk79._.js +0 -3
  437. package/.next/standalone/.next/server/chunks/_0ow7u5r._.js +0 -3
  438. package/.next/standalone/.next/server/chunks/_0t0zc2d._.js +0 -3
  439. package/.next/standalone/.next/server/chunks/_0wa631d._.js +0 -3
  440. package/.next/standalone/.next/server/chunks/_13ccnao._.js +0 -3
  441. package/.next/standalone/.next/server/chunks/_13es063._.js +0 -3
  442. package/.next/standalone/.next/server/chunks/_142872j._.js +0 -3
  443. package/.next/standalone/.next/server/chunks/_18wsb_a._.js +0 -8
  444. package/.next/standalone/.next/server/chunks/_1e-4h5h._.js +0 -3
  445. package/.next/standalone/.next/server/chunks/_1gvvd7n._.js +0 -158
  446. package/.next/standalone/.next/server/chunks/_1moda66._.js +0 -3
  447. package/.next/standalone/.next/server/chunks/_1p6ghzv._.js +0 -3
  448. package/.next/standalone/.next/server/chunks/_1xmmi_v._.js +0 -3
  449. package/.next/standalone/.next/server/chunks/_1z-yrlf._.js +0 -3
  450. package/.next/standalone/.next/server/chunks/ssr/_0bf3x4q._.js +0 -3
  451. package/.next/standalone/.next/server/chunks/ssr/app_paths_page_1ol90m7.js +0 -4
  452. package/.next/standalone/.next/static/N9wokeIiC9rUIGmzBhj6T/_clientMiddlewareManifest.js +0 -6
  453. package/.next/standalone/.next/static/chunks/1odow92u6wxz0.js +0 -1
  454. package/.next/standalone/.next/static/chunks/1wb_is4wsdm-u.js +0 -1
  455. package/.next/standalone/.next/static/chunks/1zmpcmngg5c7-.js +0 -2
  456. package/.next/standalone/.next/static/chunks/220-ne82aus0c.js +0 -44
  457. package/.next/standalone/.next/static/chunks/2rrf5kzx2fhin.js +0 -2
  458. package/.next/standalone/.next/static/chunks/2s_k9x4d0gi9h.js +0 -16
  459. package/.next/standalone/.next/static/chunks/3hsi90cejq2dg.js +0 -1
  460. package/.next/standalone/.next/static/chunks/3pfyuezyqd9ob.js +0 -1
  461. package/.next/standalone/.next/static/chunks/3ts-_4i6bfkh2.js +0 -1
  462. package/.next/standalone/scripts/score-connections.sql +0 -80
  463. package/.next/standalone/scripts/score_new_connections.sql +0 -77
  464. package/.next/static/N9wokeIiC9rUIGmzBhj6T/_clientMiddlewareManifest.js +0 -6
  465. package/.next/static/chunks/1odow92u6wxz0.js +0 -1
  466. package/.next/static/chunks/1wb_is4wsdm-u.js +0 -1
  467. package/.next/static/chunks/1zmpcmngg5c7-.js +0 -2
  468. package/.next/static/chunks/220-ne82aus0c.js +0 -44
  469. package/.next/static/chunks/2rrf5kzx2fhin.js +0 -2
  470. package/.next/static/chunks/2s_k9x4d0gi9h.js +0 -16
  471. package/.next/static/chunks/3hsi90cejq2dg.js +0 -1
  472. package/.next/static/chunks/3pfyuezyqd9ob.js +0 -1
  473. package/.next/static/chunks/3ts-_4i6bfkh2.js +0 -1
  474. package/scripts/score_new_connections.sql +0 -77
  475. /package/.next/standalone/.next/static/{N9wokeIiC9rUIGmzBhj6T → frfHFnRYTA0Wjrw8oZJtY}/_buildManifest.js +0 -0
  476. /package/.next/standalone/.next/static/{N9wokeIiC9rUIGmzBhj6T → frfHFnRYTA0Wjrw8oZJtY}/_ssgManifest.js +0 -0
  477. /package/.next/static/{N9wokeIiC9rUIGmzBhj6T → frfHFnRYTA0Wjrw8oZJtY}/_buildManifest.js +0 -0
  478. /package/.next/static/{N9wokeIiC9rUIGmzBhj6T → frfHFnRYTA0Wjrw8oZJtY}/_ssgManifest.js +0 -0
@@ -4,8 +4,8 @@ import { useState, useEffect, useCallback, useRef } from 'react';
4
4
  import OnboardingGate from '../components/OnboardingGate';
5
5
  import Link from 'next/link';
6
6
  import { stopScrape } from '../../lib/scraper-client';
7
+ import { setupStep } from '../../lib/scanner-setup';
7
8
  import { BudgetBox, CooldownBanner, PausedList } from '../components/LinkedInLimits';
8
- import UpdatePanel from '../components/UpdatePanel';
9
9
 
10
10
  // Everything here runs through /api/scraper. There is deliberately no second
11
11
  // server and no command to copy: the step where people gave up was starting a
@@ -15,7 +15,8 @@ const BG = '#0a0a1a';
15
15
  const LINE = '1px solid rgba(255,255,255,0.1)';
16
16
 
17
17
  const ACTION_LABELS = {
18
- install: 'Installing the scraper',
18
+ install: 'Installing the scanner',
19
+ setup: 'Setting up the scanner',
19
20
  login: 'Waiting for you to sign in',
20
21
  full: 'Scanning your whole network',
21
22
  refresh: 'Checking for new connections',
@@ -30,6 +31,12 @@ export default function SetupPage() {
30
31
  }
31
32
 
32
33
  function SetupInner() {
34
+ // Updates moved to Settings; an old menu item or bookmark still lands there.
35
+ useEffect(() => {
36
+ if (new URLSearchParams(window.location.search).get('check') === 'updates') {
37
+ window.location.replace('/settings?check=updates');
38
+ }
39
+ }, []);
33
40
  const [s, setS] = useState(null);
34
41
  const [busy, setBusy] = useState(false);
35
42
  // Ten, not twenty-five. The only measured number this project has is that
@@ -100,6 +107,10 @@ function SetupInner() {
100
107
 
101
108
  const c = s?.checks || {};
102
109
  const running = s?.running;
110
+ // Step 1 (lib/scanner-setup.js): ready (the Mac app's own Python, or one
111
+ // installed), Install, Set up the scanner (download a Python first), or neither;
112
+ // and a line of its own when the Python inside the app didn't work.
113
+ const step1 = setupStep(s);
103
114
  const needsDeps = s && !c.dependencies;
104
115
  const needsChrome = s && !c.chrome;
105
116
  const notFound = s && !c.scriptsFound;
@@ -183,7 +194,7 @@ function SetupInner() {
183
194
 
184
195
  {notFound && (
185
196
  <Box tone="bad">
186
- <b>Can’t find the scraper files.</b><br />
197
+ <b>Can’t find the scanner files.</b><br />
187
198
  <span style={{ color: '#9aa' }}>
188
199
  Expected <code style={code}>scripts/scrape.py</code> next to the app. If you
189
200
  downloaded a zip, run the app from inside the project folder.
@@ -195,29 +206,30 @@ function SetupInner() {
195
206
  <Box tone="bad">
196
207
  <b>Google Chrome isn’t installed.</b><br />
197
208
  <span style={{ color: '#9aa' }}>
198
- The scraper drives your real Chrome. Install it from{' '}
209
+ The scanner drives your real Chrome. Install it from{' '}
199
210
  <a href="https://www.google.com/chrome/" target="_blank" rel="noreferrer"
200
211
  style={{ color: '#3498DB' }}>google.com/chrome</a>, then reload this page.
201
212
  </span>
202
213
  </Box>
203
214
  )}
204
215
 
205
- {/* ---- step 1 : dependencies ---- */}
216
+ {/* The Python inside the app didn't work: what happened, and what to do instead.
217
+ Red only while there is something to do; once another Python runs the
218
+ scanner it is just news. */}
219
+ {s && step1.note && (
220
+ <Box tone={step1.done ? undefined : 'bad'}>{step1.note}</Box>
221
+ )}
222
+
223
+ {/* ---- step 1 : the scanner itself ---- */}
206
224
  <Step
207
225
  n={1}
208
- done={!!c.dependencies}
209
- title="Install what the scraper needs"
210
- body={
211
- c.dependencies
212
- ? 'Installed.'
213
- : c.python
214
- ? 'One-time, about a minute. Downloads the browser-automation packages.'
215
- : 'Python 3 was not found on this machine. Install it from python.org, then reload.'
216
- }
226
+ done={step1.done}
227
+ title="Set up the scanner"
228
+ body={s ? step1.text : ''}
217
229
  action={
218
- !c.dependencies && c.python && (
219
- <Btn onClick={() => run('install')} disabled={busy || running}>
220
- {running && s.action === 'install' ? 'Installing…' : 'Install'}
230
+ s && step1.button && (
231
+ <Btn onClick={() => run(step1.button.action)} disabled={busy || running}>
232
+ {step1.button.label}
221
233
  </Btn>
222
234
  )
223
235
  }
@@ -416,7 +428,10 @@ function SetupInner() {
416
428
  </>
417
429
  )}
418
430
 
419
- <UpdatePanel />
431
+ <div style={{ marginTop: 32, paddingTop: 20, borderTop: LINE, fontSize: 13.5, color: '#8b9a9a' }}>
432
+ Checking for updates has moved to{' '}
433
+ <Link href="/settings#updates" style={{ color: '#3498DB' }}>Settings →</Link>
434
+ </div>
420
435
 
421
436
  <p style={{ color: '#667', fontSize: 12.5, lineHeight: 1.7, marginTop: 32 }}>
422
437
  Automating LinkedIn may go against its User Agreement, and accounts have been
@@ -523,7 +538,8 @@ function Progress({ p, action }) {
523
538
  }
524
539
  const pct = Math.max(0, Math.min(100, Math.round((p.done / p.total) * 100)));
525
540
  let text;
526
- if (p.kind === 'batch') text = `Person ${p.current} of ${p.total}`;
541
+ if (p.kind === 'download') text = `Downloading Python: ${p.done.toFixed(1)} of ${p.total.toFixed(1)} MB · ${pct}%`;
542
+ else if (p.kind === 'batch') text = `Person ${p.current} of ${p.total}`;
527
543
  else if (action === 'refresh') text = `Looked at ${p.done.toLocaleString()} so far — stops once it reaches people already saved`;
528
544
  else text = `${p.done.toLocaleString()} of ${p.total.toLocaleString()} connections · ${pct}%`;
529
545
 
@@ -0,0 +1,44 @@
1
+ // The npx launcher's command line, kept apart from bin/six-degrees.mjs (which
2
+ // starts a server the moment it runs) so the tests can read it directly.
3
+
4
+ import { homedir } from 'node:os';
5
+ import path from 'node:path';
6
+
7
+ /**
8
+ * A folder named on the command line, made absolute. The launcher changes into
9
+ * the package's own folder before the server starts, so a relative folder
10
+ * passed on as it is would land inside the npx cache, and be lost when that is
11
+ * cleared. A leading ~ is the home folder: the shell expands `--data-dir ~/x`
12
+ * but not `--data-dir=~/x`, which would otherwise make a folder named "~".
13
+ */
14
+ export function absoluteFolder(value, { cwd = process.cwd(), home = homedir() } = {}) {
15
+ const s = String(value);
16
+ const expanded = s === '~' ? home : s.startsWith('~/') ? path.join(home, s.slice(2)) : s;
17
+ return path.resolve(cwd, expanded);
18
+ }
19
+
20
+ /**
21
+ * @returns {{ port, open, dataDir, help, version, error }}
22
+ * dataDir is absolute (absoluteFolder), or null when not given.
23
+ */
24
+ export function parseArgs(argv, { env = process.env, cwd = process.cwd(), home = homedir() } = {}) {
25
+ const out = { port: Number(env.PORT) || 6363, open: true, dataDir: null };
26
+ for (let i = 0; i < argv.length; i++) {
27
+ const a = String(argv[i]);
28
+ if (a === '--port' || a === '-p') out.port = Number(argv[++i]);
29
+ else if (a === '--no-open') out.open = false;
30
+ else if (a === '--data-dir' || a.startsWith('--data-dir=')) {
31
+ const value = a === '--data-dir' ? argv[++i] : a.slice('--data-dir='.length);
32
+ if (value) out.dataDir = absoluteFolder(value, { cwd, home });
33
+ else out.error = '--data-dir needs a folder, for example: --data-dir ~/six-degrees-copy';
34
+ }
35
+ else if (a === '--help' || a === '-h') out.help = true;
36
+ else if (a === '--version' || a === '-v') out.version = true;
37
+ }
38
+ return out;
39
+ }
40
+
41
+ /** The data folder: --data-dir, else SIX_DEGREES_HOME, else ~/.six-degrees. Always absolute, for the same reason. */
42
+ export function resolveDataDir(args, { env = process.env, cwd = process.cwd(), home = homedir() } = {}) {
43
+ return absoluteFolder(args.dataDir || env.SIX_DEGREES_HOME || path.join(home, '.six-degrees'), { cwd, home });
44
+ }
@@ -10,8 +10,9 @@ import { createServer } from 'node:net';
10
10
  import { spawn } from 'node:child_process';
11
11
  import { fileURLToPath } from 'node:url';
12
12
  import { existsSync, mkdirSync } from 'node:fs';
13
- import { homedir, platform } from 'node:os';
13
+ import { platform } from 'node:os';
14
14
  import path from 'node:path';
15
+ import { parseArgs, resolveDataDir } from './args.mjs';
15
16
 
16
17
  const HERE = path.dirname(fileURLToPath(import.meta.url));
17
18
  const ROOT = path.join(HERE, '..');
@@ -33,19 +34,6 @@ function checkNode() {
33
34
  }
34
35
  }
35
36
 
36
- function parseArgs(argv) {
37
- const out = { port: Number(process.env.PORT) || 6363, open: true };
38
- for (let i = 0; i < argv.length; i++) {
39
- const a = argv[i];
40
- if (a === '--port' || a === '-p') out.port = Number(argv[++i]);
41
- else if (a === '--no-open') out.open = false;
42
- else if (a === '--data-dir') process.env.SIX_DEGREES_HOME = argv[++i];
43
- else if (a === '--help' || a === '-h') out.help = true;
44
- else if (a === '--version' || a === '-v') out.version = true;
45
- }
46
- return out;
47
- }
48
-
49
37
  const HELP = `
50
38
  six-degrees — map your professional network as a galaxy, on your own machine
51
39
 
@@ -84,10 +72,15 @@ function freePort(start, attempts = 20) {
84
72
  function openBrowser(url) {
85
73
  const cmd = platform() === 'darwin' ? 'open' : platform() === 'win32' ? 'start' : 'xdg-open';
86
74
  const args = platform() === 'win32' ? ['', url] : [url];
75
+ // A machine with no desktop (no xdg-open) can't open one; say where to go.
76
+ // spawn reports a missing command as an 'error' event, not a throw.
77
+ const instead = () => console.log(` Open ${url} in your browser.`);
87
78
  try {
88
- spawn(cmd, args, { stdio: 'ignore', detached: true, shell: platform() === 'win32' }).unref();
79
+ const child = spawn(cmd, args, { stdio: 'ignore', detached: true, shell: platform() === 'win32' });
80
+ child.on('error', instead);
81
+ child.unref();
89
82
  } catch {
90
- /* a browser that will not open is not worth failing over */
83
+ instead();
91
84
  }
92
85
  }
93
86
 
@@ -101,9 +94,15 @@ async function main() {
101
94
  return;
102
95
  }
103
96
 
97
+ if (args.error) {
98
+ console.error(`\n ${args.error}\n`);
99
+ process.exit(1);
100
+ }
101
+
104
102
  checkNode();
105
103
 
106
- const dataDir = process.env.SIX_DEGREES_HOME || path.join(homedir(), '.six-degrees');
104
+ // Absolute (bin/args.mjs): the server runs from inside the package, not here.
105
+ const dataDir = resolveDataDir(args);
107
106
  if (!existsSync(dataDir)) mkdirSync(dataDir, { recursive: true });
108
107
 
109
108
  const server = path.join(ROOT, '.next', 'standalone', 'server.js');
@@ -110,7 +110,7 @@ stop_running_copy() {
110
110
  main() {
111
111
  printf '\n 6 Degrees — installer\n\n'
112
112
 
113
- [ "$(uname -s)" = "Darwin" ] || fail "This installer is for macOS. On Linux, run it from source (see the README). Windows isn't supported yet."
113
+ [ "$(uname -s)" = "Darwin" ] || fail "This installer is for macOS. On Linux, run: npx six-degrees (needs Node 22.13 or later). Windows isn't supported yet."
114
114
 
115
115
  local arch
116
116
  # A Terminal running under Rosetta reports x86_64 even on Apple Silicon, and
@@ -1,4 +1,4 @@
1
- import { readTitle, currentCompany } from './scoring.js';
1
+ import { readTitle, currentCompany, rolesWithCompanies, networkCompanies } from './scoring.js';
2
2
  // Companies and industries across your network — what the Paths analyzer is
3
3
  // built on. Plain functions, no React, so tests/companies.test.mjs runs them.
4
4
  //
@@ -6,99 +6,6 @@ import { readTitle, currentCompany } from './scoring.js';
6
6
  // industry is inferred from the company name and headline, and labelled
7
7
  // "inferred" wherever it is shown. Unclear stays unclear rather than guessed.
8
8
 
9
- // Merge company name variants
10
- export function normalizeCompany(name) {
11
- const n = (name || '').trim().toLowerCase();
12
- // Social / Media
13
- if (n.includes('snap') && (n.includes('inc') || n === 'snap' || n === 'snapchat')) return 'Snap';
14
- if (n.includes('meta') && (n.includes('platform') || n === 'meta' || n.includes('facebook'))) return 'Meta';
15
- if (n.includes('tiktok') || n.includes('bytedance')) return 'TikTok';
16
- if (n.includes('pinterest')) return 'Pinterest';
17
- // Big Tech
18
- if (n === 'google' || n.includes('alphabet') || (n.includes('google') && n.includes('llc'))) return 'Google';
19
- if (n === 'apple' || n === 'apple inc' || n === 'apple inc.') return 'Apple';
20
- if (n.includes('amazon') && !n.includes('amazon ')) return 'Amazon';
21
- if (n.includes('microsoft')) return 'Microsoft';
22
- // AI
23
- if (n.includes('anthropic')) return 'Anthropic';
24
- if (n.includes('openai') || n === 'open ai') return 'OpenAI';
25
- if (n.includes('deepmind')) return 'DeepMind';
26
- if (n.includes('cohere')) return 'Cohere';
27
- if (n.includes('mistral')) return 'Mistral';
28
- if (n.includes('hugging') && n.includes('face')) return 'Hugging Face';
29
- // Fintech / Crypto
30
- if (n.includes('stripe')) return 'Stripe';
31
- if (n.includes('coinbase')) return 'Coinbase';
32
- if (n.includes('polymarket')) return 'Polymarket';
33
- if (n.includes('blackrock')) return 'BlackRock';
34
- if (n.includes('robinhood')) return 'Robinhood';
35
- // Growth / Commerce
36
- if (n.includes('whatnot')) return 'Whatnot';
37
- if (n.includes('shopify')) return 'Shopify';
38
- if (n.includes('palantir')) return 'Palantir';
39
- if (n.includes('anduril')) return 'Anduril';
40
- if (n.includes('netflix')) return 'Netflix';
41
- if (n.includes('spotify')) return 'Spotify';
42
- if (n.includes('tesla')) return 'Tesla';
43
- if (n.includes('spacex')) return 'SpaceX';
44
- if (n.includes('nvidia')) return 'NVIDIA';
45
- // Defense / Aerospace
46
- if (n.includes('lockheed')) return 'Lockheed Martin';
47
- if (n.includes('northrop')) return 'Northrop Grumman';
48
- if (n.includes('boeing')) return 'Boeing';
49
- if (n.includes('l3harris') || n.includes('l3 harris')) return 'L3Harris';
50
- if (n.includes('leidos')) return 'Leidos';
51
- if (n.includes('nasa')) return 'NASA';
52
- if (n.includes('sandia')) return 'Sandia National Labs';
53
- if (n.includes('blue origin')) return 'Blue Origin';
54
- if (n.includes('raytheon')) return 'Raytheon';
55
- if (n.includes('general dynamics')) return 'General Dynamics';
56
- if (n.includes('bae systems')) return 'BAE Systems';
57
- // Finance
58
- if (n.includes('goldman')) return 'Goldman Sachs';
59
- if (n.includes('jpmorgan') || n.includes('jp morgan')) return 'JPMorgan Chase';
60
- if (n.includes('wells fargo')) return 'Wells Fargo';
61
- if (n.includes('citi') && !n.includes('citizen')) return 'Citi';
62
- if (n.includes('mastercard')) return 'Mastercard';
63
- if (n.includes('visa') && n.length < 15) return 'Visa';
64
- if (n.includes('paypal')) return 'PayPal';
65
- if (n.includes('bny') || n.includes('bank of new york') || n.includes('mellon')) return 'BNY Mellon';
66
- if (n.includes('deloitte')) return 'Deloitte';
67
- if (n.includes('bain')) return 'Bain & Company';
68
- if (n.includes('bloomberg')) return 'Bloomberg';
69
- if (n.includes('usaa')) return 'USAA';
70
- if (n.includes('navy federal')) return 'Navy Federal';
71
- if (n.includes('raymond james')) return 'Raymond James';
72
- if (n.includes('geico')) return 'GEICO';
73
- // Enterprise / Industrial
74
- if (n.includes('oracle')) return 'Oracle';
75
- if (n.includes('ibm')) return 'IBM';
76
- if (n.includes('servicenow')) return 'ServiceNow';
77
- if (n.includes('siemens')) return 'Siemens';
78
- if (n.includes('texas instruments')) return 'Texas Instruments';
79
- if (n.includes('qualcomm')) return 'Qualcomm';
80
- if (n.includes('databricks')) return 'Databricks';
81
- if (n.includes('together.ai') || n.includes('together ai')) return 'Together AI';
82
- if (n.includes('zoox')) return 'Zoox';
83
- // Entertainment
84
- if (n.includes('nbcuniversal') || n.includes('nbc universal')) return 'NBCUniversal';
85
- if (n.includes('universal destinations')) return 'Universal Destinations';
86
- // Other
87
- if (n.includes('humana')) return 'Humana';
88
- if (n.includes('booz allen')) return 'Booz Allen Hamilton';
89
- if (n.includes('abbott')) return 'Abbott';
90
- if (n.includes('walmart')) return 'Walmart';
91
- if (n.includes('publix')) return 'Publix';
92
- if (n.includes('mitsubishi')) return 'Mitsubishi Power';
93
- if (n.includes('oscar health')) return 'Oscar Health';
94
- if (n.includes('ford') && n.length < 15) return 'Ford';
95
- if (n.includes('coca') && n.includes('cola')) return 'Coca-Cola';
96
- if (n.includes('nike')) return 'Nike';
97
- if (n.includes('disney')) return 'Disney';
98
- if (n.includes('ucf') || n.includes('university of central florida')) return 'UCF';
99
- return (name || '').trim();
100
- }
101
-
102
9
  // Seniority for grouping and filters, read by lib/scoring.js so Paths and the
103
10
  // power score never disagree about someone's level (0 intern/student … 6 C-suite).
104
11
  export function getSeniority(headline) {
@@ -106,25 +13,36 @@ export function getSeniority(headline) {
106
13
  return { key: t.key, label: t.label, level: t.level };
107
14
  }
108
15
 
109
- /** The company someone works at now: a company scan's, else their current role's (lib/scoring.js). */
16
+ /**
17
+ * The company someone works at now: a company scan's, else their current
18
+ * role's, named as scoring names it (lib/scoring.js cleanCompany), so Paths
19
+ * groups people under the companies the score is built on. It used to merge
20
+ * names by a second, hand-picked list of its own, which also merged by
21
+ * mistake: Oxford, Hartford and Bradford were Ford, and Bainbridge was Bain.
22
+ */
110
23
  export function companyOf(c) {
111
- const co = currentCompany(c);
112
- return co ? normalizeCompany(co) || co : null;
24
+ return currentCompany(c);
113
25
  }
114
26
 
115
27
  // Order matters: the first industry whose words match wins, checked against the
116
- // company name first (it is the stronger signal), then the headline.
28
+ // company name first (it is the stronger signal), then the headline. The words
29
+ // are the same for everyone: no one school, region or company of one person's,
30
+ // no job every kind of company has (a "Head of Growth" can work anywhere, so
31
+ // it is "growth marketing" here), and no word that is also plain English ("AR
32
+ // Specialist" is accounts receivable). docs/brain/SCORING.md lists the words
33
+ // taken out. Editing them changes the stored scores' list stamp (lib/rpc.js),
34
+ // since a company's one industry can decide its estimate and your sector.
117
35
  export const INDUSTRIES = [
118
36
  { key: 'defense', label: 'Government, Defense & Aerospace', color: '#7f8c8d',
119
- words: /\b(government|federal|state of|county|city of|defen[cs]e|army|navy|air force|marine corps|military|dod|nasa|aerospace|lockheed|northrop|boeing|raytheon|l3harris|leidos|anduril|sandia|blue origin|spacex|public sector)\b/i },
120
- { key: 'finance', label: 'Finance, VC & Crypto', color: '#2ecc71',
121
- words: /\b(bank|banking|capital|ventures?|vc|investments?|investor|fund|private equity|asset management|wealth|trading|trader|hedge|crypto|blockchain|web3|defi|fintech|stripe|coinbase|blackrock|robinhood|polymarket|goldman|morgan stanley|jpmorgan|chase|bny|mellon|wells fargo|citi|citigroup|capital one|fidelity|vanguard|schwab|visa|mastercard|amex|american express|paypal|insurance|accounting|cpa|financial)\b/i },
37
+ words: /\b(government|federal|state of|county|city of|defen[cs]e|army|navy|air force|marine corps|military|dod|nasa|aerospace|lockheed|northrop|boeing|raytheon|l3harris|leidos|blue origin|spacex|public sector)\b/i },
38
+ { key: 'finance', label: 'Finance & Investing', color: '#2ecc71',
39
+ words: /\b(bank|banking|capital|ventures?|vc|investments?|investor|fund|private equity|growth equity|asset management|wealth|trading|trader|hedge|crypto|blockchain|web3|defi|fintech|stripe|coinbase|blackrock|robinhood|goldman|morgan stanley|jpmorgan|chase|bny|mellon|wells fargo|citi|citigroup|capital one|fidelity|vanguard|schwab|visa|mastercard|amex|american express|paypal|insurance|accounting|cpa|financial)\b/i },
122
40
  { key: 'health', label: 'Healthcare & Biotech', color: '#e74c3c',
123
41
  words: /\b(health|healthcare|medical|medicine|hospital|clinic|pharma|pharmaceutical|biotech|nurse|nursing|physician|doctor|dental|therapy|therapist|wellness)\b/i },
124
42
  { key: 'education', label: 'Education', color: '#f1c40f',
125
- words: /\b(university|college|school|education|student|professor|teacher|academy|ucf|phd|faculty|alumni)\b/i },
126
- { key: 'media', label: 'Marketing, Media & Creator', color: '#e67e22',
127
- words: /\b(marketing|brand|branding|advertising|agency|media|content|social media|creative|creator|influencer|pr|public relations|communications|snap|snapchat|tiktok|pinterest|youtube|lens|ar|growth)\b/i },
43
+ words: /\b(university|college|school|education|student|professor|teacher|academy|phd|faculty|alumni)\b/i },
44
+ { key: 'media', label: 'Marketing & Media', color: '#e67e22',
45
+ words: /\b(marketing|brand|branding|advertising|agency|media|content|social media|creative|creator|influencer|pr|public relations|communications|tiktok|pinterest|youtube|growth marketing)\b/i },
128
46
  { key: 'entertainment', label: 'Entertainment & Gaming', color: '#9b59b6',
129
47
  words: /\b(entertainment|film|movie|music|records|gaming|games?|esports|studio|studios|netflix|disney|spotify|hollywood|theater|theatre|sports)\b/i },
130
48
  { key: 'tech', label: 'Tech, Software & AI', color: '#3498db',
@@ -134,7 +52,7 @@ export const INDUSTRIES = [
134
52
  { key: 'realestate', label: 'Real Estate & Construction', color: '#d35400',
135
53
  words: /\b(real estate|realtor|realty|property|properties|construction|architecture|architect|mortgage|homes|housing|builders?)\b/i },
136
54
  { key: 'consumer', label: 'Retail, Consumer & Hospitality', color: '#ff79c6',
137
- words: /\b(retail|e-?commerce|shopify|consumer|cpg|fashion|apparel|beauty|cosmetics|food|beverage|restaurant|hospitality|hotel|travel|tourism|coca-cola|nike|whatnot|store|shop)\b/i },
55
+ words: /\b(retail|e-?commerce|shopify|consumer|cpg|fashion|apparel|beauty|cosmetics|food|beverage|restaurant|hospitality|hotel|travel|tourism|coca-cola|nike|store|shop)\b/i },
138
56
  { key: 'industry', label: 'Manufacturing, Energy & Logistics', color: '#95a5a6',
139
57
  words: /\b(manufacturing|energy|oil|gas|solar|utilities|automotive|tesla|siemens|ge|general electric|honeywell|3m|logistics|supply chain|shipping|freight|fedex|ups|industrial|mining|chemicals?)\b/i },
140
58
  { key: 'nonprofit', label: 'Nonprofit & Community', color: '#bdc3c7',
@@ -154,14 +72,30 @@ export function industryOf(company, headline) {
154
72
  return UNKNOWN_INDUSTRY;
155
73
  }
156
74
 
75
+ /** industryOf as a key: what lib/scoring.js is handed, since it imports nothing. */
76
+ export const industryKeyOf = (company, headline) => industryOf(company, headline).key;
77
+
157
78
  export const isSenior = (headline) => getSeniority(headline).level >= 4;
158
79
 
159
80
  /**
160
81
  * Every company in the network with the people there.
161
82
  * @returns Map name -> { name, industry, people, d1, d2, d3, S, A, senior }
162
83
  * People are kept once (by profile URL), at their closest degree.
84
+ *
85
+ * A company's industry is the one scoring uses (lib/scoring.js
86
+ * networkCompanies over the same rows): the curated list's, else the name's,
87
+ * else what most of its people say. So a company's colour here is the sector
88
+ * Settings → Your sector leans on, and each company is the one scoring
89
+ * scores: both name it with cleanCompany().
163
90
  */
164
91
  export function buildCompanyIndex(rows = []) {
92
+ // Each headline is read once, for the industries and for companyOf below.
93
+ const parsed = new Map();
94
+ const rolesOf = (r) => {
95
+ if (!parsed.has(r)) parsed.set(r, rolesWithCompanies(r));
96
+ return parsed.get(r);
97
+ };
98
+ const { industries } = networkCompanies(rows, { industryOf: industryKeyOf, rolesOf });
165
99
  const best = new Map();
166
100
  for (const r of rows) {
167
101
  const key = r.profile_url || `id:${r.id}`;
@@ -170,11 +104,12 @@ export function buildCompanyIndex(rows = []) {
170
104
  }
171
105
  const index = new Map();
172
106
  for (const r of best.values()) {
173
- const name = companyOf(r);
107
+ // companyOf(r), from the roles already read.
108
+ const name = rolesOf(r).find((x) => !x.former)?.company;
174
109
  if (!name) continue;
175
110
  let co = index.get(name);
176
111
  if (!co) {
177
- co = { name, people: [], d1: 0, d2: 0, d3: 0, S: 0, A: 0, senior: 0, votes: {} };
112
+ co = { name, people: [], d1: 0, d2: 0, d3: 0, S: 0, A: 0, senior: 0 };
178
113
  index.set(name, co);
179
114
  }
180
115
  co.people.push(r);
@@ -182,19 +117,9 @@ export function buildCompanyIndex(rows = []) {
182
117
  if (r.tier === 'S') co.S++;
183
118
  if (r.tier === 'A') co.A++;
184
119
  if (isSenior(r.headline)) co.senior++;
185
- const ind = industryOf(name, r.headline).key;
186
- co.votes[ind] = (co.votes[ind] || 0) + 1;
187
- }
188
- for (const co of index.values()) {
189
- // The company name decides when it can; otherwise the most common headline industry.
190
- const byName = industryOf(co.name, null);
191
- if (byName !== UNKNOWN_INDUSTRY) co.industry = byName;
192
- else {
193
- const [top] = Object.entries(co.votes).filter(([k]) => k !== 'unknown').sort((a, b) => b[1] - a[1]);
194
- co.industry = top ? industryByKey(top[0]) : UNKNOWN_INDUSTRY;
195
- }
196
- delete co.votes;
197
120
  }
121
+ // Every company here is someone's current one, so networkCompanies read it too.
122
+ for (const co of index.values()) co.industry = industryByKey(industries.get(co.name));
198
123
  return index;
199
124
  }
200
125
 
@@ -56,6 +56,34 @@ function hashId(input) {
56
56
  return `csv-${Math.abs(h).toString(36)}`;
57
57
  }
58
58
 
59
+ /** One connection, built from what the export itself says about the person. */
60
+ function connectionFrom({ id, name, role, company, profileUrl, connected_date }) {
61
+ // /paths and the sidebar read seniority off `headline`, not `role`, so
62
+ // rebuild the "Role at Company" shape the scanner would have produced.
63
+ const headline = role && company ? `${role} at ${company}` : role || company || name;
64
+ return {
65
+ id,
66
+ degree: 1,
67
+ name,
68
+ headline,
69
+ role,
70
+ company,
71
+ profile_url: profileUrl || null,
72
+ profile_image_url: null, // the official export carries no photos
73
+ connected_date,
74
+ source_connection_id: null,
75
+ is_catalyst: false,
76
+ catalyst_score: null,
77
+ circle_power: null,
78
+ circle_s_count: null,
79
+ circle_a_count: null,
80
+ circle_elite_pct: null,
81
+ outreach_status: null,
82
+ unlock_status: null,
83
+ ...scoreRecord(headline, company),
84
+ };
85
+ }
86
+
59
87
  // ── The importer ───────────────────────────────────────────────────────────
60
88
  export function parseConnectionsCsv(text) {
61
89
  const rows = parseCsv(text);
@@ -90,10 +118,6 @@ export function parseConnectionsCsv(text) {
90
118
  const role = cell(iPosition);
91
119
  const profileUrl = cell(iUrl);
92
120
 
93
- // /paths and the sidebar read seniority off `headline`, not `role`, so
94
- // rebuild the "Role at Company" shape the scraper would have produced.
95
- const headline = role && company ? `${role} at ${company}` : role || company || name;
96
-
97
121
  const id = profileUrl ? hashId(profileUrl) : `csv-row-${connections.length}`;
98
122
  if (seen.has(id)) { skipped++; continue; }
99
123
  seen.add(id);
@@ -105,27 +129,7 @@ export function parseConnectionsCsv(text) {
105
129
  if (!isNaN(d.getTime())) connected_date = d.toISOString().split('T')[0];
106
130
  }
107
131
 
108
- connections.push({
109
- id,
110
- degree: 1,
111
- name,
112
- headline,
113
- role,
114
- company,
115
- profile_url: profileUrl || null,
116
- profile_image_url: null, // the official export carries no photos
117
- connected_date,
118
- source_connection_id: null,
119
- is_catalyst: false,
120
- catalyst_score: null,
121
- circle_power: null,
122
- circle_s_count: null,
123
- circle_a_count: null,
124
- circle_elite_pct: null,
125
- outreach_status: null,
126
- unlock_status: null,
127
- ...scoreRecord(headline, company),
128
- });
132
+ connections.push(connectionFrom({ id, name, role, company, profileUrl, connected_date }));
129
133
  }
130
134
 
131
135
  if (!connections.length) {
@@ -148,20 +152,50 @@ export function saveSessionNetwork({ degree1 = [], degree2 = [], source = 'csv'
148
152
  }
149
153
  }
150
154
 
155
+ // A scored row is ~540 characters and the tab holds ~5 million, which capped an
156
+ // import near 9,000 connections. So the tab keeps only what the export says about
157
+ // each person (~130 characters) and scores it again on load: an export at
158
+ // LinkedIn's own maximum of 30,000 connections fits.
159
+ export function packConnections(connections) {
160
+ return connections.map((c) => [c.id, c.name, c.role, c.company, c.profile_url, c.connected_date]);
161
+ }
162
+
163
+ export function unpackConnections(rows = []) {
164
+ return rows
165
+ .map(([id, name, role, company, profileUrl, connected_date]) => connectionFrom({ id, name, role, company, profileUrl, connected_date }))
166
+ .sort((a, b) => b.power_score - a.power_score);
167
+ }
168
+
151
169
  export function saveCsvNetwork(connections) {
152
- return saveSessionNetwork({ degree1: connections, degree2: [], source: 'csv' });
170
+ try {
171
+ sessionStorage.setItem(STORAGE_KEY, JSON.stringify({
172
+ packed: packConnections(connections), degree2: [], source: 'csv', importedAt: Date.now(),
173
+ }));
174
+ return true;
175
+ } catch {
176
+ return false; // quota
177
+ }
153
178
  }
154
179
 
155
180
  export function hasCsvNetwork() {
156
181
  try { return !!sessionStorage.getItem(STORAGE_KEY); } catch { return false; }
157
182
  }
158
183
 
184
+ /** 'csv' or 'sample' when this tab holds one, else null — without rescoring it as loadCsvNetwork() does. */
185
+ export function csvNetworkSource() {
186
+ try {
187
+ const raw = sessionStorage.getItem(STORAGE_KEY);
188
+ return raw ? JSON.parse(raw).source || 'csv' : null;
189
+ } catch { return null; }
190
+ }
191
+
159
192
  export function loadCsvNetwork() {
160
193
  try {
161
194
  const raw = sessionStorage.getItem(STORAGE_KEY);
162
195
  if (!raw) return null;
163
196
  const parsed = JSON.parse(raw);
164
- return { degree1: parsed.degree1 || [], degree2: parsed.degree2 || [], source: parsed.source || 'csv' };
197
+ const degree1 = parsed.packed ? unpackConnections(parsed.packed) : parsed.degree1 || [];
198
+ return { degree1, degree2: parsed.degree2 || [], source: parsed.source || 'csv' };
165
199
  } catch { return null; }
166
200
  }
167
201