six-degrees 0.7.0 → 1.0.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 (360) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +1 -0
  3. package/.next/standalone/.next/build-manifest.json +3 -3
  4. package/.next/standalone/.next/prerender-manifest.json +32 -4
  5. package/.next/standalone/.next/routes-manifest.json +6 -0
  6. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  7. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  11. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  12. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  13. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  14. package/.next/standalone/.next/server/app/_not-found.rsc +16 -16
  15. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +16 -16
  16. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
  17. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  18. package/.next/standalone/.next/server/app/api/admin-delete/route.js +1 -1
  19. package/.next/standalone/.next/server/app/api/admin-delete/route.js.nft.json +1 -1
  20. package/.next/standalone/.next/server/app/api/admin-update/route.js +1 -1
  21. package/.next/standalone/.next/server/app/api/admin-update/route.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/api/bridges/route.js +1 -1
  23. package/.next/standalone/.next/server/app/api/bridges/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/bulk-import/route.js +1 -1
  25. package/.next/standalone/.next/server/app/api/bulk-import/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/company-scores/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/connections/route.js +1 -1
  29. package/.next/standalone/.next/server/app/api/connections/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/data/backup/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/data/csv/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/data/export/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/data/import/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/data/restart/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/api/data/restore/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/data/reveal/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/api/data/route.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/api/delete-cluster/route.js +1 -1
  39. package/.next/standalone/.next/server/app/api/delete-cluster/route.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/api/ingest/route.js +1 -1
  41. package/.next/standalone/.next/server/app/api/ingest/route.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/api/network/route.js +1 -1
  43. package/.next/standalone/.next/server/app/api/network/route.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/api/notifications/route.js +1 -1
  45. package/.next/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/api/outreach/route.js +3 -3
  47. package/.next/standalone/.next/server/app/api/outreach/route.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/api/queue/route.js +1 -1
  49. package/.next/standalone/.next/server/app/api/queue/route.js.nft.json +1 -1
  50. package/.next/standalone/.next/server/app/api/scraper/route.js +4 -4
  51. package/.next/standalone/.next/server/app/api/scraper/route.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.nft.json +1 -1
  54. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.nft.json +1 -1
  55. package/.next/standalone/.next/server/app/api/setup-profile/route.js +1 -1
  56. package/.next/standalone/.next/server/app/api/setup-profile/route.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/api/social/crm/route.js.nft.json +1 -1
  58. package/.next/standalone/.next/server/app/api/social/messages/route.js.nft.json +1 -1
  59. package/.next/standalone/.next/server/app/api/social/route.js +1 -1
  60. package/.next/standalone/.next/server/app/api/social/route.js.nft.json +1 -1
  61. package/.next/standalone/.next/server/app/api/unlock/route.js +1 -1
  62. package/.next/standalone/.next/server/app/api/unlock/route.js.nft.json +1 -1
  63. package/.next/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  64. package/.next/standalone/.next/server/app/api/update-images/route.js +1 -1
  65. package/.next/standalone/.next/server/app/api/update-images/route.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/api/users/route.js +1 -1
  67. package/.next/standalone/.next/server/app/api/users/route.js.nft.json +1 -1
  68. package/.next/standalone/.next/server/app/avatars/[file]/route.js.nft.json +1 -1
  69. package/.next/standalone/.next/server/app/import/page.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/import/page_client-reference-manifest.js +1 -1
  71. package/.next/standalone/.next/server/app/import.html +1 -1
  72. package/.next/standalone/.next/server/app/import.rsc +18 -18
  73. package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +18 -18
  74. package/.next/standalone/.next/server/app/import.segments/_tree.segment.rsc +2 -2
  75. package/.next/standalone/.next/server/app/import.segments/import/__PAGE__.segment.rsc +16 -16
  76. package/.next/standalone/.next/server/app/index.html +1 -1
  77. package/.next/standalone/.next/server/app/index.rsc +19 -19
  78. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +16 -16
  79. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +19 -19
  80. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  81. package/.next/standalone/.next/server/app/insights/page/app-paths-manifest.json +3 -0
  82. package/.next/standalone/.next/server/app/insights/page/build-manifest.json +20 -0
  83. package/.next/standalone/.next/server/app/insights/page/next-font-manifest.json +11 -0
  84. package/.next/standalone/.next/server/app/insights/page/react-loadable-manifest.json +1 -0
  85. package/.next/standalone/.next/server/app/insights/page/server-reference-manifest.json +4 -0
  86. package/.next/standalone/.next/server/app/insights/page.js +13 -0
  87. package/.next/standalone/.next/server/app/insights/page.js.map +5 -0
  88. package/.next/standalone/.next/server/app/insights/page.js.nft.json +1 -0
  89. package/.next/standalone/.next/server/app/insights/page_client-reference-manifest.js +3 -0
  90. package/.next/standalone/.next/server/app/insights.html +1 -0
  91. package/.next/standalone/.next/server/app/insights.meta +26 -0
  92. package/.next/standalone/.next/server/app/insights.rsc +35 -0
  93. package/.next/standalone/.next/server/app/insights.segments/_full.segment.rsc +35 -0
  94. package/.next/standalone/.next/server/app/insights.segments/_tree.segment.rsc +4 -0
  95. package/.next/standalone/.next/server/app/insights.segments/insights/__PAGE__.segment.rsc +33 -0
  96. package/.next/standalone/.next/server/app/launch/page.js.nft.json +1 -1
  97. package/.next/standalone/.next/server/app/launch/page_client-reference-manifest.js +1 -1
  98. package/.next/standalone/.next/server/app/launch.html +2 -2
  99. package/.next/standalone/.next/server/app/launch.rsc +18 -18
  100. package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +18 -18
  101. package/.next/standalone/.next/server/app/launch.segments/_tree.segment.rsc +2 -2
  102. package/.next/standalone/.next/server/app/launch.segments/launch/__PAGE__.segment.rsc +16 -16
  103. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  104. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  105. package/.next/standalone/.next/server/app/paths/page.js.nft.json +1 -1
  106. package/.next/standalone/.next/server/app/paths/page_client-reference-manifest.js +1 -1
  107. package/.next/standalone/.next/server/app/paths.html +1 -1
  108. package/.next/standalone/.next/server/app/paths.rsc +19 -19
  109. package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +19 -19
  110. package/.next/standalone/.next/server/app/paths.segments/_tree.segment.rsc +2 -2
  111. package/.next/standalone/.next/server/app/paths.segments/paths/__PAGE__.segment.rsc +16 -16
  112. package/.next/standalone/.next/server/app/profile/page.js.nft.json +1 -1
  113. package/.next/standalone/.next/server/app/profile/page_client-reference-manifest.js +1 -1
  114. package/.next/standalone/.next/server/app/profile.html +1 -1
  115. package/.next/standalone/.next/server/app/profile.rsc +19 -19
  116. package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +19 -19
  117. package/.next/standalone/.next/server/app/profile.segments/_tree.segment.rsc +2 -2
  118. package/.next/standalone/.next/server/app/profile.segments/profile/__PAGE__.segment.rsc +16 -16
  119. package/.next/standalone/.next/server/app/queue/page.js.nft.json +1 -1
  120. package/.next/standalone/.next/server/app/queue/page_client-reference-manifest.js +1 -1
  121. package/.next/standalone/.next/server/app/queue.html +1 -1
  122. package/.next/standalone/.next/server/app/queue.rsc +19 -19
  123. package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +19 -19
  124. package/.next/standalone/.next/server/app/queue.segments/_tree.segment.rsc +2 -2
  125. package/.next/standalone/.next/server/app/queue.segments/queue/__PAGE__.segment.rsc +21 -20
  126. package/.next/standalone/.next/server/app/scores/page.js.nft.json +1 -1
  127. package/.next/standalone/.next/server/app/scores/page_client-reference-manifest.js +1 -1
  128. package/.next/standalone/.next/server/app/scores.html +1 -1
  129. package/.next/standalone/.next/server/app/scores.rsc +18 -18
  130. package/.next/standalone/.next/server/app/scores.segments/_full.segment.rsc +18 -18
  131. package/.next/standalone/.next/server/app/scores.segments/_tree.segment.rsc +2 -2
  132. package/.next/standalone/.next/server/app/scores.segments/scores/__PAGE__.segment.rsc +16 -16
  133. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  134. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  135. package/.next/standalone/.next/server/app/settings.html +1 -1
  136. package/.next/standalone/.next/server/app/settings.rsc +19 -19
  137. package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +19 -19
  138. package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  139. package/.next/standalone/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +16 -16
  140. package/.next/standalone/.next/server/app/setup/page.js.nft.json +1 -1
  141. package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  142. package/.next/standalone/.next/server/app/setup.html +1 -1
  143. package/.next/standalone/.next/server/app/setup.rsc +19 -19
  144. package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +19 -19
  145. package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +2 -2
  146. package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +16 -16
  147. package/.next/standalone/.next/server/app/social/page.js.nft.json +1 -1
  148. package/.next/standalone/.next/server/app/social/page_client-reference-manifest.js +1 -1
  149. package/.next/standalone/.next/server/app/social.html +1 -1
  150. package/.next/standalone/.next/server/app/social.rsc +18 -18
  151. package/.next/standalone/.next/server/app/social.segments/_full.segment.rsc +18 -18
  152. package/.next/standalone/.next/server/app/social.segments/_tree.segment.rsc +2 -2
  153. package/.next/standalone/.next/server/app/social.segments/social/__PAGE__.segment.rsc +16 -16
  154. package/.next/standalone/.next/server/app-paths-manifest.json +1 -0
  155. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__063s0x7._.js → [root-of-the-server]__0r-0t-9._.js} +1 -1
  156. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ra6xyg._.js +15 -0
  157. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__20rwfdw._.js → [root-of-the-server]__0rcpjad._.js} +5 -2
  158. package/.next/standalone/.next/server/chunks/_1_fynia._.js +7 -7
  159. package/.next/standalone/.next/server/chunks/_1itd1o_._.js +1 -1
  160. package/.next/standalone/.next/server/chunks/lib_02iz_9q._.js +2 -2
  161. package/.next/standalone/.next/server/chunks/lib_05agvk3._.js +2 -2
  162. package/.next/standalone/.next/server/chunks/lib_0v84u66._.js +2 -2
  163. package/.next/standalone/.next/server/chunks/lib_db-client_0_dch35.js +9 -9
  164. package/.next/standalone/.next/server/chunks/{lib_rpc_0jnfp2e.js → lib_rpc_00nndai.js} +1 -1
  165. package/.next/standalone/.next/server/chunks/{lib_rpc_0b17r6v.js → lib_rpc_03ibb-x.js} +1 -1
  166. package/.next/standalone/.next/server/chunks/{lib_rpc_0doq0t-.js → lib_rpc_03ri3ji.js} +1 -1
  167. package/.next/standalone/.next/server/chunks/{lib_rpc_0fd2rlw.js → lib_rpc_078ce48.js} +1 -1
  168. package/.next/standalone/.next/server/chunks/lib_rpc_0a69mgr.js +3 -0
  169. package/.next/standalone/.next/server/chunks/{lib_rpc_005abye.js → lib_rpc_0cej3t8.js} +1 -1
  170. package/.next/standalone/.next/server/chunks/lib_rpc_0cmh4g6.js +3 -0
  171. package/.next/standalone/.next/server/chunks/lib_rpc_0nx2_pc.js +3 -0
  172. package/.next/standalone/.next/server/chunks/lib_rpc_0r79-w1.js +3 -0
  173. package/.next/standalone/.next/server/chunks/lib_rpc_0yx8ynd.js +3 -0
  174. package/.next/standalone/.next/server/chunks/lib_rpc_12p-o9-.js +3 -0
  175. package/.next/standalone/.next/server/chunks/lib_rpc_1466dnb.js +3 -0
  176. package/.next/standalone/.next/server/chunks/{lib_rpc_0is4qoc.js → lib_rpc_1hjjjr4.js} +1 -1
  177. package/.next/standalone/.next/server/chunks/lib_rpc_1sryxv6.js +3 -0
  178. package/.next/standalone/.next/server/chunks/lib_rpc_1trn-x5.js +3 -0
  179. package/.next/standalone/.next/server/chunks/lib_rpc_1ygu_mv.js +3 -0
  180. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0egamyq._.js +3 -0
  181. package/.next/standalone/.next/server/chunks/ssr/_04am_h8._.js +3 -0
  182. package/.next/standalone/.next/server/chunks/ssr/_07zb7lu._.js +1 -1
  183. package/.next/standalone/.next/server/chunks/ssr/_0_79idq._.js +1 -1
  184. package/.next/standalone/.next/server/chunks/ssr/_0gds903._.js +3 -0
  185. package/.next/standalone/.next/server/chunks/ssr/_0klqt9z._.js +3 -0
  186. package/.next/standalone/.next/server/chunks/ssr/{_1k9qfsk._.js → _14jak5s._.js} +6 -2
  187. package/.next/standalone/.next/server/chunks/ssr/_14nxd3q._.js +1 -1
  188. package/.next/standalone/.next/server/chunks/ssr/_1cj2yog._.js +3 -0
  189. package/.next/standalone/.next/server/chunks/ssr/_1fm1ih_._.js +1 -1
  190. package/.next/standalone/.next/server/chunks/ssr/_1hdqw0-._.js +7 -0
  191. package/.next/standalone/.next/server/chunks/ssr/_1k2nmbw._.js +1 -1
  192. package/.next/standalone/.next/server/chunks/ssr/{_0gy11ar._.js → _1r62six._.js} +6 -2
  193. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_insights_page_actions_0-0tf75.js +3 -0
  194. package/.next/standalone/.next/server/chunks/ssr/app_components_0uuff77._.js +2 -2
  195. package/.next/standalone/.next/server/chunks/ssr/app_components_1j3q-h5._.js +2 -2
  196. package/.next/standalone/.next/server/chunks/ssr/{_01o3i5y._.js → app_components_settings_SectorPicker_1c-29qw.js} +2 -6
  197. package/.next/standalone/.next/server/chunks/ssr/app_components_ui_0pdmz2z.js +3 -0
  198. package/.next/standalone/.next/server/chunks/ssr/app_insights_page_1d_chja.js +3 -0
  199. package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +14 -14
  200. package/.next/standalone/.next/server/chunks/ssr/app_queue_page_0c6znd6.js +3 -3
  201. package/.next/standalone/.next/server/chunks/ssr/app_settings_page_1f8mjj_.js +1 -1
  202. package/.next/standalone/.next/server/chunks/ssr/app_setup_page_1-282zx.js +4 -4
  203. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  204. package/.next/standalone/.next/server/middleware-manifest.json +5 -5
  205. package/.next/standalone/.next/server/next-font-manifest.js +1 -1
  206. package/.next/standalone/.next/server/next-font-manifest.json +4 -0
  207. package/.next/standalone/.next/server/pages/404.html +1 -1
  208. package/.next/standalone/.next/server/pages/500.html +1 -1
  209. package/.next/standalone/.next/server/prefetch-hints.json +14 -0
  210. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  211. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  212. package/.next/standalone/.next/static/chunks/02wnf8dkxegxg.js +34 -0
  213. package/.next/standalone/.next/static/chunks/0hggugbh84m4t.js +21 -0
  214. package/.next/{static/chunks/2eo9pqq9gay3r.js → standalone/.next/static/chunks/0ka4prpk3w9wn.js} +4 -4
  215. package/.next/standalone/.next/static/chunks/0s_xxwp7z88vv.js +1 -0
  216. package/.next/standalone/.next/static/chunks/1-nnl8amfm4yh.js +57 -0
  217. package/.next/{static/chunks/44yn0tcd9dfk3.js → standalone/.next/static/chunks/1bkt_hhjzvbh8.js} +1 -1
  218. package/.next/standalone/.next/static/chunks/1cmphb3kh2ers.css +3 -0
  219. package/.next/{static/chunks/1qbjermbf68xj.js → standalone/.next/static/chunks/1d8yv3k_atka7.js} +1 -1
  220. package/.next/standalone/.next/static/chunks/1ods5h86raivz.js +1 -0
  221. package/.next/standalone/.next/static/chunks/23hc51oa4vkhc.js +5 -0
  222. package/.next/standalone/.next/static/chunks/27n8k9wxlz5-7.js +1 -0
  223. package/.next/standalone/.next/static/chunks/{0p3g5tfostsep.js → 2q9i7pcxcnph1.js} +2 -2
  224. package/.next/{static/chunks/2zf4jmz9l3li2.js → standalone/.next/static/chunks/2w-y83mjlpnse.js} +1 -1
  225. package/.next/standalone/.next/static/chunks/2ws1xf293j-tm.js +5 -0
  226. package/.next/standalone/.next/static/chunks/3cqn-r-y5rrw1.js +5 -0
  227. package/.next/standalone/.next/static/chunks/3opgg1efrx8q6.js +1 -0
  228. package/.next/standalone/.next/static/chunks/3p51fpxxi4d5y.js +34 -0
  229. package/.next/{static/chunks/0an_b6zi1r_qq.js → standalone/.next/static/chunks/3y40z6of3r9py.js} +1 -5
  230. package/.next/standalone/.next/static/chunks/403dpflln8ah5.js +1 -0
  231. package/.next/standalone/CHANGELOG.md +83 -0
  232. package/.next/standalone/README.md +40 -14
  233. package/.next/standalone/SECURITY.md +17 -4
  234. package/.next/standalone/app/api/outreach/route.js +13 -73
  235. package/.next/standalone/app/api/scraper/route.js +106 -5
  236. package/.next/standalone/app/components/AppHeader.js +22 -6
  237. package/.next/standalone/app/components/AppTabs.js +4 -0
  238. package/.next/standalone/app/components/AutoConnect.js +286 -0
  239. package/.next/standalone/app/components/ChainView.js +75 -2
  240. package/.next/standalone/app/components/FilterPanel.js +8 -1
  241. package/.next/standalone/app/components/LinkedInLimits.js +38 -13
  242. package/.next/standalone/app/components/OutlinkQuest.js +32 -11
  243. package/.next/standalone/app/components/ScanStatusBar.js +18 -3
  244. package/.next/standalone/app/components/ScanTrail.js +13 -3
  245. package/.next/standalone/app/components/SeparationView.js +6 -22
  246. package/.next/standalone/app/components/Sidebar.js +147 -38
  247. package/.next/standalone/app/components/insights/Boards.js +275 -0
  248. package/.next/standalone/app/components/insights/PeopleView.js +266 -0
  249. package/.next/standalone/app/components/insights/Rail.js +156 -0
  250. package/.next/standalone/app/components/insights/Report.js +382 -0
  251. package/.next/standalone/app/components/insights/parts.js +239 -0
  252. package/.next/standalone/app/components/settings/UsageSection.js +50 -3
  253. package/.next/standalone/app/globals.css +2 -3
  254. package/.next/standalone/app/insights/page.js +220 -0
  255. package/.next/standalone/app/page.js +1 -17
  256. package/.next/standalone/app/queue/page.js +30 -18
  257. package/.next/standalone/app/setup/page.js +71 -13
  258. package/.next/standalone/install.sh +7 -6
  259. package/.next/standalone/lib/auto-connect.js +145 -0
  260. package/.next/standalone/lib/companies.js +1 -1
  261. package/.next/standalone/lib/in-progress.js +46 -0
  262. package/.next/standalone/lib/insights-board.js +613 -0
  263. package/.next/standalone/lib/linkedin-limits.js +36 -11
  264. package/.next/standalone/lib/requests-client.js +10 -0
  265. package/.next/standalone/lib/requests.js +124 -0
  266. package/.next/standalone/lib/scan-state.js +1 -0
  267. package/.next/standalone/lib/scanner-setup.js +82 -3
  268. package/.next/standalone/lib/scraper-client.js +18 -5
  269. package/.next/standalone/lib/settings.js +6 -0
  270. package/.next/standalone/lib/usage.js +5 -0
  271. package/.next/standalone/package-lock.json +2 -2
  272. package/.next/standalone/package.json +1 -1
  273. package/.next/standalone/scripts/build-app.mjs +167 -11
  274. package/.next/standalone/scripts/build-desktop.mjs +3 -2
  275. package/.next/standalone/scripts/ci-mac-signing.sh +128 -0
  276. package/.next/standalone/scripts/entitlements/electron.plist +23 -0
  277. package/.next/standalone/scripts/entitlements/node.plist +27 -0
  278. package/.next/standalone/scripts/mac-sign.mjs +563 -0
  279. package/.next/standalone/scripts/make-dmg-background.mjs +2 -1
  280. package/.next/standalone/scripts/scrape.py +569 -9
  281. package/.next/standalone/scripts/set-signing-secrets.sh +96 -0
  282. package/.next/static/chunks/02wnf8dkxegxg.js +34 -0
  283. package/.next/static/chunks/0hggugbh84m4t.js +21 -0
  284. package/.next/{standalone/.next/static/chunks/2eo9pqq9gay3r.js → static/chunks/0ka4prpk3w9wn.js} +4 -4
  285. package/.next/static/chunks/0s_xxwp7z88vv.js +1 -0
  286. package/.next/static/chunks/1-nnl8amfm4yh.js +57 -0
  287. package/.next/{standalone/.next/static/chunks/44yn0tcd9dfk3.js → static/chunks/1bkt_hhjzvbh8.js} +1 -1
  288. package/.next/static/chunks/1cmphb3kh2ers.css +3 -0
  289. package/.next/{standalone/.next/static/chunks/1qbjermbf68xj.js → static/chunks/1d8yv3k_atka7.js} +1 -1
  290. package/.next/static/chunks/1ods5h86raivz.js +1 -0
  291. package/.next/static/chunks/23hc51oa4vkhc.js +5 -0
  292. package/.next/static/chunks/27n8k9wxlz5-7.js +1 -0
  293. package/.next/static/chunks/{0p3g5tfostsep.js → 2q9i7pcxcnph1.js} +2 -2
  294. package/.next/{standalone/.next/static/chunks/2zf4jmz9l3li2.js → static/chunks/2w-y83mjlpnse.js} +1 -1
  295. package/.next/static/chunks/2ws1xf293j-tm.js +5 -0
  296. package/.next/static/chunks/3cqn-r-y5rrw1.js +5 -0
  297. package/.next/static/chunks/3opgg1efrx8q6.js +1 -0
  298. package/.next/static/chunks/3p51fpxxi4d5y.js +34 -0
  299. package/.next/{standalone/.next/static/chunks/0an_b6zi1r_qq.js → static/chunks/3y40z6of3r9py.js} +1 -5
  300. package/.next/static/chunks/403dpflln8ah5.js +1 -0
  301. package/CHANGELOG.md +83 -0
  302. package/README.md +40 -14
  303. package/SECURITY.md +17 -4
  304. package/lib/auto-connect.js +145 -0
  305. package/lib/companies.js +1 -1
  306. package/lib/in-progress.js +46 -0
  307. package/lib/insights-board.js +613 -0
  308. package/lib/linkedin-limits.js +36 -11
  309. package/lib/requests-client.js +10 -0
  310. package/lib/requests.js +124 -0
  311. package/lib/scan-state.js +1 -0
  312. package/lib/scanner-setup.js +82 -3
  313. package/lib/scraper-client.js +18 -5
  314. package/lib/settings.js +6 -0
  315. package/lib/usage.js +5 -0
  316. package/package.json +1 -1
  317. package/scripts/scrape.py +569 -9
  318. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_4y8z7._.js +0 -8
  319. package/.next/standalone/.next/server/chunks/_02twlca._.js +0 -10
  320. package/.next/standalone/.next/server/chunks/lib_rpc_0nef_n7.js +0 -3
  321. package/.next/standalone/.next/server/chunks/lib_rpc_0plrzra.js +0 -3
  322. package/.next/standalone/.next/server/chunks/lib_rpc_13a4m0c.js +0 -3
  323. package/.next/standalone/.next/server/chunks/lib_rpc_1if17c-.js +0 -3
  324. package/.next/standalone/.next/server/chunks/lib_rpc_1j-zw7v.js +0 -3
  325. package/.next/standalone/.next/server/chunks/lib_rpc_1sngt-q.js +0 -3
  326. package/.next/standalone/.next/server/chunks/lib_rpc_1v2sgme.js +0 -3
  327. package/.next/standalone/.next/server/chunks/lib_rpc_1vh-tgx.js +0 -3
  328. package/.next/standalone/.next/server/chunks/lib_rpc_1zaubz7.js +0 -3
  329. package/.next/standalone/.next/server/chunks/ssr/_02sband._.js +0 -7
  330. package/.next/standalone/.next/server/chunks/ssr/_189g8lg._.js +0 -3
  331. package/.next/standalone/.next/server/chunks/ssr/_1f_n00p._.js +0 -3
  332. package/.next/standalone/.next/server/chunks/ssr/app_components_0t908t-._.js +0 -3
  333. package/.next/standalone/.next/static/chunks/0e3g0sil79cus.js +0 -21
  334. package/.next/standalone/.next/static/chunks/0zd0t7e60bn4z.js +0 -1
  335. package/.next/standalone/.next/static/chunks/163b-20vwa06i.js +0 -34
  336. package/.next/standalone/.next/static/chunks/1pa-2v1ajvrko.js +0 -1
  337. package/.next/standalone/.next/static/chunks/23_1z47al92nz.js +0 -57
  338. package/.next/standalone/.next/static/chunks/260bomtr214m8.js +0 -34
  339. package/.next/standalone/.next/static/chunks/2xk2ra4piiuod.js +0 -34
  340. package/.next/standalone/.next/static/chunks/3b0-14cxqsprt.js +0 -1
  341. package/.next/standalone/.next/static/chunks/3jarus1_38s2z.js +0 -1
  342. package/.next/standalone/.next/static/chunks/3ssu341hav_sq.css +0 -3
  343. package/.next/standalone/.next/static/chunks/3v1qd3sqhqn0d.js +0 -1
  344. package/.next/static/chunks/0e3g0sil79cus.js +0 -21
  345. package/.next/static/chunks/0zd0t7e60bn4z.js +0 -1
  346. package/.next/static/chunks/163b-20vwa06i.js +0 -34
  347. package/.next/static/chunks/1pa-2v1ajvrko.js +0 -1
  348. package/.next/static/chunks/23_1z47al92nz.js +0 -57
  349. package/.next/static/chunks/260bomtr214m8.js +0 -34
  350. package/.next/static/chunks/2xk2ra4piiuod.js +0 -34
  351. package/.next/static/chunks/3b0-14cxqsprt.js +0 -1
  352. package/.next/static/chunks/3jarus1_38s2z.js +0 -1
  353. package/.next/static/chunks/3ssu341hav_sq.css +0 -3
  354. package/.next/static/chunks/3v1qd3sqhqn0d.js +0 -1
  355. /package/.next/standalone/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_buildManifest.js +0 -0
  356. /package/.next/standalone/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_clientMiddlewareManifest.js +0 -0
  357. /package/.next/standalone/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_ssgManifest.js +0 -0
  358. /package/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_buildManifest.js +0 -0
  359. /package/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_clientMiddlewareManifest.js +0 -0
  360. /package/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_ssgManifest.js +0 -0
@@ -0,0 +1,266 @@
1
+ 'use client';
2
+
3
+ // Insights → People: the Power Index. Everyone within two steps of you, each
4
+ // once, ranked by power, with the filters above it and the rail of boards
5
+ // beside it (mock-up B). The table shows a hundred rows at a time (25 on a
6
+ // phone), so a network of thousands stays quick; ranks are the whole list's,
7
+ // so a filter never renumbers anyone.
8
+
9
+ import { memo, useDeferredValue, useMemo, useState } from 'react';
10
+ import { filterIndex, bandText } from '../../../lib/insights-board';
11
+ import { hasRequest } from '../../../lib/requests-client';
12
+ import { shortName, TIERS } from '../../../lib/separation';
13
+ import { RARITY, toggle } from '../../../lib/rarity';
14
+ import Avatar from '../Avatar';
15
+ import { TIER_COLORS } from '../../../lib/themes';
16
+ import {
17
+ fmt, one, TierChip, DegreeChip, RarityTag, PersonCell, Src, Hero, OpenCircle, ScanCircle, AskButton,
18
+ LINE, SOFT_LINE, CARD_BG, ELLIPSIS,
19
+ } from './parts';
20
+ import Rail from './Rail';
21
+
22
+ export const PAGE = 100;
23
+ const COLS = '58px minmax(0,1.55fr) 148px minmax(0,1.45fr) 118px 100px';
24
+
25
+ export default function PeopleView({ data, heavy, open, net, source, isMobile, onView, requests }) {
26
+ const { index } = data;
27
+ const [degree, setDegree] = useState('all');
28
+ const [tiers, setTiers] = useState(() => new Set());
29
+ const [rarities, setRarities] = useState(() => new Set());
30
+ const [query, setQuery] = useState('');
31
+ const q = useDeferredValue(query);
32
+ // A hundred rows at a time on a computer, twenty-five on a phone, where the boards sit under the table.
33
+ const step = isMobile ? 25 : PAGE;
34
+ const [pages, setPages] = useState(1);
35
+ const shown = pages * step;
36
+ const filtering = degree !== 'all' || tiers.size > 0 || rarities.size > 0 || q.trim() !== '';
37
+ const list = useMemo(() => (filtering ? filterIndex(index, { degree, tiers, rarities, query: q }) : index.people),
38
+ [index, filtering, degree, tiers, rarities, q]);
39
+ const bandAt = useMemo(() => new Map(index.bands.map((b) => [b.start, b])), [index]);
40
+ // A new filter starts from the top again.
41
+ const filterKey = `${degree}|${[...tiers].join()}|${[...rarities].join()}|${q}`;
42
+ const [lastKey, setLastKey] = useState(filterKey);
43
+ if (lastKey !== filterKey) { setLastKey(filterKey); setPages(1); }
44
+
45
+ const rows = list.slice(0, shown);
46
+ const left = list.length - rows.length;
47
+ const next = list[rows.length];
48
+ const sameTieLeft = next && rows.length && rows[rows.length - 1].score === next.score
49
+ ? list.slice(rows.length).filter((p) => p.score === next.score).length : 0;
50
+ const scoped = source === 'own';
51
+ // No 2nd degree (a CSV import, or nothing scanned yet): no degree or rarity to filter by.
52
+ const second = index.counts.degree[2] > 0;
53
+
54
+ // "All →" on Hidden giants: the table, narrowed to them.
55
+ const showHidden = () => { setDegree(2); setTiers(new Set(['S'])); setRarities(new Set(['only'])); setQuery(''); window.scrollTo(0, 0); };
56
+
57
+ const filters = (
58
+ <div style={{
59
+ display: 'flex', alignItems: 'center', gap: isMobile ? 8 : 14, flexWrap: 'wrap', padding: isMobile ? '8px 10px' : '10px 12px',
60
+ border: `1px solid ${LINE}`, borderRadius: 12, background: 'rgba(var(--sd-ink, 255, 255, 255), 0.025)', marginBottom: 14,
61
+ }}>
62
+ {second && (
63
+ <Group label="Degree" isMobile={isMobile}>
64
+ {[['all', 'All', index.total], [1, '1st', index.counts.degree[1]], [2, '2nd', index.counts.degree[2]]].map(([k, label, n]) => (
65
+ <Chip key={k} on={degree === k} onClick={() => setDegree(k)} count={n}>{label}</Chip>
66
+ ))}
67
+ </Group>
68
+ )}
69
+ <Group label="Tier" isMobile={isMobile}>
70
+ {TIERS.map((t) => (
71
+ <Chip key={t} on={tiers.has(t)} onClick={() => setTiers((s) => toggle(s, t))} count={index.counts.tiers[t]} title={`${t} tier`}>
72
+ <TierChip tier={t} size={16} />
73
+ </Chip>
74
+ ))}
75
+ </Group>
76
+ {second && (
77
+ <Group label="Rarity" isMobile={isMobile}>
78
+ {RARITY.map((r) => (
79
+ <Chip key={r.key} on={rarities.has(r.key)} onClick={() => setRarities((s) => toggle(s, r.key))} count={index.counts.rarity[r.key]}
80
+ title={`${r.label}: ${r.range} mutual connection${r.range === '1' ? '' : 's'}`}>
81
+ <i className="sd-dot-html" style={{ width: 7, height: 7, borderRadius: '50%', background: r.color, display: 'inline-block' }} />{r.label}
82
+ </Chip>
83
+ ))}
84
+ </Group>
85
+ )}
86
+ <input type="search" value={query} onChange={(e) => setQuery(e.target.value)} aria-label="Search a name, company, or who knows them"
87
+ placeholder="Search a name or company" style={{
88
+ marginLeft: isMobile ? 0 : 'auto', width: isMobile ? '100%' : 240, height: isMobile ? 40 : 32, padding: '0 12px', borderRadius: 8, outline: 'none',
89
+ fontSize: isMobile ? 16 : 12.5, color: 'var(--sd-fg-1, #fff)', border: `1px solid ${LINE}`, background: 'rgba(var(--sd-ink, 255, 255, 255), 0.04)',
90
+ }} />
91
+ </div>
92
+ );
93
+
94
+ return (
95
+ <>
96
+ <Hero title="The Power Index" isMobile={isMobile}>
97
+ {second
98
+ ? <>Everyone within two steps of you, ranked by power: <b style={{ color: 'var(--sd-fg-1, #fff)' }}>{fmt(index.total)}</b> people, each once.</>
99
+ : <>Your connections, ranked by power: <b style={{ color: 'var(--sd-fg-1, #fff)' }}>{fmt(index.total)}</b> people.{' '}
100
+ {source === 'csv' ? 'A CSV import has no circles, so the people one step further out aren’t here.' : 'Scan their circles to add the people one step further out.'}</>}
101
+ </Hero>
102
+ {filters}
103
+ <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : 'minmax(0,1fr) 370px', gap: 16, alignItems: 'start' }}>
104
+ <div style={{ border: `1px solid ${LINE}`, borderRadius: 14, background: CARD_BG, overflow: 'hidden', minWidth: 0 }}>
105
+ {!isMobile && (
106
+ <div style={{ display: 'grid', gridTemplateColumns: COLS, gap: 10, padding: '0 16px', alignItems: 'center', height: 36, borderBottom: `1px solid ${LINE}`, background: 'rgba(var(--sd-ink, 255, 255, 255), 0.02)', fontSize: 10.5, color: 'var(--sd-fg-4, #6f7a88)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 700 }}>
107
+ <span>Rank</span><span>Person</span><span>Power</span><span>Way in</span><span>Rarity</span><span />
108
+ </div>
109
+ )}
110
+ {rows.length === 0 && (
111
+ <div style={{ padding: '28px 16px', fontSize: 13, color: 'var(--sd-fg-3, #8b9a9a)' }}>Nobody matches these filters.</div>
112
+ )}
113
+ {rows.map((p, i) => {
114
+ const band = !filtering ? bandAt.get(i) : null;
115
+ return (
116
+ <div key={p.key}>
117
+ {band && <Band band={band} isMobile={isMobile} />}
118
+ <Row p={p} isMobile={isMobile} scoped={scoped} csv={source === 'csv'} asked={p.degree === 2 && hasRequest(p.row, requests)} />
119
+ </div>
120
+ );
121
+ })}
122
+ {left > 0 && (
123
+ <button type="button" onClick={() => setPages((n) => n + 1)} style={{
124
+ display: 'block', width: '100%', textAlign: 'left', padding: '12px 16px', border: 'none', borderBottom: `1px solid ${LINE}`,
125
+ background: 'transparent', cursor: 'pointer', fontSize: 12.5, fontWeight: 600, color: 'var(--sd-blue, #3498DB)',
126
+ }}>
127
+ Show {fmt(Math.min(step, left))} more →
128
+ <span style={{ color: 'var(--sd-fg-4, #6f7a88)', fontWeight: 400, marginLeft: 8 }}>
129
+ {sameTieLeft ? `${fmt(sameTieLeft)} more at ${one(next.score)}, ${fmt(left)} in all` : `${fmt(left)} to go`}
130
+ </span>
131
+ </button>
132
+ )}
133
+ <Src style={{ padding: '10px 16px 14px', marginTop: 0 }}>{index.source}</Src>
134
+ </div>
135
+ <Rail data={data} heavy={heavy} open={open} source={source} onView={onView} onHidden={showHidden} isMobile={isMobile} net={net} />
136
+ </div>
137
+ </>
138
+ );
139
+ }
140
+
141
+ function Group({ label, children, isMobile }) {
142
+ // On a phone each group is one row that scrolls sideways, rather than four rows of chips.
143
+ return (
144
+ <div style={{ display: 'flex', gap: 5, alignItems: 'center', flexWrap: isMobile ? 'nowrap' : 'wrap', minWidth: 0, ...(isMobile ? { overflowX: 'auto', width: '100%', scrollbarWidth: 'none' } : null) }}>
145
+ <span style={{ fontSize: 10.5, color: 'var(--sd-fg-4, #6f7a88)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 700, marginRight: 3 }}>{label}</span>
146
+ {children}
147
+ </div>
148
+ );
149
+ }
150
+
151
+ function Chip({ on, onClick, count, children, title }) {
152
+ return (
153
+ <button type="button" aria-pressed={on} onClick={onClick} title={title} style={{
154
+ fontSize: 12, padding: '4px 9px', borderRadius: 16, cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 5, whiteSpace: 'nowrap',
155
+ border: `1px solid ${on ? 'rgba(var(--sd-ink, 255, 255, 255), 0.55)' : LINE}`,
156
+ background: on ? 'rgba(var(--sd-ink, 255, 255, 255), 0.12)' : 'rgba(var(--sd-ink, 255, 255, 255), 0.03)',
157
+ color: on ? 'var(--sd-fg-1, #fff)' : 'var(--sd-fg-2, #b8c4c4)', fontWeight: on ? 700 : 500,
158
+ }}>
159
+ {children}
160
+ {count != null && <small style={{ color: 'var(--sd-fg-4, #6f7a88)', fontSize: 11 }}>{fmt(count)}</small>}
161
+ </button>
162
+ );
163
+ }
164
+
165
+ /** A tie of many: how many share the score, and the working most of them share. */
166
+ function Band({ band, isMobile }) {
167
+ const t = bandText(band);
168
+ const mixed = band.yours > 0 && band.yours < band.count;
169
+ return (
170
+ <div style={{
171
+ display: 'flex', alignItems: isMobile ? 'flex-start' : 'center', gap: 12, padding: isMobile ? '10px 12px' : '10px 16px',
172
+ background: 'linear-gradient(90deg, rgba(255,215,0,0.1), rgba(255,215,0,0.02))',
173
+ borderTop: '1px solid rgba(255,215,0,0.22)', borderBottom: '1px solid rgba(255,215,0,0.22)',
174
+ }}>
175
+ <span style={{ fontSize: 15, fontWeight: 800, color: 'var(--sd-gold, #FFD700)', fontVariantNumeric: 'tabular-nums', flexShrink: 0 }}>#{fmt(band.rank)}=</span>
176
+ <span style={{ fontSize: 12.5, color: 'var(--sd-fg-1, #e9edf3)', lineHeight: 1.45 }}>
177
+ <b>{t.head}</b> {t.rest}{' '}
178
+ <span style={{ color: 'var(--sd-fg-3, #8b9a9a)' }}>{mixed ? 'Yours first, then most ways in.' : band.yours ? 'All yours.' : 'Most ways in first.'}</span>
179
+ </span>
180
+ </div>
181
+ );
182
+ }
183
+
184
+ /** One person: rank, who, power, way in, rarity and what to do. */
185
+ const Row = memo(function Row({ p, isMobile, scoped, csv, asked }) {
186
+ const rank = `#${fmt(p.rank)}${p.tied ? '=' : ''}`;
187
+ const podium = p.rank <= 5;
188
+ const power = (
189
+ <span style={{ display: 'flex', alignItems: 'center', gap: 7, flexShrink: 0 }}>
190
+ <b style={{ fontSize: isMobile ? 16 : 17, fontWeight: 800, minWidth: 30, textAlign: 'right', fontVariantNumeric: 'tabular-nums', color: 'var(--sd-fg-1, #fff)' }}>{one(p.score)}</b>
191
+ <TierChip tier={p.tier} />
192
+ {!isMobile && p.boost > 0 && (
193
+ <span title="Added for a strong circle: their scanned circle holds many S and A people (lib/scoring.js bridge boost, up to +2)" style={{
194
+ fontSize: 10, fontWeight: 700, color: 'var(--sd-green, #00ff88)', background: 'rgba(0,255,136,0.08)', border: '1px solid rgba(0,255,136,0.28)',
195
+ padding: '1px 6px', borderRadius: 10, whiteSpace: 'nowrap',
196
+ }}>+{p.boost} circle</span>
197
+ )}
198
+ </span>
199
+ );
200
+ const way = <Way p={p} max={isMobile ? 1 : 2} csv={csv} />;
201
+ const rarity = p.degree === 1
202
+ ? <span style={{ fontSize: 11.5, color: 'var(--sd-fg-4, #6f7a88)', whiteSpace: 'nowrap' }}>Your connection</span>
203
+ : <RarityTag rarity={p.rarity} count={!isMobile} small={isMobile} />;
204
+ const action = <Action p={p} scoped={scoped} asked={asked} compact={isMobile} />;
205
+
206
+ if (isMobile) {
207
+ return (
208
+ <div style={{ display: 'grid', gridTemplateColumns: '40px minmax(0,1fr) 66px', columnGap: 8, rowGap: 6, padding: '10px 12px', borderBottom: `1px solid ${SOFT_LINE}` }}>
209
+ <span style={{ gridRow: '1 / span 2', paddingTop: 9, fontSize: 11.5, fontWeight: 700, color: podium ? 'var(--sd-gold, #FFD700)' : 'var(--sd-fg-3, #8b9a9a)', whiteSpace: 'nowrap' }}>{rank}</span>
210
+ <PersonCell row={p.row} size={32} chip={false} />
211
+ <span style={{ justifySelf: 'end' }}>{power}</span>
212
+ <div style={{ gridColumn: '2 / span 2', display: 'flex', alignItems: 'center', gap: 8, minWidth: 0 }}>
213
+ <span style={{ display: 'flex', alignItems: 'center', gap: 7, minWidth: 0, flex: 1, overflow: 'hidden', fontSize: 12, color: 'var(--sd-fg-2, #b8c4c4)' }}>{way}</span>
214
+ {p.degree === 2 && rarity}
215
+ {action}
216
+ </div>
217
+ </div>
218
+ );
219
+ }
220
+ return (
221
+ <div style={{ display: 'grid', gridTemplateColumns: COLS, gap: 10, padding: '0 16px', alignItems: 'center', minHeight: 56, borderBottom: `1px solid ${SOFT_LINE}` }}>
222
+ <span style={{ fontSize: 13, fontWeight: 700, color: podium ? 'var(--sd-gold, #FFD700)' : 'var(--sd-fg-3, #8b9a9a)', fontVariantNumeric: 'tabular-nums' }}>{rank}</span>
223
+ <PersonCell row={p.row} chip={false} />
224
+ {power}
225
+ <span style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 0, fontSize: 12, color: 'var(--sd-fg-2, #b8c4c4)' }}>{way}</span>
226
+ <span style={{ minWidth: 0 }}>{rarity}</span>
227
+ <span style={{ justifySelf: 'end' }}>{action}</span>
228
+ </div>
229
+ );
230
+ });
231
+
232
+ /** Yours: their circle. 2nd degree: who of yours knows them, best first. */
233
+ function Way({ p, max = 2, csv }) {
234
+ if (p.degree === 1) {
235
+ const c = p.circle;
236
+ // A CSV import has no circles to scan: the chip says enough.
237
+ if (csv) return <DegreeChip degree={1} />;
238
+ const text = c.state === 'scanned'
239
+ ? <span style={{ whiteSpace: 'nowrap' }}>Circle {fmt(c.size)} · <b style={{ color: 'var(--sd-fg-1, #fff)' }}>{fmt(c.S + c.A)}</b> S+A</span>
240
+ : <span style={{ color: 'var(--sd-fg-4, #6f7a88)', fontSize: 11.5, whiteSpace: 'nowrap' }}>{c.state === 'hidden' ? 'Their list is hidden' : 'Circle not scanned'}</span>;
241
+ return <><DegreeChip degree={1} />{text}</>;
242
+ }
243
+ const named = p.routes.filter((r) => r.bridge);
244
+ const extra = p.routes.length - Math.min(max, named.length);
245
+ return (
246
+ <>
247
+ <DegreeChip degree={2} />
248
+ <span style={{ display: 'flex', gap: 8, minWidth: 0, overflow: 'hidden' }} title={p.routes.map((r) => (r.bridge ? r.bridge.name : 'a connection the app can’t name')).join('\n')}>
249
+ {named.slice(0, max).map((r) => (
250
+ <span key={r.id} style={{ display: 'inline-flex', alignItems: 'center', gap: 5, fontSize: 12, color: 'var(--sd-fg-2, #b8c4c4)', whiteSpace: 'nowrap' }}>
251
+ <Avatar person={r.bridge} size={18} tierColors={TIER_COLORS} />{shortName(r.bridge.name)}
252
+ </span>
253
+ ))}
254
+ {!named.length && <span style={{ fontSize: 11.5, color: 'var(--sd-fg-4, #6f7a88)', ...ELLIPSIS }}>a connection the app can’t name</span>}
255
+ {extra > 0 && <span style={{ fontSize: 11.5, color: 'var(--sd-fg-4, #6f7a88)', whiteSpace: 'nowrap' }}>+{fmt(extra)}</span>}
256
+ </span>
257
+ </>
258
+ );
259
+ }
260
+
261
+ function Action({ p, scoped, asked, compact }) {
262
+ if (p.degree === 2) return <AskButton row={p.row} bridgeId={p.routes[0]?.id ?? p.row.source_connection_id} asked={asked} compact={compact} canAuto={scoped} />;
263
+ if (p.circle.state === 'scanned') return <OpenCircle id={p.row.id} compact={compact} />;
264
+ if (p.circle.state === 'todo' && scoped) return <ScanCircle id={p.row.id} compact={compact} />;
265
+ return null;
266
+ }
@@ -0,0 +1,156 @@
1
+ 'use client';
2
+
3
+ // The cards beside the Power Index: Untapped, Kingmakers, Gatekeepers,
4
+ // Hidden giants, Company power, How sure, and Richest?, the honest answer to
5
+ // a question the app can't answer (it never sees money). Each card's top five,
6
+ // and a link to its board.
7
+
8
+ import { shortName } from '../../../lib/separation';
9
+ import Avatar from '../Avatar';
10
+ import { TIER_COLORS } from '../../../lib/themes';
11
+ import { fmt, one, pc, Card, CardHead, MiniRow, TierChip, Src, NeedsCircles, ELLIPSIS } from './parts';
12
+
13
+ export default function Rail({ data, heavy, open, source, onView, onHidden }) {
14
+ const { kings, gates, hidden, sure } = data;
15
+ const circles = kings.scanned > 0;
16
+ return (
17
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 12, minWidth: 0 }}>
18
+ {/* The four boards that read circles; with none scanned, one card says so once. */}
19
+ {!circles ? (
20
+ <Card>
21
+ <CardHead title="Kingmakers, Gatekeepers, Hidden giants, Untapped" sub="Who stands behind your connections, read from their circles" />
22
+ <NeedsCircles source={source} compact />
23
+ </Card>
24
+ ) : (
25
+ <>
26
+ <Untapped open={open} />
27
+
28
+ <Card>
29
+ <CardHead title="Kingmakers" sub="Most S and A people behind them" more="Board →" onMore={() => onView('kingmakers')} />
30
+ {kings.list.slice(0, 5).map((k, i) => (
31
+ <MiniRow key={k.row.id} first={i === 0} rank={i + 1} value={fmt(k.SA)} label="S+A behind"
32
+ left={<Who row={k.row} sub={<><TierChip tier={k.row.tier} size={15} /><span style={ELLIPSIS}>circle of {fmt(k.size)}</span></>} />} />
33
+ ))}
34
+ </Card>
35
+
36
+ <Card>
37
+ <CardHead title="Gatekeepers" sub={`S and A who reach you through one connection only. Top three: ${pc(gates.top3Share)} of your S and A reach.`}
38
+ more="Board →" onMore={() => onView('gatekeepers')} />
39
+ {gates.list.slice(0, 5).map((g, i) => (
40
+ <MiniRow key={g.row.id} first={i === 0} rank={i + 1} value={fmt(g.onlySA)} valueColor="var(--sd-green, #00ff88)" label="S+A only via them"
41
+ left={<Who row={g.row} sub={<><TierChip tier={g.row.tier} size={15} /><span style={ELLIPSIS}>circle of {fmt(g.size)}</span></>} />} />
42
+ ))}
43
+ </Card>
44
+
45
+ <Card>
46
+ <CardHead title={`Hidden giants · ${fmt(hidden.count)}`} sub="S-tier with one way in: the connection who knows them is the only door you have."
47
+ more={hidden.count ? 'All →' : null} onMore={onHidden} />
48
+ {hidden.count === 0 ? <div style={{ fontSize: 12, color: 'var(--sd-fg-3, #8b9a9a)', padding: '2px 0 6px' }}>None yet: every S-tier person you can reach has two or more ways in.</div>
49
+ : hidden.list.slice(0, 4).map((h, i) => (
50
+ <MiniRow key={h.key} first={i === 0} value={one(h.score)} label={h.from === 'linkedin' ? '1 mutual (LinkedIn)' : '1 way in (scans)'}
51
+ left={<Who row={h.row} sub={<span style={ELLIPSIS}>{[h.row.company, h.via ? `only via ${shortName(h.via.name)}` : 'only via a connection the app can’t name'].filter(Boolean).join(' · ')}</span>} />} />
52
+ ))}
53
+ {hidden.count > 0 && <Src>{fmt(hidden.fromLinkedIn)} from LinkedIn’s own mutual count, {fmt(hidden.fromScans)} from the ways in your scans saw, which can only go up.</Src>}
54
+ </Card>
55
+ </>
56
+ )}
57
+
58
+ <Card>
59
+ <CardHead title="Company power" sub="Everyone there now, power added up" more={heavy ? 'Board →' : null} onMore={() => onView('companies')} />
60
+ {!heavy ? <Counting /> : heavy.companies.list.slice(0, 5).map((c, i) => (
61
+ <MiniRow key={c.name} first={i === 0} rank={i + 1} value={fmt(Math.round(c.total))} label="total power"
62
+ left={<span style={{ display: 'flex', alignItems: 'center', gap: 9, minWidth: 0 }}>
63
+ <Logo name={c.name} />
64
+ <span style={{ display: 'flex', flexDirection: 'column', minWidth: 0 }}>
65
+ <b style={{ fontSize: 12.5, fontWeight: 650, ...ELLIPSIS }}>{c.name}</b>
66
+ <span style={{ fontSize: 11.5, color: 'var(--sd-fg-3, #8b9a9a)', ...ELLIPSIS }}>
67
+ <span style={{ color: TIER_COLORS.S }}>{fmt(c.S)} S</span> · <span style={{ color: TIER_COLORS.A }}>{fmt(c.A)} A</span> · {fmt(c.people)} people
68
+ </span>
69
+ </span>
70
+ </span>} />
71
+ ))}
72
+ </Card>
73
+
74
+ <Card>
75
+ <CardHead title="How sure" sub="How much of this ranking rests on a guess" />
76
+ <div style={{ display: 'flex', alignItems: 'baseline', gap: 10 }}>
77
+ <b style={{ fontSize: 26, fontWeight: 850, color: sure.share >= 50 ? 'var(--sd-orange, #FF6B35)' : 'var(--sd-fg-1, #fff)' }}>{pc(sure.share)}</b>
78
+ <span style={{ fontSize: 12.5, color: 'var(--sd-fg-2, #b8c4c4)', lineHeight: 1.4 }}>
79
+ of these scores lean on an estimate{sure.tie ? <>{sure.share >= 50 ? ', which is why' : '. At the top,'} <b style={{ color: 'var(--sd-fg-1, #fff)' }}>{fmt(sure.tie.count)}</b> people share {one(sure.tie.score)}</> : null}.
80
+ </span>
81
+ </div>
82
+ <Src>{fmt(sure.company + sure.both)} with a company no list knows, {fmt(sure.title + sure.both)} with a title the app couldn’t read. Score the companies you know on the Scores tab and the top of the list separates.</Src>
83
+ </Card>
84
+
85
+ <Richest heavy={heavy} />
86
+ </div>
87
+ );
88
+ }
89
+
90
+ function Untapped({ open }) {
91
+ return (
92
+ <Card style={{ padding: '14px 16px' }}>
93
+ <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
94
+ <b style={{ fontSize: 30, fontWeight: 850, color: 'var(--sd-orange, #FF6B35)', fontVariantNumeric: 'tabular-nums' }}>{fmt(open?.total)}</b>
95
+ <span style={{ fontSize: 12.5, color: 'var(--sd-fg-2, #b8c4c4)', lineHeight: 1.45 }}>
96
+ <b style={{ color: 'var(--sd-fg-1, #fff)' }}>Untapped:</b> S and A people in your 2nd degree with no request out. {fmt(open?.S)} of them S. Requests marked sent so far: {fmt(open?.asked)}.
97
+ </span>
98
+ </div>
99
+ </Card>
100
+ );
101
+ }
102
+
103
+ /** "Richest?": the app never sees money, and says so; power at big companies is what it can count. */
104
+ function Richest({ heavy }) {
105
+ return (
106
+ <Card dashed>
107
+ <CardHead title="Richest?" />
108
+ <p style={{ fontSize: 12.5, color: 'var(--sd-fg-1, #e9edf3)', margin: '6px 0 8px', lineHeight: 1.5 }}>
109
+ Six Degrees doesn’t know anyone’s money. LinkedIn shows titles and companies, not wealth. The closest honest measure is
110
+ power: who runs the biggest companies you can reach.
111
+ </p>
112
+ {!heavy ? <Counting /> : (
113
+ <div style={{ display: 'flex', gap: 10 }}>
114
+ <Stat n={heavy.companies.big.people} text={`people whose score rests on a company scored 8 or more (Fortune 500 scale)${heavy.companies.big.people ? `, at ${fmt(heavy.companies.big.companies)} compan${heavy.companies.big.companies === 1 ? 'y' : 'ies'}` : ''}`} />
115
+ <Stat n={heavy.ladder.rungs.find((r) => r.key === 'csuite').total} text="C-suite and founders within two steps, by their headline" />
116
+ </div>
117
+ )}
118
+ <Src>{heavy ? heavy.companies.bigSource : null}</Src>
119
+ </Card>
120
+ );
121
+ }
122
+
123
+ function Stat({ n, text }) {
124
+ return (
125
+ <div style={{ flex: 1, background: 'rgba(var(--sd-ink, 255, 255, 255), 0.05)', borderRadius: 9, padding: '8px 10px', minWidth: 0 }}>
126
+ <b style={{ fontSize: 20, fontWeight: 800, display: 'block', fontVariantNumeric: 'tabular-nums' }}>{fmt(n)}</b>
127
+ <span style={{ fontSize: 11, color: 'var(--sd-fg-3, #8b9a9a)', lineHeight: 1.35, display: 'block' }}>{text}</span>
128
+ </div>
129
+ );
130
+ }
131
+
132
+ function Who({ row, sub }) {
133
+ return (
134
+ <span style={{ display: 'flex', alignItems: 'center', gap: 9, minWidth: 0 }}>
135
+ <Avatar person={row} size={26} tierColors={TIER_COLORS} />
136
+ <span style={{ display: 'flex', flexDirection: 'column', minWidth: 0 }}>
137
+ <b style={{ fontSize: 12.5, fontWeight: 650, ...ELLIPSIS }}>{row.name}</b>
138
+ <span style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11.5, color: 'var(--sd-fg-3, #8b9a9a)', minWidth: 0 }}>{sub}</span>
139
+ </span>
140
+ </span>
141
+ );
142
+ }
143
+
144
+ export function Logo({ name, size = 26 }) {
145
+ const letters = String(name || '').split(/\s+/).filter(Boolean).map((w) => w[0]).join('').slice(0, 2).toUpperCase();
146
+ return (
147
+ <span style={{
148
+ width: size, height: size, borderRadius: 7, background: 'rgba(var(--sd-ink, 255, 255, 255), 0.08)', flexShrink: 0,
149
+ display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 10, fontWeight: 800, color: 'var(--sd-fg-2, #b8c4c4)',
150
+ }}>{letters}</span>
151
+ );
152
+ }
153
+
154
+ function Counting() {
155
+ return <div style={{ fontSize: 12, color: 'var(--sd-fg-4, #6f7a88)', padding: '4px 0 6px' }}>Counting…</div>;
156
+ }