six-degrees 0.6.0 → 0.7.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 (557) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +3 -0
  3. package/.next/standalone/.next/build-manifest.json +3 -3
  4. package/.next/standalone/.next/prerender-manifest.json +14 -14
  5. package/.next/standalone/.next/routes-manifest.json +18 -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 +1 -1
  12. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  13. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  14. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  15. package/.next/standalone/.next/server/app/_not-found.rsc +26 -18
  16. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +26 -18
  17. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +25 -16
  18. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  19. package/.next/standalone/.next/server/app/api/admin-delete/route.js +2 -2
  20. package/.next/standalone/.next/server/app/api/admin-delete/route.js.nft.json +1 -1
  21. package/.next/standalone/.next/server/app/api/admin-update/route.js +2 -2
  22. package/.next/standalone/.next/server/app/api/admin-update/route.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/api/bridges/route.js +2 -2
  24. package/.next/standalone/.next/server/app/api/bridges/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/bulk-import/route.js +2 -2
  26. package/.next/standalone/.next/server/app/api/bulk-import/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js +3 -3
  28. package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/company-scores/route.js +3 -3
  30. package/.next/standalone/.next/server/app/api/company-scores/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/connections/route.js +2 -2
  32. package/.next/standalone/.next/server/app/api/connections/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/data/backup/route/app-paths-manifest.json +3 -0
  34. package/.next/standalone/.next/server/app/api/data/backup/route/build-manifest.json +12 -0
  35. package/.next/standalone/.next/server/app/api/data/backup/route/server-reference-manifest.json +4 -0
  36. package/.next/standalone/.next/server/app/api/data/backup/route.js +7 -0
  37. package/.next/standalone/.next/server/app/api/data/backup/route.js.map +5 -0
  38. package/.next/standalone/.next/server/app/api/data/backup/route.js.nft.json +1 -0
  39. package/.next/standalone/.next/server/app/api/data/backup/route_client-reference-manifest.js +3 -0
  40. package/.next/standalone/.next/server/app/api/data/csv/route/app-paths-manifest.json +3 -0
  41. package/.next/standalone/.next/server/app/api/data/csv/route/build-manifest.json +12 -0
  42. package/.next/standalone/.next/server/app/api/data/csv/route/server-reference-manifest.json +4 -0
  43. package/.next/standalone/.next/server/app/api/data/csv/route.js +8 -0
  44. package/.next/standalone/.next/server/app/api/data/csv/route.js.map +5 -0
  45. package/.next/standalone/.next/server/app/api/data/csv/route.js.nft.json +1 -0
  46. package/.next/standalone/.next/server/app/api/data/csv/route_client-reference-manifest.js +3 -0
  47. package/.next/standalone/.next/server/app/api/data/export/route.js +1 -1
  48. package/.next/standalone/.next/server/app/api/data/export/route.js.nft.json +1 -1
  49. package/.next/standalone/.next/server/app/api/data/import/route.js +1 -1
  50. package/.next/standalone/.next/server/app/api/data/import/route.js.nft.json +1 -1
  51. package/.next/standalone/.next/server/app/api/data/restart/route.js +1 -1
  52. package/.next/standalone/.next/server/app/api/data/restart/route.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/api/data/restore/route/app-paths-manifest.json +3 -0
  54. package/.next/standalone/.next/server/app/api/data/restore/route/build-manifest.json +12 -0
  55. package/.next/standalone/.next/server/app/api/data/restore/route/server-reference-manifest.json +4 -0
  56. package/.next/standalone/.next/server/app/api/data/restore/route.js +7 -0
  57. package/.next/standalone/.next/server/app/api/data/restore/route.js.map +5 -0
  58. package/.next/standalone/.next/server/app/api/data/restore/route.js.nft.json +1 -0
  59. package/.next/standalone/.next/server/app/api/data/restore/route_client-reference-manifest.js +3 -0
  60. package/.next/standalone/.next/server/app/api/data/reveal/route.js +1 -1
  61. package/.next/standalone/.next/server/app/api/data/reveal/route.js.nft.json +1 -1
  62. package/.next/standalone/.next/server/app/api/data/route.js +1 -1
  63. package/.next/standalone/.next/server/app/api/data/route.js.nft.json +1 -1
  64. package/.next/standalone/.next/server/app/api/delete-cluster/route.js +2 -2
  65. package/.next/standalone/.next/server/app/api/delete-cluster/route.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/api/ingest/route.js +2 -2
  67. package/.next/standalone/.next/server/app/api/ingest/route.js.nft.json +1 -1
  68. package/.next/standalone/.next/server/app/api/network/route.js +2 -2
  69. package/.next/standalone/.next/server/app/api/network/route.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/api/notifications/route.js +2 -2
  71. package/.next/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  72. package/.next/standalone/.next/server/app/api/outreach/route.js +2 -2
  73. package/.next/standalone/.next/server/app/api/outreach/route.js.nft.json +1 -1
  74. package/.next/standalone/.next/server/app/api/queue/route.js +2 -2
  75. package/.next/standalone/.next/server/app/api/queue/route.js.nft.json +1 -1
  76. package/.next/standalone/.next/server/app/api/scraper/route.js +4 -2
  77. package/.next/standalone/.next/server/app/api/scraper/route.js.nft.json +1 -1
  78. package/.next/standalone/.next/server/app/api/settings/route.js +3 -3
  79. package/.next/standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
  80. package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js +3 -3
  81. package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.nft.json +1 -1
  82. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js +3 -3
  83. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.nft.json +1 -1
  84. package/.next/standalone/.next/server/app/api/setup-profile/route.js +2 -2
  85. package/.next/standalone/.next/server/app/api/setup-profile/route.js.nft.json +1 -1
  86. package/.next/standalone/.next/server/app/api/social/crm/route.js +1 -1
  87. package/.next/standalone/.next/server/app/api/social/crm/route.js.nft.json +1 -1
  88. package/.next/standalone/.next/server/app/api/social/messages/route.js +1 -1
  89. package/.next/standalone/.next/server/app/api/social/messages/route.js.nft.json +1 -1
  90. package/.next/standalone/.next/server/app/api/social/route.js +2 -2
  91. package/.next/standalone/.next/server/app/api/social/route.js.nft.json +1 -1
  92. package/.next/standalone/.next/server/app/api/unlock/route.js +2 -2
  93. package/.next/standalone/.next/server/app/api/unlock/route.js.nft.json +1 -1
  94. package/.next/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  95. package/.next/standalone/.next/server/app/api/update-images/route.js +2 -2
  96. package/.next/standalone/.next/server/app/api/update-images/route.js.nft.json +1 -1
  97. package/.next/standalone/.next/server/app/api/users/route.js +2 -2
  98. package/.next/standalone/.next/server/app/api/users/route.js.nft.json +1 -1
  99. package/.next/standalone/.next/server/app/avatars/[file]/route.js +1 -1
  100. package/.next/standalone/.next/server/app/avatars/[file]/route.js.nft.json +1 -1
  101. package/.next/standalone/.next/server/app/import/page.js +1 -1
  102. package/.next/standalone/.next/server/app/import/page.js.nft.json +1 -1
  103. package/.next/standalone/.next/server/app/import/page_client-reference-manifest.js +1 -1
  104. package/.next/standalone/.next/server/app/import.html +1 -1
  105. package/.next/standalone/.next/server/app/import.rsc +32 -24
  106. package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +32 -24
  107. package/.next/standalone/.next/server/app/import.segments/_tree.segment.rsc +2 -2
  108. package/.next/standalone/.next/server/app/import.segments/import/__PAGE__.segment.rsc +23 -18
  109. package/.next/standalone/.next/server/app/index.html +1 -1
  110. package/.next/standalone/.next/server/app/index.rsc +29 -22
  111. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +20 -15
  112. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +29 -22
  113. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  114. package/.next/standalone/.next/server/app/launch/page.js +1 -1
  115. package/.next/standalone/.next/server/app/launch/page.js.nft.json +1 -1
  116. package/.next/standalone/.next/server/app/launch/page_client-reference-manifest.js +1 -1
  117. package/.next/standalone/.next/server/app/launch.html +2 -2
  118. package/.next/standalone/.next/server/app/launch.rsc +32 -24
  119. package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +32 -24
  120. package/.next/standalone/.next/server/app/launch.segments/_tree.segment.rsc +2 -2
  121. package/.next/standalone/.next/server/app/launch.segments/launch/__PAGE__.segment.rsc +23 -18
  122. package/.next/standalone/.next/server/app/page.js +1 -1
  123. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  124. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  125. package/.next/standalone/.next/server/app/paths/page.js +1 -1
  126. package/.next/standalone/.next/server/app/paths/page.js.nft.json +1 -1
  127. package/.next/standalone/.next/server/app/paths/page_client-reference-manifest.js +1 -1
  128. package/.next/standalone/.next/server/app/paths.html +1 -1
  129. package/.next/standalone/.next/server/app/paths.rsc +32 -24
  130. package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +32 -24
  131. package/.next/standalone/.next/server/app/paths.segments/_tree.segment.rsc +2 -2
  132. package/.next/standalone/.next/server/app/paths.segments/paths/__PAGE__.segment.rsc +21 -18
  133. package/.next/standalone/.next/server/app/profile/page.js +1 -1
  134. package/.next/standalone/.next/server/app/profile/page.js.nft.json +1 -1
  135. package/.next/standalone/.next/server/app/profile/page_client-reference-manifest.js +1 -1
  136. package/.next/standalone/.next/server/app/profile.html +1 -1
  137. package/.next/standalone/.next/server/app/profile.rsc +32 -24
  138. package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +32 -24
  139. package/.next/standalone/.next/server/app/profile.segments/_tree.segment.rsc +2 -2
  140. package/.next/standalone/.next/server/app/profile.segments/profile/__PAGE__.segment.rsc +23 -18
  141. package/.next/standalone/.next/server/app/queue/page.js +1 -1
  142. package/.next/standalone/.next/server/app/queue/page.js.nft.json +1 -1
  143. package/.next/standalone/.next/server/app/queue/page_client-reference-manifest.js +1 -1
  144. package/.next/standalone/.next/server/app/queue.html +1 -1
  145. package/.next/standalone/.next/server/app/queue.rsc +32 -24
  146. package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +32 -24
  147. package/.next/standalone/.next/server/app/queue.segments/_tree.segment.rsc +2 -2
  148. package/.next/standalone/.next/server/app/queue.segments/queue/__PAGE__.segment.rsc +20 -18
  149. package/.next/standalone/.next/server/app/scores/page.js +1 -1
  150. package/.next/standalone/.next/server/app/scores/page.js.nft.json +1 -1
  151. package/.next/standalone/.next/server/app/scores/page_client-reference-manifest.js +1 -1
  152. package/.next/standalone/.next/server/app/scores.html +1 -1
  153. package/.next/standalone/.next/server/app/scores.rsc +32 -24
  154. package/.next/standalone/.next/server/app/scores.segments/_full.segment.rsc +32 -24
  155. package/.next/standalone/.next/server/app/scores.segments/_tree.segment.rsc +2 -2
  156. package/.next/standalone/.next/server/app/scores.segments/scores/__PAGE__.segment.rsc +23 -18
  157. package/.next/standalone/.next/server/app/settings/page.js +1 -1
  158. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  159. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  160. package/.next/standalone/.next/server/app/settings.html +1 -1
  161. package/.next/standalone/.next/server/app/settings.rsc +32 -24
  162. package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +32 -24
  163. package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  164. package/.next/standalone/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +20 -18
  165. package/.next/standalone/.next/server/app/setup/page.js +1 -1
  166. package/.next/standalone/.next/server/app/setup/page.js.nft.json +1 -1
  167. package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  168. package/.next/standalone/.next/server/app/setup.html +1 -1
  169. package/.next/standalone/.next/server/app/setup.rsc +32 -24
  170. package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +32 -24
  171. package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +2 -2
  172. package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +21 -18
  173. package/.next/standalone/.next/server/app/social/page.js +1 -1
  174. package/.next/standalone/.next/server/app/social/page.js.nft.json +1 -1
  175. package/.next/standalone/.next/server/app/social/page_client-reference-manifest.js +1 -1
  176. package/.next/standalone/.next/server/app/social.html +1 -1
  177. package/.next/standalone/.next/server/app/social.rsc +32 -24
  178. package/.next/standalone/.next/server/app/social.segments/_full.segment.rsc +32 -24
  179. package/.next/standalone/.next/server/app/social.segments/_tree.segment.rsc +2 -2
  180. package/.next/standalone/.next/server/app/social.segments/social/__PAGE__.segment.rsc +23 -18
  181. package/.next/standalone/.next/server/app-paths-manifest.json +3 -0
  182. package/.next/standalone/.next/server/chunks/[root-of-the-server]__00la_y0._.js +1 -1
  183. package/.next/standalone/.next/server/chunks/[root-of-the-server]__05_3-22._.js +1 -1
  184. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__15wc9e-._.js → [root-of-the-server]__063s0x7._.js} +2 -2
  185. package/.next/standalone/.next/server/chunks/[root-of-the-server]__066rab1._.js +7 -0
  186. package/.next/standalone/.next/server/chunks/[root-of-the-server]__07t47cm._.js +1 -1
  187. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__13dx4sd._.js → [root-of-the-server]__0_4y8z7._.js} +3 -3
  188. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cj5jqc._.js +1 -1
  189. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e0fei3._.js +1 -1
  190. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0fooke1._.js +7 -0
  191. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ljnyho._.js +1 -1
  192. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o5-tcg._.js +1 -1
  193. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qrnous._.js +1 -1
  194. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t3v1a1._.js +1 -1
  195. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t6y79e._.js +7 -0
  196. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wmexuc._.js +1 -1
  197. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0x29muh._.js +7 -0
  198. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0xu34sz._.js +1 -1
  199. package/.next/standalone/.next/server/chunks/[root-of-the-server]__133knx1._.js +1 -1
  200. package/.next/standalone/.next/server/chunks/[root-of-the-server]__15-17hl._.js +1 -1
  201. package/.next/standalone/.next/server/chunks/[root-of-the-server]__19b7mig._.js +1 -1
  202. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1a_6x37._.js +8 -0
  203. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1an_8pa._.js +7 -0
  204. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1bbcwub._.js +1 -1
  205. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ducpz2._.js +3 -0
  206. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1eris29._.js +1 -1
  207. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1gjo_cq._.js +1 -1
  208. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qcm08_._.js +1 -1
  209. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tir0vc._.js +1 -1
  210. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1w25q0m._.js +1 -1
  211. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1xhyinn._.js +3 -0
  212. package/.next/standalone/.next/server/chunks/[root-of-the-server]__20rwfdw._.js +1 -1
  213. package/.next/standalone/.next/server/chunks/_02twlca._.js +1 -1
  214. package/.next/standalone/.next/server/chunks/_072jl0y._.js +1 -1
  215. package/.next/standalone/.next/server/chunks/_0lw8_i0._.js +1 -1
  216. package/.next/standalone/.next/server/chunks/_0sqqpzb._.js +3 -0
  217. package/.next/standalone/.next/server/chunks/_1_fynia._.js +7 -7
  218. package/.next/standalone/.next/server/chunks/_1fn30_l._.js +1 -1
  219. package/.next/standalone/.next/server/chunks/_1itd1o_._.js +1 -1
  220. package/.next/standalone/.next/server/chunks/_1iwkh8t._.js +1 -1
  221. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_backup_route_actions_0zoj04p.js +3 -0
  222. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_csv_route_actions_0l6m7lg.js +3 -0
  223. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_restore_route_actions_0-b05bv.js +3 -0
  224. package/.next/standalone/.next/server/chunks/lib_02iz_9q._.js +4 -0
  225. package/.next/standalone/.next/server/chunks/lib_05agvk3._.js +4 -0
  226. package/.next/standalone/.next/server/chunks/lib_0v84u66._.js +4 -0
  227. package/.next/standalone/.next/server/chunks/lib_db-client_0_dch35.js +174 -0
  228. package/.next/standalone/.next/server/chunks/lib_linkedin-export_12imqxg.js +1 -1
  229. package/.next/standalone/.next/server/chunks/lib_rpc_005abye.js +3 -0
  230. package/.next/standalone/.next/server/chunks/lib_rpc_0b17r6v.js +3 -0
  231. package/.next/standalone/.next/server/chunks/lib_rpc_0c9d9ti.js +7 -0
  232. package/.next/standalone/.next/server/chunks/lib_rpc_0doq0t-.js +3 -0
  233. package/.next/standalone/.next/server/chunks/lib_rpc_0fd2rlw.js +3 -0
  234. package/.next/standalone/.next/server/chunks/lib_rpc_0is4qoc.js +3 -0
  235. package/.next/standalone/.next/server/chunks/lib_rpc_0jnfp2e.js +3 -0
  236. package/.next/standalone/.next/server/chunks/lib_rpc_0nef_n7.js +3 -0
  237. package/.next/standalone/.next/server/chunks/lib_rpc_0plrzra.js +3 -0
  238. package/.next/standalone/.next/server/chunks/lib_rpc_13a4m0c.js +3 -0
  239. package/.next/standalone/.next/server/chunks/lib_rpc_1if17c-.js +3 -0
  240. package/.next/standalone/.next/server/chunks/lib_rpc_1j-zw7v.js +3 -0
  241. package/.next/standalone/.next/server/chunks/lib_rpc_1sngt-q.js +3 -0
  242. package/.next/standalone/.next/server/chunks/lib_rpc_1v2sgme.js +3 -0
  243. package/.next/standalone/.next/server/chunks/lib_rpc_1vh-tgx.js +3 -0
  244. package/.next/standalone/.next/server/chunks/lib_rpc_1zaubz7.js +3 -0
  245. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qd8pzm._.js +3 -0
  246. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0qdeuyo._.js → [root-of-the-server]__1-012q1._.js} +2 -2
  247. package/.next/standalone/.next/server/chunks/ssr/_01o3i5y._.js +7 -0
  248. package/.next/standalone/.next/server/chunks/ssr/_02sband._.js +7 -0
  249. package/.next/standalone/.next/server/chunks/ssr/_06rgzfh._.js +3 -0
  250. package/.next/standalone/.next/server/chunks/ssr/_07zb7lu._.js +3 -0
  251. package/.next/standalone/.next/server/chunks/ssr/_0_79idq._.js +3 -0
  252. package/.next/standalone/.next/server/chunks/ssr/_0gy11ar._.js +3 -0
  253. package/.next/standalone/.next/server/chunks/ssr/_0hb-dhy._.js +3 -0
  254. package/.next/standalone/.next/server/chunks/ssr/_14nxd3q._.js +3 -0
  255. package/.next/standalone/.next/server/chunks/ssr/_189g8lg._.js +3 -0
  256. package/.next/standalone/.next/server/chunks/ssr/_1f_n00p._.js +1 -1
  257. package/.next/standalone/.next/server/chunks/ssr/_1fm1ih_._.js +2 -2
  258. package/.next/standalone/.next/server/chunks/ssr/_1k2nmbw._.js +2 -2
  259. package/.next/standalone/.next/server/chunks/ssr/_1k9qfsk._.js +3 -0
  260. package/.next/standalone/.next/server/chunks/ssr/app_141w189._.js +1 -1
  261. package/.next/standalone/.next/server/chunks/ssr/app_components_0t908t-._.js +1 -1
  262. package/.next/standalone/.next/server/chunks/ssr/app_components_0uuff77._.js +25 -2
  263. package/.next/standalone/.next/server/chunks/ssr/app_components_1j3q-h5._.js +25 -2
  264. package/.next/standalone/.next/server/chunks/ssr/app_components_CompanyScores_1g0mytz.js +1 -1
  265. package/.next/standalone/.next/server/chunks/ssr/app_import_page_1fmu6_l.js +1 -1
  266. package/.next/standalone/.next/server/chunks/ssr/app_launch_page_19t0dyd.js +1 -1
  267. package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +25 -13
  268. package/.next/standalone/.next/server/chunks/ssr/app_paths_page_1ol90m7.js +2 -2
  269. package/.next/standalone/.next/server/chunks/ssr/app_profile_page_0u3-l5y.js +1 -1
  270. package/.next/standalone/.next/server/chunks/ssr/app_queue_page_0c6znd6.js +11 -11
  271. package/.next/standalone/.next/server/chunks/ssr/app_settings_page_1f8mjj_.js +1 -1
  272. package/.next/standalone/.next/server/chunks/ssr/app_setup_page_1-282zx.js +12 -13
  273. package/.next/standalone/.next/server/chunks/ssr/app_social_page_0h7zxda.js +1 -1
  274. package/.next/standalone/.next/server/chunks/ssr/{lib_1c4ieuw._.js → lib_csv_1ttiu_h.js} +2 -2
  275. package/.next/standalone/.next/server/chunks/ssr/lib_galaxy-lab_108_lu-.js +1 -1
  276. package/.next/standalone/.next/server/chunks/ssr/lib_separation_1305zsx.js +3 -0
  277. package/.next/standalone/.next/server/edge/chunks/[root-of-the-server]__0pco7a6._.js +1 -1
  278. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  279. package/.next/standalone/.next/server/middleware-manifest.json +5 -5
  280. package/.next/standalone/.next/server/pages/404.html +1 -1
  281. package/.next/standalone/.next/server/pages/500.html +1 -1
  282. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  283. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  284. package/.next/standalone/.next/static/chunks/03-_esd2x_yk6.js +1 -0
  285. package/.next/standalone/.next/static/chunks/03-demj2iy-0p.js +44 -0
  286. package/.next/standalone/.next/static/chunks/0_1r-3csplxnj.js +1 -0
  287. package/.next/standalone/.next/static/chunks/0an_b6zi1r_qq.js +5 -0
  288. package/.next/standalone/.next/static/chunks/0e3g0sil79cus.js +21 -0
  289. package/.next/standalone/.next/static/chunks/0kscsqnvfq3-r.js +1 -0
  290. package/.next/standalone/.next/static/chunks/0p3g5tfostsep.js +7 -0
  291. package/.next/standalone/.next/static/chunks/0zd0t7e60bn4z.js +1 -0
  292. package/.next/standalone/.next/static/chunks/163b-20vwa06i.js +34 -0
  293. package/.next/standalone/.next/static/chunks/{0ws7zy0w57ufi.js → 1eyajb9ntzlrl.js} +1 -1
  294. package/.next/standalone/.next/static/chunks/1pa-2v1ajvrko.js +1 -0
  295. package/.next/standalone/.next/static/chunks/1qbjermbf68xj.js +1 -0
  296. package/.next/standalone/.next/static/chunks/1z9lb-dbcg4aa.js +1 -0
  297. package/.next/standalone/.next/static/chunks/23_1z47al92nz.js +57 -0
  298. package/.next/standalone/.next/static/chunks/260bomtr214m8.js +34 -0
  299. package/.next/standalone/.next/static/chunks/2eo9pqq9gay3r.js +34 -0
  300. package/.next/standalone/.next/static/chunks/2xk2ra4piiuod.js +34 -0
  301. package/.next/standalone/.next/static/chunks/2z1-q0_vunbql.js +2 -0
  302. package/.next/standalone/.next/static/chunks/2zf4jmz9l3li2.js +1 -0
  303. package/.next/standalone/.next/static/chunks/34g73qhayuevu.js +1 -0
  304. package/.next/standalone/.next/static/chunks/3b0-14cxqsprt.js +1 -0
  305. package/.next/standalone/.next/static/chunks/3jarus1_38s2z.js +1 -0
  306. package/.next/standalone/.next/static/chunks/3ssu341hav_sq.css +3 -0
  307. package/.next/standalone/.next/static/chunks/3v1qd3sqhqn0d.js +1 -0
  308. package/.next/standalone/.next/static/chunks/43pg2sursiypz.js +1 -0
  309. package/.next/standalone/.next/static/chunks/44yn0tcd9dfk3.js +1 -0
  310. package/.next/standalone/CHANGELOG.md +143 -0
  311. package/.next/standalone/README.md +71 -49
  312. package/.next/standalone/SECURITY.md +17 -11
  313. package/.next/standalone/app/api/data/backup/route.js +25 -0
  314. package/.next/standalone/app/api/data/csv/route.js +74 -0
  315. package/.next/standalone/app/api/data/export/route.js +1 -1
  316. package/.next/standalone/app/api/data/restore/route.js +48 -0
  317. package/.next/standalone/app/api/data/reveal/route.js +19 -6
  318. package/.next/standalone/app/api/data/route.js +15 -4
  319. package/.next/standalone/app/api/ingest/route.js +1 -1
  320. package/.next/standalone/app/api/queue/route.js +1 -1
  321. package/.next/standalone/app/api/scraper/route.js +120 -32
  322. package/.next/standalone/app/api/social/crm/route.js +2 -1
  323. package/.next/standalone/app/components/AppHeader.js +20 -16
  324. package/.next/standalone/app/components/AppTabs.js +8 -8
  325. package/.next/standalone/app/components/AutoScanButton.js +2 -2
  326. package/.next/standalone/app/components/Avatar.js +1 -1
  327. package/.next/standalone/app/components/ChainView.js +184 -112
  328. package/.next/standalone/app/components/CirclePanel.js +16 -16
  329. package/.next/standalone/app/components/ClusterSpinner.js +64 -0
  330. package/.next/standalone/app/components/CompanyScores.js +20 -20
  331. package/.next/standalone/app/components/EmptyState.js +39 -18
  332. package/.next/standalone/app/components/FieldStep.js +15 -13
  333. package/.next/standalone/app/components/FilterPanel.js +17 -17
  334. package/.next/standalone/app/components/ForceGraph.js +49 -14
  335. package/.next/standalone/app/components/GalaxyLab.js +33 -33
  336. package/.next/standalone/app/components/GridView.js +18 -18
  337. package/.next/standalone/app/components/LegacyScoresCard.js +10 -11
  338. package/.next/standalone/app/components/LinkedInLimits.js +24 -19
  339. package/.next/standalone/app/components/LiquidGlass.js +99 -0
  340. package/.next/standalone/app/components/ListView.js +20 -20
  341. package/.next/standalone/app/components/MapControls.js +5 -5
  342. package/.next/standalone/app/components/MappingProgress.js +16 -16
  343. package/.next/standalone/app/components/NoteDetail.js +13 -13
  344. package/.next/standalone/app/components/OnboardingGate.js +4 -4
  345. package/.next/standalone/app/components/OutlinkQuest.js +25 -25
  346. package/.next/standalone/app/components/PathsAnalyzer.js +37 -36
  347. package/.next/standalone/app/components/PeopleMap.js +21 -21
  348. package/.next/standalone/app/components/RingsView.js +11 -11
  349. package/.next/standalone/app/components/ScanRadar.js +84 -39
  350. package/.next/standalone/app/components/ScanStatusBar.js +22 -18
  351. package/.next/standalone/app/components/ScanTrail.js +8 -5
  352. package/.next/standalone/app/components/SeparationView.js +168 -104
  353. package/.next/standalone/app/components/Sidebar.js +161 -161
  354. package/.next/standalone/app/components/StaleServerBanner.js +4 -4
  355. package/.next/standalone/app/components/TheirCircle.js +26 -26
  356. package/.next/standalone/app/components/ThemeDefs.js +42 -0
  357. package/.next/standalone/app/components/ThemeLoader.js +20 -1
  358. package/.next/standalone/app/components/UpdatePanel.js +22 -22
  359. package/.next/standalone/app/components/UserProvider.js +22 -15
  360. package/.next/standalone/app/components/settings/AppearanceSection.js +47 -24
  361. package/.next/standalone/app/components/settings/DataSection.js +276 -109
  362. package/.next/standalone/app/components/settings/NetworkHealthSection.js +13 -13
  363. package/.next/standalone/app/components/settings/SectorPicker.js +12 -12
  364. package/.next/standalone/app/components/settings/SectorSection.js +13 -14
  365. package/.next/standalone/app/components/settings/TierSection.js +9 -9
  366. package/.next/standalone/app/components/settings/TitleSection.js +11 -11
  367. package/.next/standalone/app/components/settings/UsageSection.js +313 -0
  368. package/.next/standalone/app/components/ui.js +8 -8
  369. package/.next/standalone/app/globals.css +159 -2
  370. package/.next/standalone/app/import/page.js +94 -38
  371. package/.next/standalone/app/launch/page.js +5 -5
  372. package/.next/standalone/app/layout.js +6 -2
  373. package/.next/standalone/app/page.js +53 -37
  374. package/.next/standalone/app/paths/page.js +63 -63
  375. package/.next/standalone/app/profile/page.js +58 -58
  376. package/.next/standalone/app/queue/page.js +54 -54
  377. package/.next/standalone/app/scores/page.js +2 -2
  378. package/.next/standalone/app/settings/page.js +16 -13
  379. package/.next/standalone/app/setup/page.js +221 -125
  380. package/.next/standalone/app/social/Crm.js +63 -62
  381. package/.next/standalone/app/social/SocialHub.js +22 -22
  382. package/.next/standalone/app/social/Thread.js +7 -7
  383. package/.next/standalone/app/social/page.js +2 -2
  384. package/.next/standalone/lib/backups.js +458 -0
  385. package/.next/standalone/lib/chain-layout.js +32 -0
  386. package/.next/standalone/lib/csv-store.js +131 -0
  387. package/.next/standalone/lib/csv.js +137 -39
  388. package/.next/standalone/lib/data-folder.js +19 -3
  389. package/.next/standalone/lib/data-import.js +5 -2
  390. package/.next/standalone/lib/db-client.js +78 -20
  391. package/.next/standalone/lib/demo.js +5 -4
  392. package/.next/standalone/lib/galaxy-export.js +9 -2
  393. package/.next/standalone/lib/galaxy-lab.js +19 -5
  394. package/.next/standalone/lib/galaxy-layouts.js +43 -0
  395. package/.next/standalone/lib/gate.js +10 -4
  396. package/.next/standalone/lib/ingest.js +1 -1
  397. package/.next/standalone/lib/linkedin-limits.js +212 -11
  398. package/.next/standalone/lib/liquid-glass.js +59 -0
  399. package/.next/standalone/lib/notifications.js +13 -0
  400. package/.next/standalone/lib/scan-pace.js +11 -0
  401. package/.next/standalone/lib/scan-progress.js +20 -0
  402. package/.next/standalone/lib/scan-risk.js +44 -0
  403. package/.next/standalone/lib/scanner-setup.js +97 -15
  404. package/.next/standalone/lib/scraper-client.js +17 -3
  405. package/.next/standalone/lib/search-risk.js +7 -3
  406. package/.next/standalone/lib/settings-client.js +5 -3
  407. package/.next/standalone/lib/settings.js +10 -0
  408. package/.next/standalone/lib/social-store.js +3 -2
  409. package/.next/standalone/lib/synced-setting.js +46 -0
  410. package/.next/standalone/lib/theme-store.js +42 -10
  411. package/.next/standalone/lib/themes.js +111 -21
  412. package/.next/standalone/lib/usage.js +195 -0
  413. package/.next/standalone/package-lock.json +2 -2
  414. package/.next/standalone/package.json +1 -1
  415. package/.next/standalone/scripts/scrape.py +26 -2
  416. package/.next/static/chunks/03-_esd2x_yk6.js +1 -0
  417. package/.next/static/chunks/03-demj2iy-0p.js +44 -0
  418. package/.next/static/chunks/0_1r-3csplxnj.js +1 -0
  419. package/.next/static/chunks/0an_b6zi1r_qq.js +5 -0
  420. package/.next/static/chunks/0e3g0sil79cus.js +21 -0
  421. package/.next/static/chunks/0kscsqnvfq3-r.js +1 -0
  422. package/.next/static/chunks/0p3g5tfostsep.js +7 -0
  423. package/.next/static/chunks/0zd0t7e60bn4z.js +1 -0
  424. package/.next/static/chunks/163b-20vwa06i.js +34 -0
  425. package/.next/static/chunks/{0ws7zy0w57ufi.js → 1eyajb9ntzlrl.js} +1 -1
  426. package/.next/static/chunks/1pa-2v1ajvrko.js +1 -0
  427. package/.next/static/chunks/1qbjermbf68xj.js +1 -0
  428. package/.next/static/chunks/1z9lb-dbcg4aa.js +1 -0
  429. package/.next/static/chunks/23_1z47al92nz.js +57 -0
  430. package/.next/static/chunks/260bomtr214m8.js +34 -0
  431. package/.next/static/chunks/2eo9pqq9gay3r.js +34 -0
  432. package/.next/static/chunks/2xk2ra4piiuod.js +34 -0
  433. package/.next/static/chunks/2z1-q0_vunbql.js +2 -0
  434. package/.next/static/chunks/2zf4jmz9l3li2.js +1 -0
  435. package/.next/static/chunks/34g73qhayuevu.js +1 -0
  436. package/.next/static/chunks/3b0-14cxqsprt.js +1 -0
  437. package/.next/static/chunks/3jarus1_38s2z.js +1 -0
  438. package/.next/static/chunks/3ssu341hav_sq.css +3 -0
  439. package/.next/static/chunks/3v1qd3sqhqn0d.js +1 -0
  440. package/.next/static/chunks/43pg2sursiypz.js +1 -0
  441. package/.next/static/chunks/44yn0tcd9dfk3.js +1 -0
  442. package/CHANGELOG.md +143 -0
  443. package/README.md +71 -49
  444. package/SECURITY.md +17 -11
  445. package/lib/backups.js +458 -0
  446. package/lib/chain-layout.js +32 -0
  447. package/lib/csv-store.js +131 -0
  448. package/lib/csv.js +137 -39
  449. package/lib/data-folder.js +19 -3
  450. package/lib/data-import.js +5 -2
  451. package/lib/db-client.js +78 -20
  452. package/lib/demo.js +5 -4
  453. package/lib/galaxy-export.js +9 -2
  454. package/lib/galaxy-lab.js +19 -5
  455. package/lib/galaxy-layouts.js +43 -0
  456. package/lib/gate.js +10 -4
  457. package/lib/ingest.js +1 -1
  458. package/lib/linkedin-limits.js +212 -11
  459. package/lib/liquid-glass.js +59 -0
  460. package/lib/notifications.js +13 -0
  461. package/lib/scan-pace.js +11 -0
  462. package/lib/scan-progress.js +20 -0
  463. package/lib/scan-risk.js +44 -0
  464. package/lib/scanner-setup.js +97 -15
  465. package/lib/scraper-client.js +17 -3
  466. package/lib/search-risk.js +7 -3
  467. package/lib/settings-client.js +5 -3
  468. package/lib/settings.js +10 -0
  469. package/lib/social-store.js +3 -2
  470. package/lib/synced-setting.js +46 -0
  471. package/lib/theme-store.js +42 -10
  472. package/lib/themes.js +111 -21
  473. package/lib/usage.js +195 -0
  474. package/package.json +1 -1
  475. package/scripts/scrape.py +26 -2
  476. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-rnla2._.js +0 -3
  477. package/.next/standalone/.next/server/chunks/[root-of-the-server]__14ou7j5._.js +0 -3
  478. package/.next/standalone/.next/server/chunks/[root-of-the-server]__16iu0hv._.js +0 -3
  479. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1kbl21f._.js +0 -3
  480. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rphsdk._.js +0 -3
  481. package/.next/standalone/.next/server/chunks/lib_0851sk0._.js +0 -8
  482. package/.next/standalone/.next/server/chunks/lib_1q7p2ro._.js +0 -8
  483. package/.next/standalone/.next/server/chunks/lib_1r6l86l._.js +0 -8
  484. package/.next/standalone/.next/server/chunks/lib_db-client_15le7cw.js +0 -174
  485. package/.next/standalone/.next/server/chunks/lib_rpc_04s8mzr.js +0 -3
  486. package/.next/standalone/.next/server/chunks/lib_rpc_053z7as.js +0 -3
  487. package/.next/standalone/.next/server/chunks/lib_rpc_0b_-2te.js +0 -3
  488. package/.next/standalone/.next/server/chunks/lib_rpc_0dhbxdm.js +0 -3
  489. package/.next/standalone/.next/server/chunks/lib_rpc_0dxlk31.js +0 -3
  490. package/.next/standalone/.next/server/chunks/lib_rpc_0f8b-qc.js +0 -3
  491. package/.next/standalone/.next/server/chunks/lib_rpc_0pzie7_.js +0 -3
  492. package/.next/standalone/.next/server/chunks/lib_rpc_0r76fq_.js +0 -3
  493. package/.next/standalone/.next/server/chunks/lib_rpc_0ut7pjp.js +0 -3
  494. package/.next/standalone/.next/server/chunks/lib_rpc_15zyqaz.js +0 -3
  495. package/.next/standalone/.next/server/chunks/lib_rpc_18zpjtq.js +0 -3
  496. package/.next/standalone/.next/server/chunks/lib_rpc_1a8xkiz.js +0 -3
  497. package/.next/standalone/.next/server/chunks/lib_rpc_1e_55xo.js +0 -3
  498. package/.next/standalone/.next/server/chunks/lib_rpc_1oxfd1_.js +0 -3
  499. package/.next/standalone/.next/server/chunks/lib_rpc_1s0lod0.js +0 -3
  500. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__08oxiqh._.js +0 -3
  501. package/.next/standalone/.next/server/chunks/ssr/_03l7vge._.js +0 -3
  502. package/.next/standalone/.next/server/chunks/ssr/_08g31gm._.js +0 -3
  503. package/.next/standalone/.next/server/chunks/ssr/_0gk_ofx._.js +0 -3
  504. package/.next/standalone/.next/server/chunks/ssr/_0nwsf93._.js +0 -3
  505. package/.next/standalone/.next/server/chunks/ssr/_0vho1lb._.js +0 -3
  506. package/.next/standalone/.next/server/chunks/ssr/_1-658fq._.js +0 -3
  507. package/.next/standalone/.next/server/chunks/ssr/_1bc46kz._.js +0 -3
  508. package/.next/standalone/.next/server/chunks/ssr/_2105jz8._.js +0 -3
  509. package/.next/standalone/.next/server/chunks/ssr/app_components_settings_SectorPicker_1c-29qw.js +0 -3
  510. package/.next/standalone/.next/static/chunks/02pq76u7y4v9-.js +0 -22
  511. package/.next/standalone/.next/static/chunks/0cmq0exd4d0h9.js +0 -1
  512. package/.next/standalone/.next/static/chunks/0i02yxppzds1o.js +0 -1
  513. package/.next/standalone/.next/static/chunks/0m_p4k-q2qh--.js +0 -1
  514. package/.next/standalone/.next/static/chunks/0oyslj62jkubd.js +0 -1
  515. package/.next/standalone/.next/static/chunks/0vo-l8hxneba6.css +0 -3
  516. package/.next/standalone/.next/static/chunks/0yh8z2tbrc5i_.js +0 -1
  517. package/.next/standalone/.next/static/chunks/17-rhp8sg4m1b.js +0 -44
  518. package/.next/standalone/.next/static/chunks/172e10mi-tpo_.js +0 -34
  519. package/.next/standalone/.next/static/chunks/1ei5vbe2uw6fl.js +0 -1
  520. package/.next/standalone/.next/static/chunks/1f7_pl_wq7lh3.js +0 -11
  521. package/.next/standalone/.next/static/chunks/1jzbe7zdx9vbj.js +0 -2
  522. package/.next/standalone/.next/static/chunks/1m3017gp790pw.js +0 -45
  523. package/.next/standalone/.next/static/chunks/1t20e8u0st7ep.js +0 -1
  524. package/.next/standalone/.next/static/chunks/2-ch9rm27eril.js +0 -11
  525. package/.next/standalone/.next/static/chunks/2ldv-v3s9yaif.js +0 -1
  526. package/.next/standalone/.next/static/chunks/3bp284gjf7dyq.js +0 -1
  527. package/.next/standalone/.next/static/chunks/3k1f6clbn3gj3.js +0 -7
  528. package/.next/standalone/.next/static/chunks/3l4t8je6iguzc.js +0 -1
  529. package/.next/standalone/.next/static/chunks/3tplzuc9jk-tl.js +0 -1
  530. package/.next/standalone/.next/static/chunks/42m0bqr8pbovz.js +0 -11
  531. package/.next/static/chunks/02pq76u7y4v9-.js +0 -22
  532. package/.next/static/chunks/0cmq0exd4d0h9.js +0 -1
  533. package/.next/static/chunks/0i02yxppzds1o.js +0 -1
  534. package/.next/static/chunks/0m_p4k-q2qh--.js +0 -1
  535. package/.next/static/chunks/0oyslj62jkubd.js +0 -1
  536. package/.next/static/chunks/0vo-l8hxneba6.css +0 -3
  537. package/.next/static/chunks/0yh8z2tbrc5i_.js +0 -1
  538. package/.next/static/chunks/17-rhp8sg4m1b.js +0 -44
  539. package/.next/static/chunks/172e10mi-tpo_.js +0 -34
  540. package/.next/static/chunks/1ei5vbe2uw6fl.js +0 -1
  541. package/.next/static/chunks/1f7_pl_wq7lh3.js +0 -11
  542. package/.next/static/chunks/1jzbe7zdx9vbj.js +0 -2
  543. package/.next/static/chunks/1m3017gp790pw.js +0 -45
  544. package/.next/static/chunks/1t20e8u0st7ep.js +0 -1
  545. package/.next/static/chunks/2-ch9rm27eril.js +0 -11
  546. package/.next/static/chunks/2ldv-v3s9yaif.js +0 -1
  547. package/.next/static/chunks/3bp284gjf7dyq.js +0 -1
  548. package/.next/static/chunks/3k1f6clbn3gj3.js +0 -7
  549. package/.next/static/chunks/3l4t8je6iguzc.js +0 -1
  550. package/.next/static/chunks/3tplzuc9jk-tl.js +0 -1
  551. package/.next/static/chunks/42m0bqr8pbovz.js +0 -11
  552. /package/.next/standalone/.next/static/{dQUvvVSXqbkEFC3-CNcwT → ZVpLBK-2vpllv2HxOFs2d}/_buildManifest.js +0 -0
  553. /package/.next/standalone/.next/static/{dQUvvVSXqbkEFC3-CNcwT → ZVpLBK-2vpllv2HxOFs2d}/_clientMiddlewareManifest.js +0 -0
  554. /package/.next/standalone/.next/static/{dQUvvVSXqbkEFC3-CNcwT → ZVpLBK-2vpllv2HxOFs2d}/_ssgManifest.js +0 -0
  555. /package/.next/static/{dQUvvVSXqbkEFC3-CNcwT → ZVpLBK-2vpllv2HxOFs2d}/_buildManifest.js +0 -0
  556. /package/.next/static/{dQUvvVSXqbkEFC3-CNcwT → ZVpLBK-2vpllv2HxOFs2d}/_clientMiddlewareManifest.js +0 -0
  557. /package/.next/static/{dQUvvVSXqbkEFC3-CNcwT → ZVpLBK-2vpllv2HxOFs2d}/_ssgManifest.js +0 -0
@@ -12,21 +12,25 @@ This app is designed to run **on your own machine, against your own network**.
12
12
 
13
13
  - The web UI binds to localhost. It is not hardened for exposure to the
14
14
  internet, and it has no multi-user authentication or per-user authorization.
15
- - Ten API routes are gated (`admin-delete`, `admin-update`, `delete-cluster`,
16
- `setup-profile`, `scraper`, `update`, and Settings → Your data's
17
- `data/export`, `data/import`, `data/restart`, `data/reveal`). The first four
18
- can irreversibly destroy or rewrite data, `scraper` starts processes, and
19
- `update` changes the code that runs next. `data/export` hands over the whole
15
+ - Thirteen API routes are gated (`admin-delete`, `admin-update`, `delete-cluster`,
16
+ `setup-profile`, `scraper`, `update`, Settings → Your data's
17
+ `data/export`, `data/import`, `data/restart`, `data/reveal`, `data/backup`,
18
+ `data/restore`, and `data/csv`). The first four can irreversibly destroy or rewrite data,
19
+ `scraper` starts processes, and `update` changes the code that runs next. `data/export` hands over the whole
20
20
  network in one file, `data/import` replaces it, `data/restart` stops the
21
- server, and `data/reveal` starts a process (Finder, or the Linux file
22
- browser, on the data folder's own path). While the server is bound to
21
+ server, `data/reveal` starts a process (Finder, or the Linux file
22
+ browser, on the data folder's own path or a backup in it), `data/backup`
23
+ writes the whole network to a file in `backups/`, `data/restore`
24
+ replaces the network with one of those backups, named as `backups/` lists
25
+ it, never by a path from the request, and `data/csv` keeps, hands over and
26
+ removes a LinkedIn CSV import kept in the data folder. While the server is bound to
23
27
  127.0.0.1 they need no token — anyone who can reach it can already open the
24
28
  database file directly, so a token there adds friction rather than safety. If
25
29
  it is bound to any other address, every caller must send `ADMIN_TOKEN` as a
26
30
  bearer, including this machine and the app's own buttons, and the routes
27
31
  refuse to run when it is unset. Reading the data folder's facts
28
- (`GET /api/data`: its path and sizes) changes nothing and stays open, like
29
- every other read.
32
+ (`GET /api/data`: its path, sizes and backups) changes nothing and stays
33
+ open, like every other read.
30
34
  - A localhost-bound service is still reachable by any web page you visit — the
31
35
  binding keeps other machines out, not your own browser. Every mutating API
32
36
  request is therefore refused when the browser reports it came from another
@@ -113,8 +117,10 @@ This app is designed to run **on your own machine, against your own network**.
113
117
 
114
118
  Everything stays local:
115
119
 
116
- - A CSV import is parsed in the browser and held for that tab only. It is never
117
- uploaded and never written to a database.
120
+ - A CSV import is parsed in the browser. Only what the map needs about each
121
+ person (no email addresses) goes to the app on this computer, which keeps it
122
+ in the data folder as `csv-network.json` until you remove it, apart from the
123
+ database. It is never uploaded anywhere.
118
124
  - Scanned data and cached avatars are written to your machine and are gitignored.
119
125
  The app shows photos only from those files, so looking at your network never
120
126
  contacts LinkedIn.
@@ -0,0 +1,25 @@
1
+ import { getDb, backupOptions } from '../../../../lib/db-client';
2
+ import { makeBackup, noteBackupFailure } from '../../../../lib/backups';
3
+ import { countPeople } from '../../../../lib/data-export';
4
+
5
+ // Settings → Your data → Back up now: a backup in backups/ like the daily ones
6
+ // (lib/backups.js), kept until the person deletes it. Nothing is taken from
7
+ // the request. Gated (lib/gate.js) with the routes that hand over or replace
8
+ // the whole network: it writes all of it to a file.
9
+
10
+ export async function POST() {
11
+ const db = getDb();
12
+ if (countPeople(db) === 0) {
13
+ return Response.json({ error: 'There’s no network here to back up yet.' }, { status: 409 });
14
+ }
15
+ try {
16
+ const made = makeBackup('manual', backupOptions(db));
17
+ return Response.json({
18
+ ok: true,
19
+ backup: { name: made.name, bytes: made.bytes, people: made.people, photos: made.photos, verified: made.verified },
20
+ });
21
+ } catch (err) {
22
+ noteBackupFailure('manual', err);
23
+ return Response.json({ error: `The backup couldn’t be made: ${err.message}` }, { status: 500 });
24
+ }
25
+ }
@@ -0,0 +1,74 @@
1
+ import { dataDir } from '../../../../lib/db-client';
2
+ import { pendingImport } from '../../../../lib/data-import';
3
+ import { resolveProfile, networkCounts } from '../../../../lib/profile';
4
+ import {
5
+ readCsvNetwork, writeCsvNetwork, removeCsvNetwork, CsvStoreError, CSV_NETWORK_FILE,
6
+ } from '../../../../lib/csv-store';
7
+
8
+ // A LinkedIn Connections.csv import, kept in the data folder so it is still
9
+ // there after the window closes (lib/csv-store.js). The page reads the CSV and
10
+ // sends only what the map needs (lib/csv.js packConnections); nothing here
11
+ // sees the file itself.
12
+ //
13
+ // Gated with the other routes under /api/data (lib/gate.js): POST replaces the
14
+ // kept import, DELETE removes it, and GET hands it over, so all three answer
15
+ // only on this computer, as the server's bind address proves, never a header
16
+ // (TRAPS §2). POST and DELETE are writes, so middleware.js also refuses them
17
+ // from another site.
18
+
19
+ export async function GET() {
20
+ const { csv, problem } = readCsvNetwork(dataDir());
21
+ // Your scanned 1st-degree connections, under the profile the map shows
22
+ // (lib/profile.js): once there are any, pages show them instead of a kept
23
+ // CSV (lib/csv.js openNetworkSource).
24
+ let scanned;
25
+ try {
26
+ const me = resolveProfile({ create: false });
27
+ scanned = me ? networkCounts(me.id).first : 0;
28
+ } catch (err) {
29
+ return Response.json({ error: `Your network couldn't be read (${err.message}).` }, { status: 500 });
30
+ }
31
+ return Response.json({
32
+ csv,
33
+ scanned,
34
+ // Said, never shown as no import at all (TRAPS §7): the welcome screen
35
+ // puts this on the CSV card.
36
+ problem: problem ? `Your kept CSV import couldn't be read: ${problem}. Import Connections.csv again to replace it.` : null,
37
+ });
38
+ }
39
+
40
+ export async function POST(request) {
41
+ const dir = dataDir();
42
+ // An import from another computer waiting for the next start replaces the
43
+ // network's files, this one included: a CSV kept now would be set aside
44
+ // with what it replaces.
45
+ if (pendingImport(dir)) {
46
+ return Response.json({
47
+ error: 'A copy of a network is waiting to finish importing. Restart Six Degrees to finish it first (Settings → Your data says how), then import the CSV.',
48
+ }, { status: 409 });
49
+ }
50
+ let body;
51
+ try {
52
+ body = await request.json();
53
+ } catch {
54
+ return Response.json({ error: "The import didn't arrive whole, so nothing was kept. Try again." }, { status: 400 });
55
+ }
56
+ try {
57
+ return Response.json({ ok: true, ...writeCsvNetwork(dir, body?.connections) });
58
+ } catch (err) {
59
+ if (err instanceof CsvStoreError) {
60
+ return Response.json({ error: `This import can't be kept (${err.message}), so nothing was saved.` }, { status: 400 });
61
+ }
62
+ return Response.json({ error: `The import couldn't be saved on this computer (${err.message}).` }, { status: 500 });
63
+ }
64
+ }
65
+
66
+ export async function DELETE() {
67
+ try {
68
+ return Response.json({ ok: true, removed: removeCsvNetwork(dataDir()) });
69
+ } catch (err) {
70
+ return Response.json({
71
+ error: `The import couldn't be removed (${err.message}). It is ${CSV_NETWORK_FILE} in your data folder.`,
72
+ }, { status: 500 });
73
+ }
74
+ }
@@ -7,7 +7,7 @@ import { EXPORT_WORK_PREFIX, sweepLeftovers } from '../../../../lib/data-folder'
7
7
  import { SCHEMA_SQL } from '../../../../db/schema';
8
8
  import { APP_VERSION } from '../../../../lib/app-version';
9
9
 
10
- // Save a copy of the network to carry to another computer: one .sixdegrees
10
+ // Export backup file…: a copy of the network to carry to another computer, one .sixdegrees
11
11
  // file (lib/data-export.js), sent back as a download. A POST, so it takes a
12
12
  // click on the app's own page (the cross-site guard applies), and gated with
13
13
  // the other routes that hand over or replace everything (lib/gate.js).
@@ -0,0 +1,48 @@
1
+ import path from 'node:path';
2
+ import { getDb, dataDir, applySchema, backupsFolder } from '../../../../lib/db-client';
3
+ import { SCHEMA_SQL } from '../../../../db/schema';
4
+ import { APP_VERSION } from '../../../../lib/app-version';
5
+ import { countPeople } from '../../../../lib/data-export';
6
+ import { ImportError, pendingImport } from '../../../../lib/data-import';
7
+ import { findBackup, restoreBackup, restorePreflight } from '../../../../lib/backups';
8
+ import { scannerJob } from '../../../../lib/scan-state';
9
+
10
+ // Settings → Your data → Restore, on one backup: put that backup's network
11
+ // back. The same as importing it (lib/backups.js restoreBackup, through
12
+ // stageImport): checked first, applied at the next start (Restart now), and
13
+ // what is here kept in backups/ before anything is replaced.
14
+ //
15
+ // The body names a backup, {name, replace}: a name from backups/' own listing
16
+ // (lib/data-folder.js listBackups), never a path. Anything else is refused.
17
+ // `replace` is the number of people the person agreed to replace. Gated
18
+ // (lib/gate.js): it replaces the network.
19
+
20
+ export async function POST(request) {
21
+ let body = {};
22
+ try { body = await request.json(); } catch { /* refused below */ }
23
+ const name = typeof body?.name === 'string' ? body.name : '';
24
+
25
+ // The name first: one the folder doesn't hold is refused before anything else is asked.
26
+ if (!findBackup(backupsFolder(), name)) {
27
+ return Response.json({ error: 'There is no backup by that name in the backups folder.' }, { status: 404 });
28
+ }
29
+ const dir = path.resolve(dataDir());
30
+ const currentPeople = countPeople(getDb());
31
+ const refusal = restorePreflight({
32
+ scanRunning: scannerJob(),
33
+ pending: pendingImport(dir),
34
+ currentPeople,
35
+ confirmedPeople: Number(body?.replace),
36
+ });
37
+ if (refusal) return Response.json({ error: refusal.message, ...refusal.extra }, { status: refusal.status });
38
+
39
+ try {
40
+ const pending = restoreBackup(name, {
41
+ dir, backupsDir: backupsFolder(), applySchema, schemaSql: SCHEMA_SQL, appVersion: APP_VERSION, replacedPeople: currentPeople,
42
+ });
43
+ return Response.json({ ok: true, pending });
44
+ } catch (err) {
45
+ if (err instanceof ImportError) return Response.json({ error: err.message, ...err.extra }, { status: err.status });
46
+ return Response.json({ error: `The backup couldn’t be restored: ${err.message}` }, { status: 500 });
47
+ }
48
+ }
@@ -1,14 +1,27 @@
1
1
  import path from 'node:path';
2
- import { dataDir } from '../../../../lib/db-client';
2
+ import { dataDir, backupsFolder } from '../../../../lib/db-client';
3
3
  import { revealFolder } from '../../../../lib/data-folder';
4
+ import { findBackup } from '../../../../lib/backups';
4
5
 
5
- // Show the data folder in Finder (or the Linux file browser). It opens the data
6
- // folder itself and takes nothing from the request. Gated (lib/gate.js) like
7
- // every route that starts a process.
6
+ // Show the data folder in Finder (or the Linux file browser), or one backup in
7
+ // it, selected: {backup: name}, a name from backups/' own listing, never a
8
+ // path (lib/backups.js findBackup). Nothing else is taken from the request.
9
+ // Gated (lib/gate.js) like every route that starts a process.
8
10
 
9
- export async function POST() {
11
+ export async function POST(request) {
12
+ let body = {};
13
+ try { body = await request.json(); } catch { /* no body: the data folder */ }
14
+ if (body?.backup !== undefined) {
15
+ const folder = path.resolve(backupsFolder());
16
+ const found = findBackup(folder, body.backup, { restorable: false });
17
+ if (!found) return Response.json({ error: 'There is no backup by that name in the backups folder.' }, { status: 404 });
18
+ const file = path.join(folder, found.name);
19
+ const result = await revealFolder(folder, { select: file });
20
+ if (result.ok) return Response.json({ ok: true });
21
+ return Response.json({ error: `${result.message} The backup is ${file}`, path: file }, { status: 500 });
22
+ }
10
23
  const dir = path.resolve(dataDir());
11
24
  const result = await revealFolder(dir);
12
25
  if (result.ok) return Response.json({ ok: true });
13
- return Response.json({ error: `${result.message} The folder is ${dir}` }, { status: 500 });
26
+ return Response.json({ error: `${result.message} The folder is ${dir}`, path: dir }, { status: 500 });
14
27
  }
@@ -1,7 +1,10 @@
1
1
  import path from 'node:path';
2
2
  import { homedir } from 'node:os';
3
- import { getDb, dataDir, dbFile, AUTO_BACKUP_PREFIX } from '../../../lib/db-client';
3
+ import { getDb, dataDir, dbFile, backupsFolder, applySchema, AUTO_BACKUP_PREFIX } from '../../../lib/db-client';
4
4
  import { folderReport } from '../../../lib/data-folder';
5
+ import { backupReport } from '../../../lib/backups';
6
+ import { SCHEMA_SQL } from '../../../db/schema';
7
+ import { APP_VERSION } from '../../../lib/app-version';
5
8
  import { countPeople, referencedPhotos } from '../../../lib/data-export';
6
9
  import {
7
10
  pendingImport, lastImport, restartCodeFrom, restartAdvice, MAX_IMPORT_BYTES,
@@ -9,9 +12,11 @@ import {
9
12
  import { projectRoot, isGitCheckout } from '../../../lib/paths';
10
13
  import { installKind } from '../../../lib/release';
11
14
 
12
- // Settings → Your data: where the network is kept, what it takes up, and any
13
- // import waiting to finish. Sizes come from the file system; nothing in the
14
- // folder is read, and chrome-profile/ is only reported as there or not. A read
15
+ // Settings → Your data: where the network is kept, what it takes up, the
16
+ // backups, and any import waiting to finish. Sizes come from the file system,
17
+ // and chrome-profile/ is only reported as there or not. The one file read is
18
+ // the newest backup, checked as the importer would check it (once per file per
19
+ // server, lib/backups.js backupReport), so "verified" is never a guess. A read
15
20
  // that changes nothing, so it stays open like every other read. The actions
16
21
  // live under /api/data/… and are gated (lib/gate.js).
17
22
 
@@ -22,8 +27,14 @@ export async function GET() {
22
27
  // A git checkout is its own kind here, as on the rest of the Settings page.
23
28
  const kind = isGitCheckout() ? 'git' : installKind(process.env, projectRoot());
24
29
  const custom = dir !== path.join(homedir(), '.six-degrees');
30
+ // One entry per backup (a database copy and its folder of photos are one), newest first.
31
+ const { backups, ...backupStatus } = backupReport(path.resolve(backupsFolder()), {
32
+ applySchema, schemaSql: SCHEMA_SQL, appVersion: APP_VERSION,
33
+ });
25
34
  return Response.json({
26
35
  ...folderReport({ dir, dbFile: path.resolve(dbFile()), autoPrefix: AUTO_BACKUP_PREFIX, inNetwork: referencedPhotos(db) }),
36
+ backups,
37
+ backupStatus,
27
38
  people: countPeople(db),
28
39
  platform: process.platform,
29
40
  kind,
@@ -322,7 +322,7 @@ export async function POST(request) {
322
322
  user_id: userId || null,
323
323
  type: 'request_accepted',
324
324
  title: `${p.name} accepted! +${XP_ACCEPT[p.tier] || 5} XP`,
325
- message: `${p.tier}-Tier connection — bridge their cluster to reach D3`,
325
+ message: `${p.tier}-Tier connection: bridge their cluster to reach D3`,
326
326
  icon: '🤝',
327
327
  data: { personId: p.id, viaId: p.source_connection_id ?? null, tier: p.tier ?? null },
328
328
  }))
@@ -59,7 +59,7 @@ export async function POST(request) {
59
59
  await supabase.from('notifications').insert([{
60
60
  type: 'connection_accepted',
61
61
  title: `${item.name} accepted!`,
62
- message: `+${item.xp_reward} XP — Ready to scan their cluster`,
62
+ message: `+${item.xp_reward} XP · Ready to scan their cluster`,
63
63
  icon: '🎉',
64
64
  }]);
65
65
  }
@@ -3,16 +3,19 @@ import { existsSync, readFileSync, mkdirSync, mkdtempSync, rmSync } from 'node:f
3
3
  import path from 'node:path';
4
4
  import { projectRoot, dataDir } from '../../../lib/paths';
5
5
  import { resolveProfile, networkCounts } from '../../../lib/profile';
6
- import { scanProgress } from '../../../lib/scan-progress';
7
- import { linkedinState, writeLimits, liftCooldown } from '../../../lib/linkedin-limits';
6
+ import { scanProgress, mappingNow } from '../../../lib/scan-progress';
7
+ import { linkedinState, linkedinUsage, writeLimits, liftCooldown } from '../../../lib/linkedin-limits';
8
8
  import { pausedList, readProgress, readUnclear } from '../../../lib/paused';
9
- import { getDb } from '../../../lib/db-client';
9
+ import { getDb, backUpDailyIfDue } from '../../../lib/db-client';
10
10
  import { db as notesDb } from '../../../lib/db';
11
11
  import { scanDoneNotification } from '../../../lib/notifications';
12
12
  import { registerScanState } from '../../../lib/scan-state';
13
13
  import { pendingImport } from '../../../lib/data-import';
14
14
  import { waitingPhotoCount } from '../../../lib/photos';
15
+ import { readSettings } from '../../../lib/settings';
16
+ import { riskAccepted, touchesLinkedIn, RISK_REFUSAL } from '../../../lib/scan-risk';
15
17
  import { reachIndex, circleState } from '../../../lib/reach';
18
+ import { chromeInstalled, signedInFrom, SIGNED_IN_FILE, CHROME_REFUSAL } from '../../../lib/scanner-setup';
16
19
  import {
17
20
  pythonLooker, thisHostKey, scannerCommand, installSteps, downloadedPython, downloadVerified,
18
21
  placeDownloadedPython, sweepSetupLeftovers, megabytes, SETUP_WORK_PREFIX, ScannerSetupError,
@@ -47,6 +50,7 @@ const state = registerScanState({
47
50
  stderrTail: [],
48
51
  failure: null, // the last lines of stderr from a run that failed — its reason
49
52
  pages: 0, // pages the running scan has read: the dots along the header's line (app/components/ScanTrail.js)
53
+ found: [], // how many people each of those pages found: the Scan page's cluster (app/components/ScanRadar.js)
50
54
  });
51
55
 
52
56
  // A page read, as scripts/scrape.py prints it: " Page 3... " as a circle or a
@@ -54,6 +58,10 @@ const state = registerScanState({
54
58
  // people of your own connections list. Counted as the lines arrive, since the
55
59
  // log only keeps its last MAX_LOG lines.
56
60
  const PAGE_READ = /^\s*Page \d+\.\.\.|\d+\s*\/\s*\d+\s+collected/;
61
+ // What a page found, which the scanner prints after "Page N... " once it's read:
62
+ // "10 found (total: 30)" in a circle, "7 found (2 with images)" for a company.
63
+ const PAGE_FOUND = /(\d+) found \((?:total: \d+|\d+ with images)\)/;
64
+ const MAX_PAGES_KEPT = 400;
57
65
 
58
66
  /** Stop the running job without orphaning the browser it opened.
59
67
  *
@@ -83,7 +91,7 @@ function stopChild() {
83
91
  spawn('taskkill', ['/pid', String(pid), '/T'], { stdio: 'ignore', windowsHide: true }).on('error', () => {});
84
92
  setTimeout(() => {
85
93
  if (state.child && state.child.pid === pid) {
86
- push('Still running — forcing it.');
94
+ push('Still running. Forcing it to stop.');
87
95
  spawn('taskkill', ['/pid', String(pid), '/T', '/F'], { stdio: 'ignore', windowsHide: true }).on('error', () => {});
88
96
  }
89
97
  }, 5000);
@@ -94,7 +102,7 @@ function stopChild() {
94
102
 
95
103
  setTimeout(() => {
96
104
  if (state.child && state.child.pid === pid) {
97
- push('Still running — forcing it.');
105
+ push('Still running. Forcing it to stop.');
98
106
  try { process.kill(-pid, 'SIGKILL'); }
99
107
  catch { try { child.kill('SIGKILL'); } catch {} }
100
108
  }
@@ -106,7 +114,14 @@ function push(line) {
106
114
  const t = part.replace(/\s+$/, '');
107
115
  if (!t) continue;
108
116
  state.log.push(t);
109
- if (PAGE_READ.test(t)) state.pages += 1;
117
+ if (PAGE_READ.test(t)) {
118
+ state.pages += 1;
119
+ // Fifty of your own list at a time; a page's count comes on its next line.
120
+ state.found.push(/collected/.test(t) ? 50 : 0);
121
+ if (state.found.length > MAX_PAGES_KEPT) state.found.splice(0, state.found.length - MAX_PAGES_KEPT);
122
+ }
123
+ const got = t.match(PAGE_FOUND);
124
+ if (got && state.found.length) state.found[state.found.length - 1] = Number(got[1]);
110
125
  }
111
126
  if (state.log.length > MAX_LOG) state.log.splice(0, state.log.length - MAX_LOG);
112
127
  }
@@ -208,12 +223,12 @@ function pickedPerson(id) {
208
223
  }
209
224
  }
210
225
 
211
- // The machine checks (Python, Chrome, signed in) spawn processes, so they are
212
- // cached for a few seconds, and callers that arrive while a look is under way
213
- // share it rather than each starting their own Pythons. Everything about the
214
- // running job — its log, how far it has got — and the counts are read fresh on
215
- // every call: the page polls every 1.5 s, and a progress bar that moves every
216
- // 4 s looks stuck.
226
+ // The look for a Python spawns processes, so it is cached for a few seconds,
227
+ // and callers that arrive while a look is under way share it rather than each
228
+ // starting their own Pythons. Everything else (Chrome and signed in, which are
229
+ // file checks; the running job, its log, how far it has got; the counts) is
230
+ // read fresh on every call: the page polls every 1.5 s, a progress bar that
231
+ // moves every 4 s looks stuck, and step 1 ticks the moment Chrome is installed.
217
232
  let cached = { at: 0, value: null };
218
233
  let looking = null;
219
234
  let lookGeneration = 0;
@@ -251,26 +266,38 @@ async function look() {
251
266
  host: hostOnce(),
252
267
  });
253
268
 
254
- // Where Playwright's "chrome" channel looks for Google Chrome (Chromium doesn't count).
255
- const chrome =
256
- process.platform === 'darwin' ? existsSync('/Applications/Google Chrome.app')
257
- : process.platform === 'linux' ? existsSync('/opt/google/chrome/chrome')
258
- : process.platform === 'win32' ? windowsChrome()
259
- : true; // elsewhere Playwright resolves the channel itself
269
+ return { root, python };
270
+ }
260
271
 
261
- // Windows' Chrome keeps its cookies one folder down, in Default\Network.
262
- const profile = path.join(dataDir(), 'chrome-profile', 'Default');
263
- const signedIn = existsSync(path.join(profile, 'Cookies')) || existsSync(path.join(profile, 'Network', 'Cookies'));
272
+ /** Google Chrome, where Playwright's "chrome" channel looks (lib/scanner-setup.js). A file check, so cheap enough for every POST. */
273
+ function chromeHere() {
274
+ return chromeInstalled({ platform: process.platform, env: process.env, exists: existsSync });
275
+ }
264
276
 
265
- return { root, python, chrome, signedIn };
277
+ /**
278
+ * Signed in to LinkedIn in the scanner's Chrome: the scanner's own note once
279
+ * it has confirmed the session (lib/scanner-setup.js signedInFrom). A folder
280
+ * from before the note goes by Chrome's cookie file, as it always did; Windows'
281
+ * Chrome keeps that one folder down, in Default\Network.
282
+ */
283
+ function signedIn() {
284
+ const data = dataDir();
285
+ let note = null;
286
+ try { note = JSON.parse(readFileSync(path.join(data, SIGNED_IN_FILE), 'utf8')); } catch { /* none yet, or unreadable: the old check */ }
287
+ const profile = path.join(data, 'chrome-profile', 'Default');
288
+ return signedInFrom({
289
+ note,
290
+ profile: existsSync(path.join(data, 'chrome-profile')),
291
+ cookies: existsSync(path.join(profile, 'Cookies')) || existsSync(path.join(profile, 'Network', 'Cookies')),
292
+ });
266
293
  }
267
294
 
268
- /** Google Chrome on Windows, where Playwright's "chrome" channel looks: for this user, then for everyone. */
269
- function windowsChrome() {
270
- const env = process.env;
271
- return [env.LOCALAPPDATA, env.PROGRAMFILES, env['PROGRAMFILES(X86)']]
272
- .filter(Boolean)
273
- .some((root) => existsSync(path.join(root, 'Google', 'Chrome', 'Application', 'chrome.exe')));
295
+ // The "I understand" before the first scan: given on the Scan page, or implied by
296
+ // the scanner's own Chrome profile, which only a scan before it could have made.
297
+ function scanRisk() {
298
+ let acceptedAt = null;
299
+ try { acceptedAt = readSettings(getDb()).scanRiskAccepted; } catch { /* unreadable: ask */ }
300
+ return riskAccepted({ acceptedAt, scannedBefore: existsSync(path.join(dataDir(), 'chrome-profile')) });
274
301
  }
275
302
 
276
303
  function machineChecks() {
@@ -309,6 +336,7 @@ function paused(userId) {
309
336
 
310
337
  async function status() {
311
338
  const m = await machineChecks();
339
+ const chrome = chromeHere();
312
340
 
313
341
  // How much is already mapped, by degree, so the page can mark the scan step
314
342
  // done and offer the way to the galaxy instead of leaving someone on a form.
@@ -325,7 +353,9 @@ async function status() {
325
353
 
326
354
  const py = m.python;
327
355
  return {
328
- ready: Boolean(m.root && py.run && m.chrome),
356
+ ready: Boolean(m.root && py.run && chrome),
357
+ // Whose circle is being read now, for the Scan page's "Watch it fill in".
358
+ mapping: mappingWho(me?.id),
329
359
  checks: {
330
360
  scriptsFound: Boolean(m.root),
331
361
  // A Python that runs the scanner, or one Install can build its environment from.
@@ -344,8 +374,10 @@ async function status() {
344
374
  systemPython: py.systemFound,
345
375
  // What "Set up the scanner" would download, when there is nothing to install from.
346
376
  download: py.download ? { version: py.download.version, size: py.download.size, from: 'github.com' } : null,
347
- chrome: m.chrome,
348
- signedIn: m.signedIn,
377
+ chrome,
378
+ signedIn: signedIn(),
379
+ // The one-time "I understand" before the first scan (lib/scan-risk.js).
380
+ riskAccepted: scanRisk(),
349
381
  },
350
382
  network,
351
383
  photosWaiting,
@@ -356,6 +388,28 @@ async function status() {
356
388
  };
357
389
  }
358
390
 
391
+ /**
392
+ * Whose circle the running scan is reading: { id, name } of one of your
393
+ * connections, or null. A scan of one person knows its target; a batch (Map
394
+ * 2nd degree, every paused list) prints each person's name as it starts
395
+ * (lib/scan-progress.js mappingNow), found here among your connections. Two
396
+ * with that name can't be told apart that way, so neither is named.
397
+ */
398
+ function mappingWho(userId) {
399
+ if (!state.running) return null;
400
+ if (state.target?.id && ['bridge', 'rescrape', 'resume'].includes(state.action)) return { id: state.target.id, name: state.target.name };
401
+ const name = mappingNow(state.log, state.action);
402
+ if (!name || !userId) return null;
403
+ try {
404
+ const rows = getDb().prepare(
405
+ 'SELECT id FROM linkedin_connections WHERE user_id = ? AND degree = 1 AND name = ? LIMIT 2',
406
+ ).all(userId, name);
407
+ return rows.length === 1 ? { id: rows[0].id, name } : null;
408
+ } catch {
409
+ return null;
410
+ }
411
+ }
412
+
359
413
  /**
360
414
  * The running job alone, from memory: no checks, no database. Every Scan
361
415
  * button in the app asks this (lib/scraper-client.js watchScanner), every few
@@ -375,6 +429,7 @@ function job() {
375
429
  failure: state.running ? null : state.failure,
376
430
  progress: state.running ? scanProgress(state.log, state.action) : null,
377
431
  pages: state.running ? state.pages : 0,
432
+ found: state.running ? state.found : [],
378
433
  log: state.log.slice(-120),
379
434
  recent: state.recent,
380
435
  budget: state.running ? budgetNow() : null,
@@ -425,6 +480,16 @@ export async function GET(request) {
425
480
  if (q.has('job')) return Response.json(job());
426
481
  if (q.has('resume')) return Response.json({ resume: resumePoint(q.get('resume')) });
427
482
  if (q.has('reach')) return Response.json(scanNotes());
483
+ // Settings → LinkedIn usage: the scanner's record of searches, profile views
484
+ // and pauses, counted (lib/linkedin-limits.js linkedinUsage). Reads only; no
485
+ // checks, no Python, nothing written.
486
+ if (q.has('usage')) {
487
+ try {
488
+ return Response.json(linkedinUsage(dataDir()));
489
+ } catch {
490
+ return Response.json({ error: 'The record of LinkedIn searches on this computer could not be read.' }, { status: 500 });
491
+ }
492
+ }
428
493
  if (q.has('person')) return Response.json(pickedPerson(q.get('person')));
429
494
  return Response.json(await status());
430
495
  }
@@ -586,6 +651,17 @@ export async function POST(request) {
586
651
  if (!Object.hasOwn(ACTIONS, action)) {
587
652
  return Response.json({ error: `Unknown action '${action}'` }, { status: 400 });
588
653
  }
654
+ // Nothing opens LinkedIn before the one-time "I understand" on the Scan page,
655
+ // whichever button asked (lib/scan-risk.js).
656
+ if (touchesLinkedIn(action) && !scanRisk()) {
657
+ return Response.json({ error: RISK_REFUSAL, needsRiskAcceptance: true }, { status: 409 });
658
+ }
659
+ // Nor without Google Chrome, which the scanner drives: the Scan page's step 1
660
+ // says so in the same words, and every other button is told here, before
661
+ // anything starts, rather than by a Playwright error at the end of a log.
662
+ if (touchesLinkedIn(action) && !chromeHere()) {
663
+ return Response.json({ error: CHROME_REFUSAL, needsChrome: true }, { status: 409 });
664
+ }
589
665
 
590
666
  const spec = ACTIONS[action];
591
667
  const maxBridges = Number.isInteger(body.maxBridges) && body.maxBridges > 0
@@ -645,7 +721,7 @@ export async function POST(request) {
645
721
  }
646
722
  const cooldown = linkedinState(dataDir()).cooldown;
647
723
  if (searches && cooldown) {
648
- return Response.json({ error: `Scanning is paused until ${new Date(cooldown.until).toLocaleString()} — ${cooldown.reason}.`, cooldown }, { status: 409 });
724
+ return Response.json({ error: `Scanning is paused until ${new Date(cooldown.until).toLocaleString()}: ${cooldown.reason}.`, cooldown }, { status: 409 });
649
725
  }
650
726
  if (state.running) {
651
727
  return Response.json({ error: 'Something is already running.', action: state.action }, { status: 409 });
@@ -714,6 +790,7 @@ export async function POST(request) {
714
790
  state.startedAt = Date.now();
715
791
  state.log = [spec.label + (target?.name ? ` ${target.name}…` : '…')];
716
792
  state.pages = 0;
793
+ state.found = [];
717
794
  state.stderrTail = [];
718
795
  state.failure = null;
719
796
  forgetChecks();
@@ -766,6 +843,17 @@ export async function POST(request) {
766
843
  try { cleanup(); } catch { /* swept at the next setup (sweepSetupLeftovers) */ }
767
844
  }
768
845
  forgetChecks();
846
+ // The daily backup, once a scan may have changed the network (lib/backups.js):
847
+ // checked here and when the server starts, never on a timer. Setting the
848
+ // scanner up and signing in change nothing in it.
849
+ if (!['install', 'setup', 'login'].includes(state.action)) {
850
+ try {
851
+ const daily = backUpDailyIfDue();
852
+ if (daily) push('Made today’s backup of your network (Settings → Your data).');
853
+ } catch (err) {
854
+ push(`Today’s backup couldn’t be made: ${err.message}`);
855
+ }
856
+ }
769
857
  }
770
858
 
771
859
  function runStep(i) {
@@ -5,7 +5,8 @@ import { socialFiles, readJson, writeJsonAtomic } from '../../../../lib/social-s
5
5
  // The Social tab's CRM: your own stage, tags, notes and next follow-up for each
6
6
  // person, in crm-<profile>.json in the data folder (lib/social-crm.js has the
7
7
  // shape). Yours, so always kept, whatever Keep my messages says; never sent
8
- // anywhere, and not in "Save a copy of my network".
8
+ // anywhere, never in Six Degrees' own backups (lib/backups.js BACKUP_SOCIAL),
9
+ // and in "Export backup file…" only when its Social box is ticked.
9
10
  //
10
11
  // GET the whole store
11
12
  // PATCH { key, set: { stage?, tags?, notes?, followUp? } } one person's