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.
Files changed (470) 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 +10 -10
  18. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +10 -10
  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 +12 -12
  128. package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +12 -12
  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 +12 -12
  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 +12 -12
  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 +12 -12
  140. package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +12 -12
  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 +12 -12
  149. package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +12 -12
  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 +12 -12
  156. package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +12 -12
  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 +12 -12
  163. package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +12 -12
  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 +12 -12
  185. package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +12 -12
  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]__1m0255u._.js +3 -0
  252. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0bipr5s._.js → [root-of-the-server]__1z1j3ek._.js} +2 -2
  253. package/.next/standalone/.next/server/chunks/ssr/_07u8byv._.js +3 -0
  254. package/.next/standalone/.next/server/chunks/ssr/_08r_mlf._.js +3 -0
  255. package/.next/standalone/.next/server/chunks/ssr/{_0ggabjc._.js → _0942v8n._.js} +1 -1
  256. package/.next/standalone/.next/server/chunks/ssr/{_1djpk8t._.js → _0hl_t7r._.js} +2 -2
  257. package/.next/standalone/.next/server/chunks/ssr/_0tb83dw._.js +132 -0
  258. package/.next/standalone/.next/server/chunks/ssr/_1-87bs1._.js +3 -0
  259. package/.next/standalone/.next/server/chunks/ssr/_17gui6a._.js +1 -1
  260. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_settings_page_actions_11x4dq5.js +3 -0
  261. package/.next/standalone/.next/server/chunks/ssr/app_launch_page_19t0dyd.js +2 -2
  262. package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +4 -4
  263. package/.next/standalone/.next/server/chunks/ssr/app_profile_page_0u3-l5y.js +1 -1
  264. package/.next/standalone/.next/server/chunks/ssr/app_queue_page_0c6znd6.js +5 -5
  265. package/.next/standalone/.next/server/chunks/ssr/app_settings_page_1f8mjj_.js +3 -0
  266. package/.next/standalone/.next/server/chunks/ssr/app_setup_page_1-282zx.js +2 -2
  267. package/.next/standalone/.next/server/chunks/ssr/lib_0i8v-s3._.js +1 -1
  268. package/.next/standalone/.next/server/chunks/ssr/node_modules_1f8t_rp._.js +23 -0
  269. package/.next/standalone/.next/server/chunks/ssr/node_modules_1nkgb45._.js +2 -2
  270. package/.next/standalone/.next/server/chunks/ssr/{node_modules_01xbj_9._.js → node_modules_1wax83z._.js} +3 -3
  271. package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_00nap8h._.js → node_modules_next_dist_1bunoni._.js} +2 -2
  272. package/.next/standalone/.next/server/edge/chunks/[root-of-the-server]__0pco7a6._.js +2 -2
  273. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  274. package/.next/standalone/.next/server/middleware-manifest.json +15 -7
  275. package/.next/standalone/.next/server/next-font-manifest.js +1 -1
  276. package/.next/standalone/.next/server/next-font-manifest.json +4 -0
  277. package/.next/standalone/.next/server/pages/404.html +1 -1
  278. package/.next/standalone/.next/server/pages/500.html +1 -1
  279. package/.next/standalone/.next/server/prefetch-hints.json +14 -0
  280. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  281. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  282. package/.next/standalone/.next/static/chunks/06x3jiiz96m5t.js +1 -0
  283. package/.next/standalone/.next/static/chunks/{34at5d2ifl62i.js → 0ngx9s6-zgshe.js} +5 -5
  284. package/.next/standalone/.next/static/chunks/0q-_khndfxubv.js +2 -0
  285. package/.next/standalone/.next/static/chunks/1c79veqedvubt.js +1 -0
  286. package/.next/standalone/.next/static/chunks/1chp3nx45meg5.js +44 -0
  287. package/.next/standalone/.next/static/chunks/1irqj0lf-fu3d.js +1 -0
  288. package/.next/standalone/.next/static/chunks/1uadqylrod5_v.js +1 -0
  289. package/.next/standalone/.next/static/chunks/23u0zclgwpc4d.js +1 -0
  290. package/.next/standalone/.next/static/chunks/289ktj97di6zg.js +1 -0
  291. package/.next/standalone/.next/static/chunks/2b3lmf8e6uj8m.js +16 -0
  292. package/.next/standalone/.next/static/chunks/2jz311xl1pp_8.js +1 -0
  293. package/.next/standalone/.next/static/chunks/3npq5yd7c4dmn.js +2 -0
  294. package/.next/standalone/.next/static/qqqcxvzBUizkECrT4swyK/_clientMiddlewareManifest.js +14 -0
  295. package/.next/standalone/CHANGELOG.md +298 -0
  296. package/.next/standalone/CONTRIBUTING.md +5 -2
  297. package/.next/standalone/README.md +138 -30
  298. package/.next/standalone/SECURITY.md +117 -10
  299. package/.next/standalone/app/api/company-scores/legacy/route.js +32 -0
  300. package/.next/standalone/app/api/company-scores/route.js +20 -11
  301. package/.next/standalone/app/api/data/export/route.js +49 -0
  302. package/.next/standalone/app/api/data/import/route.js +83 -0
  303. package/.next/standalone/app/api/data/restart/route.js +37 -0
  304. package/.next/standalone/app/api/data/reveal/route.js +14 -0
  305. package/.next/standalone/app/api/data/route.js +39 -0
  306. package/.next/standalone/app/api/ingest/route.js +15 -47
  307. package/.next/standalone/app/api/scraper/route.js +264 -125
  308. package/.next/standalone/app/api/settings/route.js +58 -0
  309. package/.next/standalone/app/api/settings/sector-preview/route.js +38 -0
  310. package/.next/standalone/app/api/settings/sector-suggestions/route.js +20 -0
  311. package/.next/standalone/app/api/update/route.js +188 -23
  312. package/.next/standalone/app/avatars/[file]/route.js +4 -2
  313. package/.next/standalone/app/components/CompanyScores.js +28 -7
  314. package/.next/standalone/app/components/EmptyState.js +8 -0
  315. package/.next/standalone/app/components/ForceGraph.js +39 -35
  316. package/.next/standalone/app/components/LegacyScoresCard.js +129 -0
  317. package/.next/standalone/app/components/Sidebar.js +11 -10
  318. package/.next/standalone/app/components/UpdatePanel.js +306 -119
  319. package/.next/standalone/app/components/UserProvider.js +4 -3
  320. package/.next/standalone/app/components/settings/DataSection.js +437 -0
  321. package/.next/standalone/app/components/settings/SectorSection.js +445 -0
  322. package/.next/standalone/app/components/ui.js +62 -0
  323. package/.next/standalone/app/launch/page.js +30 -20
  324. package/.next/standalone/app/page.js +13 -0
  325. package/.next/standalone/app/paths/page.js +12 -4
  326. package/.next/standalone/app/profile/page.js +41 -8
  327. package/.next/standalone/app/queue/page.js +8 -2
  328. package/.next/standalone/app/settings/page.js +96 -0
  329. package/.next/standalone/app/setup/page.js +32 -16
  330. package/.next/standalone/bin/args.mjs +44 -0
  331. package/.next/standalone/bin/six-degrees.mjs +9 -15
  332. package/.next/standalone/lib/companies.js +44 -119
  333. package/.next/standalone/lib/csv.js +8 -0
  334. package/.next/standalone/lib/data-export.js +170 -0
  335. package/.next/standalone/lib/data-folder.js +238 -0
  336. package/.next/standalone/lib/data-import.js +878 -0
  337. package/.next/standalone/lib/db-client.js +48 -3
  338. package/.next/standalone/lib/durable.js +73 -0
  339. package/.next/standalone/lib/gate.js +90 -1
  340. package/.next/standalone/lib/ingest.js +40 -0
  341. package/.next/standalone/lib/legacy-offer.js +185 -0
  342. package/.next/standalone/lib/legacy-scores.js +77 -0
  343. package/.next/standalone/lib/linkedin-limits.js +124 -1
  344. package/.next/standalone/lib/rpc.js +121 -13
  345. package/.next/standalone/lib/sample-stats.js +16 -0
  346. package/.next/standalone/lib/scan-progress.js +13 -0
  347. package/.next/standalone/lib/scan-state.js +53 -0
  348. package/.next/standalone/lib/scanner-python.js +685 -0
  349. package/.next/standalone/lib/scanner-setup.js +104 -0
  350. package/.next/standalone/lib/scoring.js +747 -138
  351. package/.next/standalone/lib/scraper-client.js +9 -5
  352. package/.next/standalone/lib/sector-directory.js +1532 -0
  353. package/.next/standalone/lib/sector-focus.js +163 -0
  354. package/.next/standalone/lib/sector-labels.js +81 -0
  355. package/.next/standalone/lib/settings-effects.js +59 -0
  356. package/.next/standalone/lib/settings.js +83 -0
  357. package/.next/standalone/lib/updater-job.js +838 -0
  358. package/.next/standalone/lib/updater.js +494 -0
  359. package/.next/standalone/middleware.js +25 -28
  360. package/.next/standalone/next.config.mjs +19 -3
  361. package/.next/standalone/package-lock.json +2 -2
  362. package/.next/standalone/package.json +1 -2
  363. package/.next/standalone/scripts/apply-update.sh +482 -0
  364. package/.next/standalone/scripts/build-app.mjs +251 -9
  365. package/.next/standalone/scripts/requirements.txt +106 -4
  366. package/.next/standalone/scripts/test-release-server.mjs +143 -0
  367. package/.next/standalone/server.js +1 -1
  368. package/.next/static/chunks/06x3jiiz96m5t.js +1 -0
  369. package/.next/static/chunks/{34at5d2ifl62i.js → 0ngx9s6-zgshe.js} +5 -5
  370. package/.next/static/chunks/0q-_khndfxubv.js +2 -0
  371. package/.next/static/chunks/1c79veqedvubt.js +1 -0
  372. package/.next/static/chunks/1chp3nx45meg5.js +44 -0
  373. package/.next/static/chunks/1irqj0lf-fu3d.js +1 -0
  374. package/.next/static/chunks/1uadqylrod5_v.js +1 -0
  375. package/.next/static/chunks/23u0zclgwpc4d.js +1 -0
  376. package/.next/static/chunks/289ktj97di6zg.js +1 -0
  377. package/.next/static/chunks/2b3lmf8e6uj8m.js +16 -0
  378. package/.next/static/chunks/2jz311xl1pp_8.js +1 -0
  379. package/.next/static/chunks/3npq5yd7c4dmn.js +2 -0
  380. package/.next/static/qqqcxvzBUizkECrT4swyK/_clientMiddlewareManifest.js +14 -0
  381. package/CHANGELOG.md +298 -0
  382. package/README.md +138 -30
  383. package/SECURITY.md +117 -10
  384. package/bin/args.mjs +44 -0
  385. package/bin/six-degrees.mjs +9 -15
  386. package/lib/companies.js +44 -119
  387. package/lib/csv.js +8 -0
  388. package/lib/data-export.js +170 -0
  389. package/lib/data-folder.js +238 -0
  390. package/lib/data-import.js +878 -0
  391. package/lib/db-client.js +48 -3
  392. package/lib/durable.js +73 -0
  393. package/lib/gate.js +90 -1
  394. package/lib/ingest.js +40 -0
  395. package/lib/legacy-offer.js +185 -0
  396. package/lib/legacy-scores.js +77 -0
  397. package/lib/linkedin-limits.js +124 -1
  398. package/lib/rpc.js +121 -13
  399. package/lib/sample-stats.js +16 -0
  400. package/lib/scan-progress.js +13 -0
  401. package/lib/scan-state.js +53 -0
  402. package/lib/scanner-python.js +685 -0
  403. package/lib/scanner-setup.js +104 -0
  404. package/lib/scoring.js +747 -138
  405. package/lib/scraper-client.js +9 -5
  406. package/lib/sector-directory.js +1532 -0
  407. package/lib/sector-focus.js +163 -0
  408. package/lib/sector-labels.js +81 -0
  409. package/lib/settings-effects.js +59 -0
  410. package/lib/settings.js +83 -0
  411. package/lib/updater-job.js +838 -0
  412. package/lib/updater.js +494 -0
  413. package/package.json +1 -2
  414. package/scripts/requirements.txt +106 -4
  415. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jrmmj-._.js +0 -150
  416. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qx548g._.js +0 -151
  417. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1an3leo._.js +0 -150
  418. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1m8zedk._.js +0 -155
  419. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1zor0ys._.js +0 -3
  420. package/.next/standalone/.next/server/chunks/_0_rp-01._.js +0 -3
  421. package/.next/standalone/.next/server/chunks/_0hzdk79._.js +0 -3
  422. package/.next/standalone/.next/server/chunks/_0ow7u5r._.js +0 -3
  423. package/.next/standalone/.next/server/chunks/_0t0zc2d._.js +0 -3
  424. package/.next/standalone/.next/server/chunks/_0wa631d._.js +0 -3
  425. package/.next/standalone/.next/server/chunks/_13ccnao._.js +0 -3
  426. package/.next/standalone/.next/server/chunks/_13es063._.js +0 -3
  427. package/.next/standalone/.next/server/chunks/_142872j._.js +0 -3
  428. package/.next/standalone/.next/server/chunks/_18wsb_a._.js +0 -8
  429. package/.next/standalone/.next/server/chunks/_1e-4h5h._.js +0 -3
  430. package/.next/standalone/.next/server/chunks/_1gvvd7n._.js +0 -158
  431. package/.next/standalone/.next/server/chunks/_1moda66._.js +0 -3
  432. package/.next/standalone/.next/server/chunks/_1p6ghzv._.js +0 -3
  433. package/.next/standalone/.next/server/chunks/_1xmmi_v._.js +0 -3
  434. package/.next/standalone/.next/server/chunks/_1z-yrlf._.js +0 -3
  435. package/.next/standalone/.next/server/chunks/ssr/_0bf3x4q._.js +0 -3
  436. package/.next/standalone/.next/server/chunks/ssr/app_paths_page_1ol90m7.js +0 -4
  437. package/.next/standalone/.next/static/ZGTiDrZ5NHGETgGdlhssu/_clientMiddlewareManifest.js +0 -6
  438. package/.next/standalone/.next/static/chunks/0jk64vo17avsb.js +0 -1
  439. package/.next/standalone/.next/static/chunks/0s65dsrthylo6.js +0 -2
  440. package/.next/standalone/.next/static/chunks/0uyfdhi8dek85.js +0 -16
  441. package/.next/standalone/.next/static/chunks/220-ne82aus0c.js +0 -44
  442. package/.next/standalone/.next/static/chunks/229haorf0f19b.js +0 -2
  443. package/.next/standalone/.next/static/chunks/2g54uafnwuakc.js +0 -1
  444. package/.next/standalone/.next/static/chunks/2spwqs6b6dx13.js +0 -1
  445. package/.next/standalone/.next/static/chunks/38dlepuubiox0.js +0 -1
  446. package/.next/standalone/scripts/score-connections.sql +0 -80
  447. package/.next/standalone/scripts/score_new_connections.sql +0 -77
  448. package/.next/standalone/site/app.js +0 -84
  449. package/.next/standalone/site/index.html +0 -221
  450. package/.next/standalone/site/style.css +0 -155
  451. package/.next/standalone/site/video/install-mac-poster.jpg +0 -0
  452. package/.next/standalone/site/video/install-mac.mp4 +0 -0
  453. package/.next/standalone/site/video/linux-poster.jpg +0 -0
  454. package/.next/standalone/site/video/linux.mp4 +0 -0
  455. package/.next/standalone/site/video/scan-poster.jpg +0 -0
  456. package/.next/standalone/site/video/scan.mp4 +0 -0
  457. package/.next/static/ZGTiDrZ5NHGETgGdlhssu/_clientMiddlewareManifest.js +0 -6
  458. package/.next/static/chunks/0jk64vo17avsb.js +0 -1
  459. package/.next/static/chunks/0s65dsrthylo6.js +0 -2
  460. package/.next/static/chunks/0uyfdhi8dek85.js +0 -16
  461. package/.next/static/chunks/220-ne82aus0c.js +0 -44
  462. package/.next/static/chunks/229haorf0f19b.js +0 -2
  463. package/.next/static/chunks/2g54uafnwuakc.js +0 -1
  464. package/.next/static/chunks/2spwqs6b6dx13.js +0 -1
  465. package/.next/static/chunks/38dlepuubiox0.js +0 -1
  466. package/scripts/score_new_connections.sql +0 -77
  467. /package/.next/standalone/.next/static/{ZGTiDrZ5NHGETgGdlhssu → qqqcxvzBUizkECrT4swyK}/_buildManifest.js +0 -0
  468. /package/.next/standalone/.next/static/{ZGTiDrZ5NHGETgGdlhssu → qqqcxvzBUizkECrT4swyK}/_ssgManifest.js +0 -0
  469. /package/.next/static/{ZGTiDrZ5NHGETgGdlhssu → qqqcxvzBUizkECrT4swyK}/_buildManifest.js +0 -0
  470. /package/.next/static/{ZGTiDrZ5NHGETgGdlhssu → qqqcxvzBUizkECrT4swyK}/_ssgManifest.js +0 -0
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { useEffect, useState, useRef, useCallback } from 'react';
4
4
  import Link from 'next/link';
5
+ import { SAMPLE_STATS } from '../../lib/sample-stats';
5
6
 
6
7
  // ── Intersection Observer hook for scroll-triggered animations ──
7
8
  function useInView(options = {}) {
@@ -177,13 +178,15 @@ function HeroSection() {
177
178
  // ═══════════════════════════════════════════════════════════════
178
179
  // STATS BAR — Animated counters
179
180
  // ═══════════════════════════════════════════════════════════════
181
+ // The numbers on this page are the invented sample network's
182
+ // (lib/sample-stats.js), never one person's real network.
180
183
  function StatsBar() {
181
184
  const [ref, inView] = useInView();
182
185
  const stats = [
183
- { label: 'Connections Mapped', value: 2438, color: '#3498DB' },
184
- { label: 'Bridges Discovered', value: 25, color: '#FFD700' },
185
- { label: 'Power Scored', value: 575, color: '#9B59B6' },
186
- { label: 'Degrees Deep', value: 6, color: '#00ff88' },
186
+ { label: 'Connections Mapped', value: SAMPLE_STATS.connections, color: '#3498DB' },
187
+ { label: 'Bridges Discovered', value: SAMPLE_STATS.bridges, color: '#FFD700' },
188
+ { label: 'People Scored', value: SAMPLE_STATS.people, color: '#9B59B6' },
189
+ { label: 'Companies', value: SAMPLE_STATS.companies, color: '#00ff88' },
187
190
  ];
188
191
  return (
189
192
  <section ref={ref} style={{ padding: '80px 24px', borderTop: '1px solid rgba(255,255,255,0.05)', borderBottom: '1px solid rgba(255,255,255,0.05)' }}>
@@ -196,12 +199,14 @@ function StatsBar() {
196
199
  }}>
197
200
  <div style={{ fontSize: 48, fontWeight: 800, color: s.color, lineHeight: 1 }}>
198
201
  <Counter end={s.value} active={inView} />
199
- {s.value > 100 ? '+' : ''}
200
202
  </div>
201
203
  <div style={{ fontSize: 13, color: '#666', marginTop: 8, fontWeight: 500, letterSpacing: 0.5 }}>{s.label}</div>
202
204
  </div>
203
205
  ))}
204
206
  </div>
207
+ <p style={{ textAlign: 'center', fontSize: 12, color: '#555', margin: '32px auto 0', maxWidth: 520 }}>
208
+ Counted from the sample network that comes with the app. Every person in it is invented.
209
+ </p>
205
210
  </section>
206
211
  );
207
212
  }
@@ -315,9 +320,10 @@ function GalaxySection() {
315
320
  function ChainSection() {
316
321
  const [ref, inView] = useInView();
317
322
  const degrees = [
318
- { d: 1, label: 'Your Connections', desc: 'Direct network — scored & tiered', color: '#3498DB', count: 575 },
319
- { d: 2, label: 'Bridge Connections', desc: 'Friends of your bridges', color: '#9B59B6', count: 1519 },
320
- { d: 3, label: 'Extended Reach', desc: 'Bridged from promoted D2s', color: '#FFD700', count: 344 },
323
+ // The sample's counts; it maps two degrees.
324
+ { d: 1, label: 'Your Connections', desc: 'Direct network — scored & tiered', color: '#3498DB', count: SAMPLE_STATS.degree1 },
325
+ { d: 2, label: 'Bridge Connections', desc: 'Friends of your bridges', color: '#9B59B6', count: SAMPLE_STATS.degree2 },
326
+ { d: 3, label: 'Extended Reach', desc: 'Bridged from promoted D2s', color: '#FFD700', count: null },
321
327
  { d: 4, label: 'Industry Layer', desc: 'Company & sector intelligence', color: '#FF6B35', count: null },
322
328
  { d: 5, label: 'Market Layer', desc: 'Cross-industry connections', color: '#00ff88', count: null },
323
329
  { d: 6, label: 'Global Reach', desc: 'Anyone in the world', color: '#ff5050', count: null },
@@ -396,6 +402,9 @@ function ChainSection() {
396
402
  </div>
397
403
  ))}
398
404
  </div>
405
+ <p style={{ textAlign: 'center', fontSize: 12, color: '#555', marginTop: 40 }}>
406
+ The counts are the sample network&rsquo;s, whose people are all invented.
407
+ </p>
399
408
  </div>
400
409
  </section>
401
410
  );
@@ -407,7 +416,7 @@ function ChainSection() {
407
416
  function ScoringSection() {
408
417
  const [ref, inView] = useInView();
409
418
  const tiers = [
410
- { tier: 'S', label: 'Supreme', score: '7.0+', color: TIER.S, glow: 'rgba(255,215,0,0.3)', people: 'C-Suite, VPs, Founders', icon: '👑' },
419
+ { tier: 'S', label: 'Supreme', score: '7.5+', color: TIER.S, glow: 'rgba(255,215,0,0.3)', people: 'C-Suite, VPs, Founders', icon: '👑' },
411
420
  { tier: 'A', label: 'Ace', score: '5.5+', color: TIER.A, glow: 'rgba(155,89,182,0.3)', people: 'Directors, Senior Leaders', icon: '💎' },
412
421
  { tier: 'B', label: 'Builder', score: '4.0+', color: TIER.B, glow: 'rgba(52,152,219,0.3)', people: 'Managers, Senior ICs', icon: '🔷' },
413
422
  { tier: 'C', label: 'Connector', score: '2.5+', color: TIER.C, glow: 'rgba(149,165,166,0.2)', people: 'Associates, Specialists', icon: '🔸' },
@@ -479,10 +488,10 @@ function FeaturesGrid() {
479
488
  {
480
489
  title: 'Paths',
481
490
  subtitle: 'Company Intelligence',
482
- desc: 'Scan any company on LinkedIn and see every person mapped, scored, and organized by seniority. 80+ company normalizations built in.',
491
+ desc: 'Scan any company on LinkedIn and see every person mapped, scored, and organized by seniority.',
483
492
  color: '#00ff88',
484
493
  icon: '🏢',
485
- stat: '344 people scanned',
494
+ stat: `${SAMPLE_STATS.companies} companies in the sample`,
486
495
  },
487
496
  {
488
497
  title: 'Outlink',
@@ -490,7 +499,7 @@ function FeaturesGrid() {
490
499
  desc: 'Your curated list of high-value D2 connections to request. Grouped by bridge, filtered by tier, with batch-open for efficient networking.',
491
500
  color: '#FF6B35',
492
501
  icon: '🚀',
493
- stat: '798 recommendations',
502
+ stat: `${SAMPLE_STATS.recommendations} recommendations in the sample`,
494
503
  },
495
504
  {
496
505
  title: 'XP System',
@@ -506,7 +515,7 @@ function FeaturesGrid() {
506
515
  desc: 'Select any D1 connection as a bridge. Automatically discover and score all their connections — your D2 layer.',
507
516
  color: '#9B59B6',
508
517
  icon: '🔗',
509
- stat: '25 bridges mapped',
518
+ stat: `${SAMPLE_STATS.bridges} bridges in the sample`,
510
519
  },
511
520
  ];
512
521
 
@@ -599,13 +608,14 @@ function TechSection() {
599
608
  background: GRADIENT, WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent',
600
609
  marginBottom: 32,
601
610
  }}>
602
- P = (S &times; 0.5) + (C &times; 0.3) + B
611
+ P = T &times; (0.45 + 0.055 &times; C) + R + B
603
612
  </div>
604
613
  <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 24 }}>
605
614
  {[
606
- { sym: 'S', label: 'Seniority', desc: 'VP = 8, Director = 6, Manager = 4', weight: '50%', color: TIER.S },
607
- { sym: 'C', label: 'Company Prestige', desc: 'FAANG = 9, Fortune 500 = 7', weight: '30%', color: TIER.A },
608
- { sym: 'B', label: 'Circle Bonus', desc: 'Inner circle proximity boost', weight: '20%', color: TIER.B },
615
+ // The model in lib/scoring.js: a product, so a title counts for more at a bigger company.
616
+ { sym: 'T', label: 'Title', desc: 'C-suite 10, VP 9, Director 7.5, Manager 6.5', note: 'Multiplied by the company', color: TIER.S },
617
+ { sym: 'C', label: 'Company', desc: 'Well-known 7–10, else estimated from your network', note: 'Weight 0.5 to 1.0', color: TIER.A },
618
+ { sym: 'R + B', label: 'Reach & bridge', desc: 'Investor, YC, an audience in the millions; a strong circle', note: 'Up to +1.5 and +1', color: TIER.B },
609
619
  ].map((item, i) => (
610
620
  <div key={i} style={{
611
621
  padding: 16, borderRadius: 12, background: `${item.color}08`,
@@ -615,7 +625,7 @@ function TechSection() {
615
625
  <div style={{ fontSize: 28, fontWeight: 900, color: item.color }}>{item.sym}</div>
616
626
  <div style={{ fontSize: 13, fontWeight: 700, color: '#fff', marginTop: 4 }}>{item.label}</div>
617
627
  <div style={{ fontSize: 10, color: '#555', marginTop: 4 }}>{item.desc}</div>
618
- <div style={{ fontSize: 10, color: item.color, fontWeight: 700, marginTop: 8 }}>Weight: {item.weight}</div>
628
+ <div style={{ fontSize: 10, color: item.color, fontWeight: 700, marginTop: 8 }}>{item.note}</div>
619
629
  </div>
620
630
  ))}
621
631
  </div>
@@ -627,7 +637,7 @@ function TechSection() {
627
637
  opacity: inView ? 1 : 0, transition: 'opacity 1s ease 0.6s',
628
638
  }}>
629
639
  {[
630
- { t: 'S', min: 7, color: TIER.S },
640
+ { t: 'S', min: 7.5, color: TIER.S },
631
641
  { t: 'A', min: 5.5, color: TIER.A },
632
642
  { t: 'B', min: 4, color: TIER.B },
633
643
  { t: 'C', min: 2.5, color: TIER.C },
@@ -751,7 +761,7 @@ function CTASection() {
751
761
  opacity: inView ? 0.4 : 0, transition: 'opacity 1.5s ease 0.5s',
752
762
  }}>
753
763
  <span style={{ fontSize: 12, color: '#444' }}>Built by Blake Burford</span>
754
- <span style={{ fontSize: 12, color: '#444' }}>Stead Labs</span>
764
+ <span style={{ fontSize: 12, color: '#444' }}>Open source · MIT</span>
755
765
  <span style={{ fontSize: 12, color: '#444' }}>2026</span>
756
766
  </div>
757
767
  </div>
@@ -240,6 +240,19 @@ function HomeInner() {
240
240
  Scan
241
241
  </Link>}
242
242
  </div>
243
+ {/* Settings — also in CSV/sample mode and on phones, so updates stay reachable */}
244
+ {!IS_DEMO && <Link
245
+ href="/settings"
246
+ title="Settings"
247
+ aria-label="Settings"
248
+ style={{
249
+ width: isMobile ? 28 : 32, height: isMobile ? 28 : 32, borderRadius: '50%', flexShrink: 0,
250
+ background: 'rgba(255,255,255,0.06)', color: '#888', fontSize: isMobile ? 14 : 16, textDecoration: 'none',
251
+ display: 'flex', alignItems: 'center', justifyContent: 'center', marginLeft: isMobile ? 4 : 8,
252
+ }}
253
+ >
254
+ {'\u2699\uFE0E'}
255
+ </Link>}
243
256
  {/* Notification bell */}
244
257
  {!IS_DEMO && !csvMode && <div style={{ position: 'relative', marginLeft: isMobile ? 4 : 8 }}>
245
258
  <button
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
 
3
- import { useEffect, useState } from 'react';
3
+ import { Suspense, useEffect, useState } from 'react';
4
+ import { useSearchParams } from 'next/navigation';
4
5
  import { runScrape, scraperStatus, notReadyMessage } from '../../lib/scraper-client';
5
6
  import { loadNetwork } from '../../lib/network';
6
7
  import { IS_DEMO } from '../../lib/demo';
@@ -13,9 +14,12 @@ import Link from 'next/link';
13
14
  import { companyOf, getSeniority } from '../../lib/companies';
14
15
 
15
16
  const TIER_COLORS = { S: '#FFD700', A: '#9B59B6', B: '#3498DB', C: '#95A5A6', D: '#BDC3C7' };
17
+ const TABS = [['map', 'Map'], ['industries', 'Industries'], ['companies', 'Companies'], ['scores', 'Scores']];
16
18
 
17
19
  export default function PathsPage() {
18
- return <OnboardingGate><PathsInner /></OnboardingGate>;
20
+ // Suspense because PathsInner reads the address's ?tab= (useSearchParams),
21
+ // which Next requires to sit inside one for the page to build.
22
+ return <OnboardingGate><Suspense><PathsInner /></Suspense></OnboardingGate>;
19
23
  }
20
24
 
21
25
  function PathsInner() {
@@ -28,7 +32,11 @@ function PathsInner() {
28
32
  const [d2Data, setD2Data] = useState([]);
29
33
  const [d3Data, setD3Data] = useState([]);
30
34
  // Map and Industries are the analyzer; Companies is the list it grew from.
31
- const [tab, setTab] = useState('map');
35
+ // A link can open a tab (/paths?tab=scores, from Settings → Your sector).
36
+ // The router's search params rather than window.location: on a click from
37
+ // another page the address bar only changes after this page has rendered.
38
+ const asked = useSearchParams().get('tab');
39
+ const [tab, setTab] = useState(() => (TABS.some(([k]) => k === asked) ? asked : 'map'));
32
40
  // Bumped when company scores change, so the network reloads with new tiers.
33
41
  const [reloadKey, setReloadKey] = useState(0);
34
42
 
@@ -229,7 +237,7 @@ function PathsInner() {
229
237
  }}>Paths</h1>
230
238
  {!selectedCompany && (
231
239
  <div style={{ display: 'flex', gap: 4, marginLeft: 8, padding: 3, borderRadius: 8, background: 'rgba(255,255,255,0.05)' }}>
232
- {[['map', 'Map'], ['industries', 'Industries'], ['companies', 'Companies'], ['scores', 'Scores']].map(([k, label]) => (
240
+ {TABS.map(([k, label]) => (
233
241
  <button key={k} onClick={() => setTab(k)} style={{
234
242
  padding: '5px 12px', borderRadius: 6, border: 'none', cursor: 'pointer', fontSize: 12.5, fontWeight: 700,
235
243
  background: tab === k ? 'linear-gradient(135deg, #00ff88, #3498DB)' : 'transparent', color: tab === k ? '#000' : '#aab',
@@ -6,6 +6,7 @@ import MappingProgress from '../components/MappingProgress';
6
6
  import { IS_DEMO } from '../../lib/demo';
7
7
  import OnboardingGate from '../components/OnboardingGate';
8
8
  import { useUser } from '../components/UserProvider';
9
+ import { sectorByKey } from '../../lib/sector-labels';
9
10
  import Link from 'next/link';
10
11
 
11
12
  const LEVEL_NAMES = {
@@ -32,11 +33,20 @@ function ProfileInner() {
32
33
  const [notifications, setNotifications] = useState([]);
33
34
  const [queueStats, setQueueStats] = useState({ total: 0, sent: 0, accepted: 0 });
34
35
  const [mapping, setMapping] = useState({ degree1: [], degree2: [], skips: [] });
36
+ // "Your Sectors" is what you picked in Settings → Your sector. (users.sectors,
37
+ // which this card used to show, is never written by anything; the Sidebar
38
+ // and Outlink still read it as free text.) null while it loads; a load that
39
+ // fails says so rather than showing "none picked" (TRAPS §7).
40
+ const [sectorFocus, setSectorFocus] = useState(null);
35
41
 
36
42
  useEffect(() => {
37
43
  if (IS_DEMO) return;
38
44
  if (!userId) return;
39
45
  async function load() {
46
+ fetch('/api/settings')
47
+ .then((r) => r.json().then((d) => (r.ok && d.settings ? d : Promise.reject(new Error(d.error)))))
48
+ .then((d) => setSectorFocus(d.settings.sectorFocus || { sectors: [], strength: 'lean' }))
49
+ .catch(() => setSectorFocus({ failed: true }));
40
50
  const net = await loadNetwork(userId);
41
51
  const d1 = net.degree1;
42
52
  const d2 = net.degree2;
@@ -364,15 +374,38 @@ function ProfileInner() {
364
374
  background: 'rgba(255,255,255,0.04)', borderRadius: 12, padding: 20,
365
375
  border: '1px solid rgba(255,255,255,0.08)',
366
376
  }}>
367
- <h3 style={{ fontSize: 14, fontWeight: 700, marginTop: 0, marginBottom: 12 }}>Your Sectors</h3>
368
- <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
369
- {profile.sectors.map((s, i) => (
370
- <span key={i} style={{
371
- padding: '4px 12px', borderRadius: 20, fontSize: 11, fontWeight: 600,
372
- background: 'rgba(52,152,219,0.15)', border: '1px solid rgba(52,152,219,0.3)', color: '#3498DB',
373
- }}>{s}</span>
374
- ))}
377
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
378
+ <h3 style={{ fontSize: 14, fontWeight: 700, margin: 0 }}>Your Sectors</h3>
379
+ <Link href="/settings#sector" style={{ fontSize: 11, color: '#3498DB', textDecoration: 'none', fontWeight: 600 }}>
380
+ {sectorFocus?.sectors?.length ? 'Change' : sectorFocus && !sectorFocus.failed ? 'Pick in Settings' : 'Settings'} &rarr;
381
+ </Link>
375
382
  </div>
383
+ {!sectorFocus ? (
384
+ <div style={{ fontSize: 12, color: '#888' }}>Loading…</div>
385
+ ) : sectorFocus.failed ? (
386
+ <div style={{ fontSize: 12, color: '#ff7676' }}>
387
+ Couldn&rsquo;t load your sectors. Reload this page, or open Settings to see them.
388
+ </div>
389
+ ) : sectorFocus.sectors?.length ? (
390
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, alignItems: 'center' }}>
391
+ {sectorFocus.sectors.map((key) => {
392
+ const ind = sectorByKey(key);
393
+ return (
394
+ <span key={key} style={{
395
+ padding: '4px 12px', borderRadius: 20, fontSize: 11, fontWeight: 600,
396
+ background: `${ind.color}26`, border: `1px solid ${ind.color}66`, color: ind.color,
397
+ }}>{ind.label}</span>
398
+ );
399
+ })}
400
+ <span style={{ fontSize: 11, color: '#888' }}>
401
+ {sectorFocus.strength === 'strong' ? 'Strong' : 'Lean'}: companies here count for more in your scores.
402
+ </span>
403
+ </div>
404
+ ) : (
405
+ <div style={{ fontSize: 12, color: '#888' }}>
406
+ None picked. Pick up to three in Settings and companies in them count for more in your scores.
407
+ </div>
408
+ )}
376
409
  </div>
377
410
 
378
411
  </div>
@@ -6,15 +6,21 @@ import { IS_DEMO } from '../../lib/demo';
6
6
  import OutlinkQuest from '../components/OutlinkQuest';
7
7
  import OnboardingGate from '../components/OnboardingGate';
8
8
  import { useUser } from '../components/UserProvider';
9
+ import { rowCompanyScore, TOP_COMPANY } from '../../lib/scoring';
9
10
  import Link from 'next/link';
10
11
 
11
12
  const TIER_COLORS = { S: '#FFD700', A: '#9B59B6', B: '#3498DB', C: '#95A5A6', D: '#BDC3C7' };
12
- const PRESTIGE = ['snap', 'google', 'meta', 'apple', 'amazon', 'microsoft', 'netflix', 'tesla', 'spotify', 'tiktok', 'coca-cola', 'nike', 'disney', 'palantir', 'stripe', 'coinbase', 'polymarket', 'pinterest', 'whatnot', 'blackrock', 'anduril'];
13
13
 
14
+ // Who to reach first: power, +1 when the company their score is built on is a
15
+ // top one by the model's own scores (TOP_COMPANY: the curated list's major
16
+ // companies and up, or one you or your sector score that high), a nudge for
17
+ // the free-text sectors on your profile, then a lift for S and A. The +1 used
18
+ // to come from a list of one person's favourite names, matched anywhere in the
19
+ // headline, once per name: "Metadata" counted as Meta, "Ex-Google" as Google.
14
20
  function calculatePriority(person, sectors) {
15
21
  let score = parseFloat(person.power_score) || 0;
16
22
  const hl = (person.headline || '').toLowerCase();
17
- PRESTIGE.forEach(c => { if (hl.includes(c)) score += 1; });
23
+ if (rowCompanyScore(person) >= TOP_COMPANY) score += 1;
18
24
  (sectors || []).forEach(s => { if (hl.includes(s.toLowerCase())) score += 0.5; });
19
25
  if (person.tier === 'S') score *= 1.5;
20
26
  else if (person.tier === 'A') score *= 1.2;
@@ -0,0 +1,96 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useState } from 'react';
4
+ import Link from 'next/link';
5
+ import OnboardingGate from '../components/OnboardingGate';
6
+ import UpdatePanel from '../components/UpdatePanel';
7
+ import SectorSection from '../components/settings/SectorSection';
8
+ import DataSection from '../components/settings/DataSection';
9
+ import { Section, Body, Mono, LINE, FONT } from '../components/ui';
10
+ import { IS_DEMO } from '../../lib/demo';
11
+
12
+ // Settings: one page for the choices that shape how the app treats your data,
13
+ // and the facts about this copy. Each feature adds its own <Section>; what the
14
+ // user chooses is saved in the database (lib/settings.js), so it travels with
15
+ // their data.
16
+
17
+ export default function SettingsPage() {
18
+ return <OnboardingGate><SettingsInner /></OnboardingGate>;
19
+ }
20
+
21
+ const KIND_LABEL = {
22
+ 'mac-app': 'the Mac app',
23
+ npm: 'the npm package (npx six-degrees)',
24
+ source: 'a copy built from the source code',
25
+ git: 'a git checkout of the source code',
26
+ };
27
+
28
+ function SettingsInner() {
29
+ const [info, setInfo] = useState(null);
30
+ const [error, setError] = useState(null);
31
+
32
+ useEffect(() => {
33
+ fetch('/api/settings')
34
+ .then((r) => r.json().then((d) => (r.ok ? d : Promise.reject(new Error(d.error || 'Could not load settings.')))))
35
+ .then(setInfo)
36
+ .catch((e) => setError(e.message));
37
+ }, []);
38
+
39
+ if (IS_DEMO) {
40
+ return (
41
+ <div style={{
42
+ minHeight: '100vh', background: '#0a0a1a', color: 'rgba(255,255,255,0.7)',
43
+ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
44
+ gap: 12, textAlign: 'center', padding: 24, fontFamily: FONT,
45
+ }}>
46
+ <h2 style={{ margin: 0, fontSize: 20, fontWeight: 700, color: '#fff' }}>Not part of the demo</h2>
47
+ <p style={{ margin: 0, fontSize: 13 }}>The public demo includes the Network Circle and Degrees views only.</p>
48
+ <Link href="/" style={{ fontSize: 12, color: 'rgba(255,255,255,0.5)', textDecoration: 'none' }}>&larr; Back to the network</Link>
49
+ </div>
50
+ );
51
+ }
52
+
53
+ const about = info?.about;
54
+
55
+ return (
56
+ <div style={{ minHeight: '100vh', background: '#0a0a1a', color: '#fff', fontFamily: FONT }}>
57
+ <header style={{ padding: '16px 24px', borderBottom: LINE, display: 'flex', alignItems: 'center', gap: 16 }}>
58
+ <Link href="/" style={{
59
+ display: 'flex', alignItems: 'center', gap: 6, color: '#888', textDecoration: 'none',
60
+ fontSize: 13, fontWeight: 600, padding: '6px 14px', borderRadius: 6,
61
+ background: 'rgba(255,255,255,0.06)', border: LINE,
62
+ }}>← Back to Map</Link>
63
+ <h1 style={{
64
+ fontSize: 22, fontWeight: 700, margin: 0,
65
+ background: 'linear-gradient(135deg, #FFD700, #9B59B6, #3498DB)',
66
+ WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent',
67
+ }}>Settings</h1>
68
+ </header>
69
+
70
+ <main style={{ maxWidth: 720, margin: '0 auto', padding: '8px 24px 64px' }}>
71
+ {error && <Body style={{ color: '#ff7676', marginTop: 16 }}>{error}</Body>}
72
+
73
+ <UpdatePanel />
74
+ <SectorSection />
75
+
76
+ <DataSection />
77
+
78
+ <Section id="about" title="About this copy">
79
+ {about ? (
80
+ <>
81
+ <Body>Version <Mono>{about.version}</Mono>, running as {KIND_LABEL[about.kind] || about.kind}.</Body>
82
+ <Body>
83
+ Your network is kept in <Mono>{about.dataDir}</Mono>
84
+ {about.customDataDir ? ' (a folder you chose).' : '.'}
85
+ {about.kind === 'mac-app' && ' Help → Show the Data Folder opens it.'}
86
+ </Body>
87
+ <Body style={{ fontSize: 12, color: '#667', marginTop: 10 }}>
88
+ Settings are saved with your network, on this computer. Nothing here is sent anywhere.
89
+ </Body>
90
+ </>
91
+ ) : !error && <Body>Loading…</Body>}
92
+ </Section>
93
+ </main>
94
+ </div>
95
+ );
96
+ }
@@ -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
@@ -16,6 +16,7 @@ const LINE = '1px solid rgba(255,255,255,0.1)';
16
16
 
17
17
  const ACTION_LABELS = {
18
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;
@@ -202,22 +213,23 @@ function SetupInner() {
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 scanner 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
 
@@ -106,9 +94,15 @@ async function main() {
106
94
  return;
107
95
  }
108
96
 
97
+ if (args.error) {
98
+ console.error(`\n ${args.error}\n`);
99
+ process.exit(1);
100
+ }
101
+
109
102
  checkNode();
110
103
 
111
- 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);
112
106
  if (!existsSync(dataDir)) mkdirSync(dataDir, { recursive: true });
113
107
 
114
108
  const server = path.join(ROOT, '.next', 'standalone', 'server.js');