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
@@ -6,8 +6,9 @@
6
6
  //
7
7
  // They belong to the LinkedIn account, not to a profile in the app. TRAPS §35.
8
8
 
9
- import { readFileSync, writeFileSync, renameSync, unlinkSync, existsSync } from 'node:fs';
9
+ import { readFileSync, writeFileSync, renameSync, unlinkSync, existsSync, lstatSync } from 'node:fs';
10
10
  import path from 'node:path';
11
+ import { durable } from './durable.js';
11
12
 
12
13
  export const DEFAULT_LIMITS = { daily: 50, monthly: 250 };
13
14
  export const DAILY_CHOICES = [25, 50, 100, 200, 500];
@@ -116,3 +117,125 @@ export function linkedinState(dir, now = Date.now()) {
116
117
  cooldown: readCooldown(dir, now),
117
118
  };
118
119
  }
120
+
121
+ // ── another computer's budget (Settings → Your data → Import) ───────────────
122
+ // An import carries these three files from the other computer. They describe
123
+ // the same LinkedIn account, so they are merged with the ones here, never put
124
+ // in their place: replacing them would forget the searches made here (and lift
125
+ // a cooldown nobody chose to lift), and the account would be asked for more
126
+ // than its budget (TRAPS §35).
127
+
128
+ const ACTIVITY = 'linkedin-activity.json';
129
+ const COOLDOWN = 'linkedin-cooldown.json';
130
+ const LIMITS = 'scan-limits.json';
131
+
132
+ const isObject = (v) => Boolean(v) && typeof v === 'object' && !Array.isArray(v);
133
+ const isTimeList = (v) => v === undefined
134
+ || (Array.isArray(v) && v.every((t) => typeof t === 'number' && Number.isFinite(t) && t >= 0));
135
+ const isTime = (v) => typeof v === 'number' && Number.isFinite(v) && v >= 0;
136
+
137
+ /**
138
+ * Why one of these files from another computer can't be used here, in words
139
+ * for the page, or null when it can. The limits follow writeLimits: only the
140
+ * menu's own choices. A value the app never offers is refused rather than
141
+ * passed to the scanner, which reads a daily limit of 0 as "no limit at all".
142
+ */
143
+ export function budgetFileProblem(name, data) {
144
+ if (!isObject(data)) return 'it is not a JSON object';
145
+ if (name === ACTIVITY) {
146
+ if (!isTimeList(data.searches) || !isTimeList(data.profiles)) return 'its record of searches is not a list of times';
147
+ } else if (name === COOLDOWN) {
148
+ if (!isTime(data.until)) return 'its pause has no end time';
149
+ if (data.reason !== undefined && typeof data.reason !== 'string') return 'its pause has a reason that is not text';
150
+ if (data.set_at !== undefined && !isTime(data.set_at)) return 'its pause has a start time that is not a time';
151
+ } else if (name === LIMITS) {
152
+ if (data.daily !== undefined && !DAILY_CHOICES.includes(data.daily)) {
153
+ return `its daily limit (${String(data.daily).slice(0, 20)}) is not one Six Degrees offers`;
154
+ }
155
+ if (data.monthly !== undefined && !MONTHLY_CHOICES.includes(data.monthly)) {
156
+ return `its monthly limit (${String(data.monthly).slice(0, 20)}) is not one Six Degrees offers`;
157
+ }
158
+ }
159
+ return null;
160
+ }
161
+
162
+ /**
163
+ * Both lists of times, each time kept as many times as the list that has it
164
+ * most often. Not a plain union, and not a de-duplication: the scanner writes
165
+ * one time n times when a single click cost n searches (charge_linkedin), and
166
+ * those are n searches; and a history both computers already share (one was
167
+ * imported from the other before) must still count once, not twice.
168
+ */
169
+ export function mergeTimes(mine = [], theirs = []) {
170
+ const counts = (list) => list.reduce((m, t) => m.set(t, (m.get(t) || 0) + 1), new Map());
171
+ const merged = counts(mine);
172
+ for (const [t, n] of counts(theirs)) if (n > (merged.get(t) || 0)) merged.set(t, n);
173
+ return [...merged].sort((a, b) => a[0] - b[0]).flatMap(([t, n]) => Array(n).fill(t));
174
+ }
175
+
176
+ /** The scanner's own reading of a record: every entry a number (float() in scrape.py). */
177
+ function readableTimes(v) {
178
+ if (v === undefined) return [];
179
+ if (!Array.isArray(v)) return null;
180
+ const out = v.map(Number);
181
+ return out.every(Number.isFinite) ? out : null;
182
+ }
183
+
184
+ const hasFile = (p) => {
185
+ try { lstatSync(p); return true; } catch { return false; }
186
+ };
187
+
188
+ /**
189
+ * Merge the budget files in `from` (an import's, already checked with
190
+ * budgetFileProblem) into the data folder `dir`:
191
+ * linkedin-activity.json both computers' searches and profile views (mergeTimes)
192
+ * linkedin-cooldown.json whichever pause ends later
193
+ * scan-limits.json this computer's, if it has one; the copy's otherwise.
194
+ * The limits are a choice someone made here, and an
195
+ * import never quietly changes it.
196
+ * A record here that can't be read is left as it is: the scanner reads it as
197
+ * "today's searches are used up" (scrape.py _read_activity), which is the safe
198
+ * way round. Running it twice gives the same files as running it once, so a
199
+ * start that stops part-way can simply do it again.
200
+ */
201
+ export function mergeBudgetFiles({ dir, from }) {
202
+ const here = (name) => path.join(dir, name);
203
+ const theirs = (name) => {
204
+ const data = readJson(path.join(from, name));
205
+ return isObject(data) && !budgetFileProblem(name, data) ? data : null;
206
+ };
207
+
208
+ const activity = theirs(ACTIVITY);
209
+ if (activity) {
210
+ const mine = hasFile(here(ACTIVITY)) ? readJson(here(ACTIVITY)) : {};
211
+ const searches = isObject(mine) ? readableTimes(mine.searches) : null;
212
+ const profiles = isObject(mine) ? readableTimes(mine.profiles) : null;
213
+ if (searches && profiles) {
214
+ durable.writeJsonDurably(here(ACTIVITY), {
215
+ searches: mergeTimes(searches, activity.searches),
216
+ profiles: mergeTimes(profiles, activity.profiles),
217
+ });
218
+ }
219
+ }
220
+
221
+ const cooldown = theirs(COOLDOWN);
222
+ if (cooldown) {
223
+ const mine = readJson(here(COOLDOWN));
224
+ const mineEnds = Number.isFinite(Number(mine?.until)) ? Number(mine.until) : -Infinity;
225
+ if (cooldown.until > mineEnds) {
226
+ durable.writeJsonDurably(here(COOLDOWN), {
227
+ until: cooldown.until,
228
+ reason: cooldown.reason ?? 'LinkedIn pushed back',
229
+ set_at: cooldown.set_at ?? null,
230
+ });
231
+ }
232
+ }
233
+
234
+ const limits = theirs(LIMITS);
235
+ if (limits && !hasFile(here(LIMITS))) {
236
+ durable.writeJsonDurably(here(LIMITS), {
237
+ daily: limits.daily ?? DEFAULT_LIMITS.daily,
238
+ monthly: limits.monthly ?? DEFAULT_LIMITS.monthly,
239
+ });
240
+ }
241
+ }
package/lib/rpc.js CHANGED
@@ -1,52 +1,160 @@
1
- import { getDb, nowIso } from './db-client.js';
1
+ import { createHash } from 'node:crypto';
2
+ import { getDb, newId, nowIso } from './db-client.js';
2
3
 
3
4
  // Replacements for the stored procedures the hosted database used to provide.
4
5
  // Scoring lives in lib/scoring.js; this file only reads rows and writes the
5
- // results back. (scripts/*.sql are the retired hosted-era model.)
6
+ // results back. rpc('score_new_connections') is that procedure's name, kept
7
+ // for the routes that call it; it rescores with lib/scoring.js like the rest.
6
8
 
7
- import { scoreNetwork, explainScore, SCORING_VERSION } from './scoring.js';
8
- import { industryOf } from './companies.js';
9
+ import { readNetwork, scoreNetwork, explainScore, SCORING_VERSION, KNOWN_COMPANIES, RULE_TABLES } from './scoring.js';
10
+ import { industryKeyOf, INDUSTRIES } from './companies.js';
11
+ import { readSettings } from './settings.js';
12
+ import { SECTOR_FOCUS_SETTING, focusFingerprint, previewSectorFocus } from './sector-focus.js';
13
+ import { LEGACY_OFFER_KEY } from './legacy-scores.js';
14
+ import { sectorMatcher, sectorGroup, sectorLabel } from './sector-directory.js';
15
+
16
+ // The word lists and rules the stored scores were computed with: a fingerprint
17
+ // of every entry on the curated company list (name, score, alias, industry),
18
+ // of the broad industries' words and labels (lib/companies.js INDUSTRIES), and
19
+ // of every rule table scoring reads headlines and names with (lib/scoring.js
20
+ // RULE_TABLES: titles, students and clubs, what isn't a company, the reach
21
+ // bonuses), stamped beside them in app_meta 'scoring_list'. The industries'
22
+ // words decide a company's one industry, which decides whether it is a school
23
+ // (no estimate) and whether a broad pick in Settings leans it; their labels
24
+ // are in the stored working ("4 + 1 your sector: Healthcare & Biotech").
25
+ // Editing any of them makes stored scores stale, as a new SCORING_VERSION
26
+ // does, with no number to remember to bump. Copies from before the list was
27
+ // made neutral stamped none, which is also how rescoreAll() knows to offer
28
+ // keeping their old scores (lib/legacy-offer.js).
29
+ export function scoringStamp({ known = KNOWN_COMPANIES, industries = INDUSTRIES, rules = RULE_TABLES } = {}) {
30
+ // JSON has no patterns or sets: a pattern counts by its source and flags, a set by its members.
31
+ const plain = (key, value) => (value instanceof RegExp ? String(value) : value instanceof Set ? [...value] : value);
32
+ return createHash('sha256')
33
+ .update(JSON.stringify([
34
+ known.map(([name, score, alias, industry]) => [name, score, String(alias), industry]),
35
+ industries.map(({ key, label, words }) => [key, label, String(words)]),
36
+ rules,
37
+ ], plain))
38
+ .digest('hex').slice(0, 16);
39
+ }
40
+
41
+ export const KNOWN_LIST_STAMP = scoringStamp();
9
42
 
10
43
  export function companyOverrides(db = getDb()) {
11
44
  return new Map(db.prepare('SELECT name, score FROM company_scores').all().map((r) => [r.name, r.score]));
12
45
  }
13
46
 
47
+ /**
48
+ * Set company scores as your own ([[name, score], …]), the way Paths → Scores
49
+ * does: one row per name, replacing any you had. Rescoring is the caller's
50
+ * job, so a batch rescores once.
51
+ */
52
+ export function setCompanyScores(db, entries) {
53
+ const upsert = db.prepare(`INSERT INTO company_scores (id, name, score, updated_at) VALUES (?, ?, ?, ?)
54
+ ON CONFLICT(name) DO UPDATE SET score = excluded.score, updated_at = excluded.updated_at`);
55
+ const now = nowIso();
56
+ for (const [name, score] of entries) upsert.run(newId(), name, score, now);
57
+ }
58
+
59
+ /** The sector focus saved in Settings (lib/sector-focus.js), or none. */
60
+ export function sectorFocusOf(db = getDb()) {
61
+ return readSettings(db, { sectorFocus: SECTOR_FOCUS_SETTING }).sectorFocus;
62
+ }
63
+
64
+ /**
65
+ * What rescoring reads: every row, as scoring needs it. `withPeople` adds each
66
+ * row's name, for naming who a change would move.
67
+ */
68
+ export function scoringRows(db = getDb(), { withPeople = false } = {}) {
69
+ return db.prepare(`SELECT id, degree, headline, role, company, scanned_company, profile_url, source_connection_id${withPeople ? ', name' : ''}
70
+ FROM linkedin_connections`).all();
71
+ }
72
+
73
+ /**
74
+ * Every headline read once, the way scoring reads it: each company's
75
+ * headcount, its one industry, the sector directory's sectors it matches and
76
+ * the industries those sit under. Rescoring, Settings' preview and
77
+ * suggestions, and Paths → Scores all read the rows through this, so they
78
+ * agree on which company is in which sector.
79
+ */
80
+ export function readForScoring(rows) {
81
+ return readNetwork(rows, { industryOf: industryKeyOf, sectorsOf: sectorMatcher(), groupOf: sectorGroup });
82
+ }
83
+
14
84
  /**
15
85
  * Rescore everyone. The score depends on the whole network (how many of your
16
86
  * people work at a company, how strong a bridge's circle is), so after any
17
87
  * ingest or company-score change every row is recomputed — ~0.1s for 4,000.
88
+ * Your company scores and your sector focus are read here, not passed in, so
89
+ * every path that rescores (an import, a company score, Settings, a stale
90
+ * model) applies both.
91
+ *
92
+ * `compareWith` is another sector focus: Settings' save passes the one it
93
+ * replaced. The same rows are then also scored with it, in memory, and the
94
+ * answer says who changed tier between the two, counted by the preview's own
95
+ * function (lib/sector-focus.js), so a save reports what its preview said.
96
+ * That compares two fresh scorings rather than the stored tiers, which can be
97
+ * stale (a save whose rescore failed, a database from another computer).
98
+ * @returns { scored } rows written, plus { people, up, down } when comparing.
18
99
  */
19
- export function rescoreAll() {
100
+ export function rescoreAll({ compareWith } = {}) {
20
101
  const db = getDb();
21
- const rows = db.prepare('SELECT id, degree, headline, role, company, scanned_company, profile_url, source_connection_id FROM linkedin_connections').all();
22
- const { scores } = scoreNetwork(rows, { overrides: companyOverrides(db), industryOf: (c, h) => industryOf(c, h).key });
102
+ const rows = scoringRows(db);
103
+ const overrides = companyOverrides(db);
104
+ const focus = sectorFocusOf(db);
105
+ // Every headline is read once, however many ways the rows are then scored.
106
+ const read = readForScoring(rows);
107
+ const { scores } = scoreNetwork(rows, { overrides, focus, read });
108
+ // Worked out before anything is written, so a failure leaves nothing half done.
109
+ const change = compareWith === undefined ? null
110
+ : previewSectorFocus(rows, { overrides, read, from: compareWith, to: focus, examples: 0 });
23
111
  const update = db.prepare(`UPDATE linkedin_connections SET seniority_score = ?, company_prestige_score = ?, power_score = ?, tier = ?,
24
112
  score_why = ?, circle_power = ?, circle_s_count = ?, circle_a_count = ?, circle_elite_pct = ?, is_catalyst = ?, catalyst_score = ?, updated_at = ?
25
113
  WHERE id = ?`);
26
114
  const now = nowIso();
27
115
  db.exec('BEGIN');
28
116
  try {
117
+ // Stored scores with no list stamp came from a copy whose curated list
118
+ // held one person's picks. The first time they are replaced, Paths →
119
+ // Scores offers once to keep the old ones as your own (lib/legacy-offer.js).
120
+ // A database nothing has scored yet never had them, so it is never offered.
121
+ const listed = db.prepare("SELECT 1 FROM app_meta WHERE key = 'scoring_list'").get();
122
+ if (!listed && db.prepare('SELECT 1 FROM linkedin_connections WHERE tier IS NOT NULL LIMIT 1').get()) {
123
+ db.prepare("INSERT OR IGNORE INTO app_meta (key, value) VALUES (?, 'open')").run(LEGACY_OFFER_KEY);
124
+ }
29
125
  for (const r of rows) {
30
126
  const s = scores.get(r.id);
31
127
  const c = s.circle;
32
- update.run(s.title.points, s.companyScore, s.power, s.tier, explainScore(s, s.boost),
128
+ update.run(s.title.points, s.companyScore, s.power, s.tier, explainScore(s, s.boost, { sectorLabel }),
33
129
  c ? Math.round(c.circlePower * 100) / 100 : 0, c?.sCount || 0, c?.aCount || 0, c ? Math.round(c.elitePct * 100) / 100 : 0,
34
130
  c?.isCatalyst ? 1 : 0, c?.isCatalyst ? c.sCount + c.aCount : 0, now, r.id);
35
131
  }
36
- db.prepare('INSERT INTO app_meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value').run('scoring_version', String(SCORING_VERSION));
132
+ const meta = db.prepare('INSERT INTO app_meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value');
133
+ meta.run('scoring_version', String(SCORING_VERSION));
134
+ // Which curated list and sector focus these scores were computed with (see rescoreIfStale).
135
+ meta.run('scoring_list', KNOWN_LIST_STAMP);
136
+ meta.run('scoring_focus', focusFingerprint(focus));
37
137
  db.exec('COMMIT');
38
138
  } catch (err) {
39
139
  db.exec('ROLLBACK');
40
140
  throw err;
41
141
  }
42
- return { scored: rows.length };
142
+ return change ? { scored: rows.length, people: change.people, up: change.up, down: change.down } : { scored: rows.length };
43
143
  }
44
144
 
45
- /** Rescore once if the stored scores came from an older scoring model. */
145
+ /**
146
+ * Rescore once if the stored scores came from an older scoring model or
147
+ * curated list, or from a sector focus other than the one saved now: an
148
+ * update, a database restored or brought from another computer, or a Settings
149
+ * save whose rescore never finished.
150
+ */
46
151
  export function rescoreIfStale() {
47
152
  const db = getDb();
48
- const v = db.prepare("SELECT value FROM app_meta WHERE key = 'scoring_version'").get()?.value;
49
- return v === String(SCORING_VERSION) ? { scored: 0 } : rescoreAll();
153
+ const meta = (key) => db.prepare('SELECT value FROM app_meta WHERE key = ?').get(key)?.value;
154
+ const fresh = meta('scoring_version') === String(SCORING_VERSION)
155
+ && meta('scoring_list') === KNOWN_LIST_STAMP
156
+ && meta('scoring_focus') === focusFingerprint(sectorFocusOf(db));
157
+ return fresh ? { scored: 0 } : rescoreAll();
50
158
  }
51
159
 
52
160
  function incrementXp({ amount = 0 } = {}) {
@@ -0,0 +1,16 @@
1
+ // The sample network's own numbers, for the launch page (app/launch/page.js),
2
+ // which shows them rather than anyone's real network. Counted from
3
+ // public/demo-data.json, where every person is invented
4
+ // (scripts/gen-synthetic.mjs); tests/sample-stats.test.mjs counts them again,
5
+ // so regenerating the sample can't leave them stale. They're written here
6
+ // rather than read from the file so the page doesn't download the whole sample
7
+ // to show a few numbers.
8
+ export const SAMPLE_STATS = {
9
+ connections: 873, // rows: the 1st degree and the circles of the bridges
10
+ degree1: 150,
11
+ degree2: 723,
12
+ people: 748, // each person once, however many circles they're in
13
+ bridges: 14, // 1st-degree people whose circle is mapped
14
+ companies: 19, // where people work now, as Paths groups them
15
+ recommendations: 474, // the Queue's list: 2nd-degree S, A and B you aren't connected to
16
+ };
@@ -9,8 +9,13 @@
9
9
  // " 350 / 817 collected" (every fifty people)
10
10
  // " Collected all 817 connections." (the end)
11
11
  // 2nd degree: "[3/10] Some Name (A-tier, score 6.2)" (as each person starts)
12
+ //
13
+ // And one from the app itself (app/api/scraper/route.js setupPlan), while
14
+ // "Set up the scanner" downloads its Python:
15
+ // "Downloading Python 3.12.14: 12.0 of 24.0 MB"
12
16
 
13
17
  const REPORTED = /LinkedIn reports (\d+) connections/;
18
+ const DOWNLOADING = /^Downloading Python [\d.]+: ([\d.]+) of ([\d.]+) MB$/;
14
19
  const COLLECTED = /(\d+)\s*\/\s*(\d+)\s+collected/;
15
20
  const COLLECTED_ALL = /Collected all (\d+) connections/;
16
21
  const BRIDGE_STEP = /\[(\d+)\/(\d+)\]/;
@@ -26,6 +31,14 @@ const SAVING = /^(Collected \d+ connections|Pushing \d+ connections|\s*Sent \d+
26
31
  export function scanProgress(log, action) {
27
32
  if (!Array.isArray(log) || log.length === 0) return null;
28
33
 
34
+ // Only while the download is the step under way: once the log has moved on
35
+ // (unpacking, installing), a bar left at 100% would look stuck.
36
+ if (action === 'setup') {
37
+ const m = String(log[log.length - 1]).match(DOWNLOADING);
38
+ if (!m || !Number(m[2])) return null;
39
+ return { done: Math.min(Number(m[1]), Number(m[2])), total: Number(m[2]), kind: 'download' };
40
+ }
41
+
29
42
  if (action === 'full' || action === 'refresh') {
30
43
  for (let i = log.length - 1; i >= 0; i--) {
31
44
  const line = String(log[i]);
@@ -0,0 +1,53 @@
1
+ // Whether the scanner is running, for routes other than the one that runs it.
2
+ //
3
+ // app/api/scraper/route.js owns the job and its state. It registers that state
4
+ // here, on globalThis, so a route that must not act mid-scan (an import that
5
+ // replaces the database, a restart) can ask without an HTTP call to its own
6
+ // server, and gets the same answer however the bundler splits route modules.
7
+ //
8
+ // The scanner's route runs more than scans: Install, Set up the scanner and
9
+ // the LinkedIn sign-in window take the same slot. A refusal says which one is
10
+ // running (runningNow): "A scan is running" while Install ran sent people
11
+ // looking for a scan that wasn't there.
12
+
13
+ const KEY = Symbol.for('six-degrees.scan-state');
14
+
15
+ /** The scanner's state object: the one already registered in this server, or `initial`. */
16
+ export function registerScanState(initial) {
17
+ if (!globalThis[KEY]) globalThis[KEY] = initial;
18
+ return globalThis[KEY];
19
+ }
20
+
21
+ /** What the scanner's route is running: its action ('full', 'install', 'setup', 'login', …), or null. */
22
+ export function scannerJob() {
23
+ const state = globalThis[KEY];
24
+ if (state?.running !== true) return null;
25
+ return typeof state.action === 'string' && state.action ? state.action : 'scan';
26
+ }
27
+
28
+ /** Is a scan, or the scanner's setup, running in this server? */
29
+ export function scanIsRunning() {
30
+ return scannerJob() !== null;
31
+ }
32
+
33
+ /**
34
+ * What is running, in words that start a refusal: "A scan is running", "The
35
+ * scanner is being set up", … `job` is scannerJob()'s answer; `true` (a caller
36
+ * that only knows something runs) reads as a scan.
37
+ */
38
+ export function runningNow(job) {
39
+ switch (job) {
40
+ case 'install': return 'The scanner\'s packages are being installed';
41
+ case 'setup': return 'The scanner is being set up';
42
+ case 'login': return 'The LinkedIn sign-in window is open';
43
+ default: return 'A scan is running';
44
+ }
45
+ }
46
+
47
+ /**
48
+ * A refusal while the scanner's route runs something: "<what runs>. <then>",
49
+ * or null when nothing runs.
50
+ */
51
+ export function busyRefusal(then, job = scannerJob()) {
52
+ return job ? `${runningNow(job)}. ${then}` : null;
53
+ }