six-degrees 0.4.7 → 0.4.9

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 (280) 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 +3 -3
  5. package/.next/standalone/.next/routes-manifest.json +6 -0
  6. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  7. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.rsc +2 -2
  9. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +2 -2
  11. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +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 +13 -13
  16. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +13 -13
  17. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +11 -11
  18. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +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.nft.json +1 -1
  21. package/.next/standalone/.next/server/app/api/bridges/route.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/api/bulk-import/route.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js +2 -1
  24. package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/company-scores/route.js +2 -1
  26. package/.next/standalone/.next/server/app/api/company-scores/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/connections/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/data/export/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/data/import/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/data/restart/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/data/reveal/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/data/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/delete-cluster/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/ingest/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/api/network/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/api/outreach/route.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/api/queue/route.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/api/scraper/route.js +2 -2
  40. package/.next/standalone/.next/server/app/api/scraper/route.js.nft.json +1 -1
  41. package/.next/standalone/.next/server/app/api/settings/route.js +3 -2
  42. package/.next/standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js +2 -1
  44. package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.nft.json +1 -1
  45. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js +2 -1
  46. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.nft.json +1 -1
  47. package/.next/standalone/.next/server/app/api/setup-profile/route.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/api/social/messages/route/app-paths-manifest.json +3 -0
  49. package/.next/standalone/.next/server/app/api/social/messages/route/build-manifest.json +12 -0
  50. package/.next/standalone/.next/server/app/api/social/messages/route/server-reference-manifest.json +4 -0
  51. package/.next/standalone/.next/server/app/api/social/messages/route.js +9 -0
  52. package/.next/standalone/.next/server/app/api/social/messages/route.js.map +5 -0
  53. package/.next/standalone/.next/server/app/api/social/messages/route.js.nft.json +1 -0
  54. package/.next/standalone/.next/server/app/api/social/messages/route_client-reference-manifest.js +3 -0
  55. package/.next/standalone/.next/server/app/api/social/route.js +4 -2
  56. package/.next/standalone/.next/server/app/api/social/route.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/api/unlock/route.js.nft.json +1 -1
  58. package/.next/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  59. package/.next/standalone/.next/server/app/api/update-images/route.js.nft.json +1 -1
  60. package/.next/standalone/.next/server/app/api/users/route.js.nft.json +1 -1
  61. package/.next/standalone/.next/server/app/avatars/[file]/route.js.nft.json +1 -1
  62. package/.next/standalone/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  63. package/.next/standalone/.next/server/app/favicon.ico.body +0 -0
  64. package/.next/standalone/.next/server/app/import/page.js.nft.json +1 -1
  65. package/.next/standalone/.next/server/app/import/page_client-reference-manifest.js +1 -1
  66. package/.next/standalone/.next/server/app/import.html +1 -1
  67. package/.next/standalone/.next/server/app/import.rsc +15 -15
  68. package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +15 -15
  69. package/.next/standalone/.next/server/app/import.segments/_tree.segment.rsc +1 -1
  70. package/.next/standalone/.next/server/app/import.segments/import/__PAGE__.segment.rsc +13 -13
  71. package/.next/standalone/.next/server/app/index.html +1 -1
  72. package/.next/standalone/.next/server/app/index.rsc +15 -15
  73. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +13 -13
  74. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  75. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  76. package/.next/standalone/.next/server/app/launch/page.js.nft.json +1 -1
  77. package/.next/standalone/.next/server/app/launch/page_client-reference-manifest.js +1 -1
  78. package/.next/standalone/.next/server/app/launch.html +2 -2
  79. package/.next/standalone/.next/server/app/launch.rsc +15 -15
  80. package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +15 -15
  81. package/.next/standalone/.next/server/app/launch.segments/_tree.segment.rsc +1 -1
  82. package/.next/standalone/.next/server/app/launch.segments/launch/__PAGE__.segment.rsc +13 -13
  83. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  84. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  85. package/.next/standalone/.next/server/app/paths/page.js.nft.json +1 -1
  86. package/.next/standalone/.next/server/app/paths/page_client-reference-manifest.js +1 -1
  87. package/.next/standalone/.next/server/app/paths.html +1 -1
  88. package/.next/standalone/.next/server/app/paths.rsc +15 -15
  89. package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +15 -15
  90. package/.next/standalone/.next/server/app/paths.segments/_tree.segment.rsc +1 -1
  91. package/.next/standalone/.next/server/app/paths.segments/paths/__PAGE__.segment.rsc +13 -13
  92. package/.next/standalone/.next/server/app/profile/page.js.nft.json +1 -1
  93. package/.next/standalone/.next/server/app/profile/page_client-reference-manifest.js +1 -1
  94. package/.next/standalone/.next/server/app/profile.html +1 -1
  95. package/.next/standalone/.next/server/app/profile.rsc +15 -15
  96. package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +15 -15
  97. package/.next/standalone/.next/server/app/profile.segments/_tree.segment.rsc +1 -1
  98. package/.next/standalone/.next/server/app/profile.segments/profile/__PAGE__.segment.rsc +13 -13
  99. package/.next/standalone/.next/server/app/queue/page.js.nft.json +1 -1
  100. package/.next/standalone/.next/server/app/queue/page_client-reference-manifest.js +1 -1
  101. package/.next/standalone/.next/server/app/queue.html +1 -1
  102. package/.next/standalone/.next/server/app/queue.rsc +15 -15
  103. package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +15 -15
  104. package/.next/standalone/.next/server/app/queue.segments/_tree.segment.rsc +1 -1
  105. package/.next/standalone/.next/server/app/queue.segments/queue/__PAGE__.segment.rsc +13 -13
  106. package/.next/standalone/.next/server/app/scores/page.js.nft.json +1 -1
  107. package/.next/standalone/.next/server/app/scores/page_client-reference-manifest.js +1 -1
  108. package/.next/standalone/.next/server/app/scores.html +1 -1
  109. package/.next/standalone/.next/server/app/scores.rsc +15 -15
  110. package/.next/standalone/.next/server/app/scores.segments/_full.segment.rsc +15 -15
  111. package/.next/standalone/.next/server/app/scores.segments/_tree.segment.rsc +1 -1
  112. package/.next/standalone/.next/server/app/scores.segments/scores/__PAGE__.segment.rsc +13 -13
  113. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  114. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  115. package/.next/standalone/.next/server/app/settings.html +1 -1
  116. package/.next/standalone/.next/server/app/settings.rsc +15 -15
  117. package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +15 -15
  118. package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  119. package/.next/standalone/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +13 -13
  120. package/.next/standalone/.next/server/app/setup/page.js.nft.json +1 -1
  121. package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  122. package/.next/standalone/.next/server/app/setup.html +1 -1
  123. package/.next/standalone/.next/server/app/setup.rsc +15 -15
  124. package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +15 -15
  125. package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +1 -1
  126. package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +13 -13
  127. package/.next/standalone/.next/server/app/social/page.js.nft.json +1 -1
  128. package/.next/standalone/.next/server/app/social/page_client-reference-manifest.js +1 -1
  129. package/.next/standalone/.next/server/app/social.html +1 -1
  130. package/.next/standalone/.next/server/app/social.rsc +15 -15
  131. package/.next/standalone/.next/server/app/social.segments/_full.segment.rsc +15 -15
  132. package/.next/standalone/.next/server/app/social.segments/_tree.segment.rsc +1 -1
  133. package/.next/standalone/.next/server/app/social.segments/social/__PAGE__.segment.rsc +13 -13
  134. package/.next/standalone/.next/server/app-paths-manifest.json +1 -0
  135. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06mi9k2._.js +3 -0
  136. package/.next/standalone/.next/server/chunks/[root-of-the-server]__08f5awg._.js +8 -0
  137. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0bat8nx._.js +1 -1
  138. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17hjtzl._.js +8 -0
  139. package/.next/standalone/.next/server/chunks/[root-of-the-server]__20tmem7._.js +1 -1
  140. package/.next/standalone/.next/server/chunks/_0ea9qwy._.js +3 -0
  141. package/.next/standalone/.next/server/chunks/_1_fynia._.js +6 -6
  142. package/.next/standalone/.next/server/chunks/_1itd1o_._.js +1 -1
  143. package/.next/standalone/.next/server/chunks/_1mxn_lb._.js +1 -1
  144. package/.next/standalone/.next/server/chunks/_1xh07bp._.js +1 -1
  145. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_social_messages_route_actions_0skh09r.js +3 -0
  146. package/.next/standalone/.next/server/chunks/lib_18cr1gi._.js +8 -0
  147. package/.next/standalone/.next/server/chunks/lib_db-client_15le7cw.js +1 -1
  148. package/.next/standalone/.next/server/chunks/lib_rpc_03i8xef.js +1 -1
  149. package/.next/standalone/.next/server/chunks/lib_rpc_08fc3rp.js +1 -1
  150. package/.next/standalone/.next/server/chunks/lib_rpc_08r2t_q.js +1 -1
  151. package/.next/standalone/.next/server/chunks/lib_rpc_0btpv1t.js +1 -1
  152. package/.next/standalone/.next/server/chunks/lib_rpc_0c9d9ti.js +5 -5
  153. package/.next/standalone/.next/server/chunks/lib_rpc_0cm2ev3.js +1 -1
  154. package/.next/standalone/.next/server/chunks/lib_rpc_0iovswz.js +1 -1
  155. package/.next/standalone/.next/server/chunks/lib_rpc_0is8flp.js +1 -1
  156. package/.next/standalone/.next/server/chunks/lib_rpc_0v8ajtd.js +1 -1
  157. package/.next/standalone/.next/server/chunks/lib_rpc_0xgmvvt.js +1 -1
  158. package/.next/standalone/.next/server/chunks/lib_rpc_144mzbf.js +1 -1
  159. package/.next/standalone/.next/server/chunks/lib_rpc_1bggi0n.js +1 -1
  160. package/.next/standalone/.next/server/chunks/lib_rpc_1dkcu9f.js +1 -1
  161. package/.next/standalone/.next/server/chunks/lib_rpc_1o0jb6w.js +1 -1
  162. package/.next/standalone/.next/server/chunks/lib_scoring_1-e4ur0.js +3 -0
  163. package/.next/standalone/.next/server/chunks/node_modules_next_1zc5q0a._.js +1 -1
  164. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00d8snt._.js +1 -1
  165. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00g61b8._.js +1 -1
  166. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__08lf3gy._.js +1 -1
  167. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0hg5gib._.js +1 -1
  168. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ho-u0w._.js +1 -1
  169. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1feicqq._.js → [root-of-the-server]__0qdeuyo._.js} +1 -1
  170. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ze473p._.js +1 -1
  171. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1194jps._.js +1 -1
  172. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1cnxxc9._.js +1 -1
  173. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1jeztd-._.js +1 -1
  174. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ll97ry._.js +1 -1
  175. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1m0255u._.js +1 -1
  176. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1w9z0zv._.js +1 -1
  177. package/.next/standalone/.next/server/chunks/ssr/_0c_y09g._.js +3 -0
  178. package/.next/standalone/.next/server/chunks/ssr/_0ezj4e0._.js +1 -1
  179. package/.next/standalone/.next/server/chunks/ssr/{_1mj739k._.js → _0l8cxmo._.js} +2 -2
  180. package/.next/standalone/.next/server/chunks/ssr/_1errbuf._.js +3 -0
  181. package/.next/standalone/.next/server/chunks/ssr/{_0wxbq78._.js → app_components_19c2d9c._.js} +2 -2
  182. package/.next/standalone/.next/server/chunks/ssr/app_components_ui_0pdmz2z.js +3 -0
  183. package/.next/standalone/.next/server/chunks/ssr/app_paths_page_1ol90m7.js +1 -1
  184. package/.next/standalone/.next/server/chunks/ssr/app_profile_page_0u3-l5y.js +1 -1
  185. package/.next/standalone/.next/server/chunks/ssr/app_queue_page_0c6znd6.js +1 -1
  186. package/.next/standalone/.next/server/chunks/ssr/app_scores_page_09wepvv.js +1 -1
  187. package/.next/standalone/.next/server/chunks/ssr/app_settings_page_1f8mjj_.js +1 -1
  188. package/.next/standalone/.next/server/chunks/ssr/app_setup_page_1-282zx.js +1 -1
  189. package/.next/standalone/.next/server/chunks/ssr/app_social_page_0h7zxda.js +3 -0
  190. package/.next/standalone/.next/server/chunks/ssr/lib_0i8v-s3._.js +1 -1
  191. package/.next/standalone/.next/server/chunks/ssr/{node_modules_1wax83z._.js → node_modules_0h91jdk._.js} +2 -2
  192. package/.next/standalone/.next/server/chunks/ssr/{node_modules_1nkgb45._.js → node_modules_1f8t_rp._.js} +1 -1
  193. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  194. package/.next/standalone/.next/server/middleware-manifest.json +5 -5
  195. package/.next/standalone/.next/server/pages/404.html +1 -1
  196. package/.next/standalone/.next/server/pages/500.html +1 -1
  197. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  198. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  199. package/.next/standalone/.next/static/chunks/{2_zu7rmb8flzl.js → 04bbi55urkrd6.js} +1 -1
  200. package/.next/{static/chunks/3q3pmt5vv-4pi.js → standalone/.next/static/chunks/054zdthcnyd2h.js} +1 -1
  201. package/.next/{static/chunks/236f0jtp68j_h.js → standalone/.next/static/chunks/1_mohm2643nxp.js} +1 -1
  202. package/.next/{static/chunks/3zw8bv7-mc4n6.js → standalone/.next/static/chunks/1z_rt4jteewqp.js} +1 -1
  203. package/.next/standalone/.next/static/chunks/24tvdun1cb3g1.js +1 -0
  204. package/.next/standalone/.next/static/chunks/2bftn9gubwf0w.js +1 -0
  205. package/.next/{static/chunks/0g_p4p7oci18u.js → standalone/.next/static/chunks/2kfhc58df2xyo.js} +1 -1
  206. package/.next/standalone/.next/static/chunks/2pw6_osz1n_te.js +1 -0
  207. package/.next/standalone/.next/static/chunks/39csdcx7yv227.js +1 -0
  208. package/.next/standalone/.next/static/chunks/3yzlf70j5t0-o.js +1 -0
  209. package/.next/standalone/.next/static/chunks/{2_wcobfqry2uj.js → 3z-swu5pet507.js} +1 -1
  210. package/.next/standalone/.next/static/media/favicon.23vm2o6v3er2z.ico +0 -0
  211. package/.next/standalone/CHANGELOG.md +72 -0
  212. package/.next/standalone/CONTRIBUTING.md +5 -0
  213. package/.next/standalone/README.md +168 -56
  214. package/.next/standalone/app/api/social/messages/route.js +130 -0
  215. package/.next/standalone/app/api/social/route.js +89 -47
  216. package/.next/standalone/app/components/ScanStatusBar.js +40 -3
  217. package/.next/standalone/app/components/settings/DataSection.js +2 -1
  218. package/.next/standalone/app/favicon.ico +0 -0
  219. package/.next/standalone/app/paths/page.js +27 -18
  220. package/.next/standalone/app/profile/page.js +2 -0
  221. package/.next/standalone/app/queue/page.js +2 -0
  222. package/.next/standalone/app/scores/page.js +2 -0
  223. package/.next/standalone/app/settings/page.js +2 -0
  224. package/.next/standalone/app/setup/page.js +6 -3
  225. package/.next/standalone/app/social/Conversations.js +246 -0
  226. package/.next/standalone/app/social/page.js +90 -9
  227. package/.next/standalone/lib/galaxy-lab.js +6 -1
  228. package/.next/standalone/lib/linkedin-export.js +175 -5
  229. package/.next/standalone/lib/scoring.js +42 -1
  230. package/.next/standalone/lib/social-store.js +73 -0
  231. package/.next/standalone/package-lock.json +2 -2
  232. package/.next/standalone/package.json +1 -1
  233. package/.next/standalone/scripts/build-site.mjs +537 -0
  234. package/.next/standalone/scripts/scrape.py +156 -23
  235. package/.next/standalone/scripts/site-markdown.mjs +188 -0
  236. package/.next/standalone/scripts/site-news.mjs +311 -0
  237. package/.next/static/chunks/{2_zu7rmb8flzl.js → 04bbi55urkrd6.js} +1 -1
  238. package/.next/{standalone/.next/static/chunks/3q3pmt5vv-4pi.js → static/chunks/054zdthcnyd2h.js} +1 -1
  239. package/.next/{standalone/.next/static/chunks/236f0jtp68j_h.js → static/chunks/1_mohm2643nxp.js} +1 -1
  240. package/.next/{standalone/.next/static/chunks/3zw8bv7-mc4n6.js → static/chunks/1z_rt4jteewqp.js} +1 -1
  241. package/.next/static/chunks/24tvdun1cb3g1.js +1 -0
  242. package/.next/static/chunks/2bftn9gubwf0w.js +1 -0
  243. package/.next/{standalone/.next/static/chunks/0g_p4p7oci18u.js → static/chunks/2kfhc58df2xyo.js} +1 -1
  244. package/.next/static/chunks/2pw6_osz1n_te.js +1 -0
  245. package/.next/static/chunks/39csdcx7yv227.js +1 -0
  246. package/.next/static/chunks/3yzlf70j5t0-o.js +1 -0
  247. package/.next/static/chunks/{2_wcobfqry2uj.js → 3z-swu5pet507.js} +1 -1
  248. package/.next/static/media/favicon.23vm2o6v3er2z.ico +0 -0
  249. package/CHANGELOG.md +72 -0
  250. package/README.md +168 -56
  251. package/lib/galaxy-lab.js +6 -1
  252. package/lib/linkedin-export.js +175 -5
  253. package/lib/scoring.js +42 -1
  254. package/lib/social-store.js +73 -0
  255. package/package.json +1 -1
  256. package/scripts/scrape.py +156 -23
  257. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17kn1mk._.js +0 -8
  258. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1dmc7-t._.js +0 -8
  259. package/.next/standalone/.next/server/chunks/ssr/_005q9n1._.js +0 -3
  260. package/.next/standalone/.next/server/chunks/ssr/_217nddo._.js +0 -3
  261. package/.next/standalone/.next/server/chunks/ssr/app_0i3fw_m._.js +0 -3
  262. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_client_components_server-async-storage_0t1dato.js +0 -3
  263. package/.next/standalone/.next/static/chunks/0a5iadnmt9u9k.js +0 -1
  264. package/.next/standalone/.next/static/chunks/0y1yms5kez2f3.js +0 -1
  265. package/.next/standalone/.next/static/chunks/14m1zu-8warte.js +0 -1
  266. package/.next/standalone/.next/static/chunks/15qbli9udo0vh.js +0 -1
  267. package/.next/standalone/.next/static/chunks/3p_pwu5gx2i9h.js +0 -1
  268. package/.next/standalone/.next/static/media/favicon.0zdzw5kurn8m-.ico +0 -0
  269. package/.next/static/chunks/0a5iadnmt9u9k.js +0 -1
  270. package/.next/static/chunks/0y1yms5kez2f3.js +0 -1
  271. package/.next/static/chunks/14m1zu-8warte.js +0 -1
  272. package/.next/static/chunks/15qbli9udo0vh.js +0 -1
  273. package/.next/static/chunks/3p_pwu5gx2i9h.js +0 -1
  274. package/.next/static/media/favicon.0zdzw5kurn8m-.ico +0 -0
  275. /package/.next/standalone/.next/static/{YNRcnda8lvMnnrOKL1L5l → yPlsfKhdS8MMtyXF7twSZ}/_buildManifest.js +0 -0
  276. /package/.next/standalone/.next/static/{YNRcnda8lvMnnrOKL1L5l → yPlsfKhdS8MMtyXF7twSZ}/_clientMiddlewareManifest.js +0 -0
  277. /package/.next/standalone/.next/static/{YNRcnda8lvMnnrOKL1L5l → yPlsfKhdS8MMtyXF7twSZ}/_ssgManifest.js +0 -0
  278. /package/.next/static/{YNRcnda8lvMnnrOKL1L5l → yPlsfKhdS8MMtyXF7twSZ}/_buildManifest.js +0 -0
  279. /package/.next/static/{YNRcnda8lvMnnrOKL1L5l → yPlsfKhdS8MMtyXF7twSZ}/_clientMiddlewareManifest.js +0 -0
  280. /package/.next/static/{YNRcnda8lvMnnrOKL1L5l → yPlsfKhdS8MMtyXF7twSZ}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,2776,e=>{"use strict";var t=e.i(43476),n=e.i(15812);e.s(["default",0,function({children:e}){let{userId:o,ready:i}=(0,n.useUser)();return i&&o?e:(0,t.jsx)("div",{style:{minHeight:"100vh",display:"flex",alignItems:"center",justifyContent:"center",background:"#0a0a1a",color:"#fff",padding:24,textAlign:"center",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'},children:i?(0,t.jsxs)("div",{style:{maxWidth:420},children:[(0,t.jsx)("div",{style:{fontSize:18,fontWeight:700,marginBottom:8},children:"Can’t reach Six Degrees’ local server"}),(0,t.jsx)("div",{style:{color:"#888",fontSize:14,lineHeight:1.6},children:"The page loaded but the app behind it is not answering. If you started it from a terminal, check that window for an error, then reload this page."})]}):(0,t.jsx)("div",{style:{fontSize:18,fontWeight:600},children:"Loading…"})})}])},8819,e=>{"use strict";var t=e.i(43476);let n="1px solid rgba(255,255,255,0.1)";function o({children:e,style:n}){return(0,t.jsx)("div",{style:{fontSize:13.5,color:"#8b9a9a",lineHeight:1.6,marginTop:4,...n},children:e})}e.s(["Body",0,o,"Btn",0,function({children:e,onClick:o,disabled:i,primary:a,tone:r,type:s="button"}){return(0,t.jsx)("button",{type:s,onClick:o,disabled:i,style:{padding:"9px 18px",borderRadius:7,fontSize:13.5,fontWeight:650,color:i?"#667":"#fff",border:n,background:i?"rgba(255,255,255,0.05)":"bad"===r?"rgba(255,80,80,0.15)":a?"linear-gradient(135deg, #9B59B6, #3498DB)":"rgba(255,255,255,0.08)",cursor:i?"not-allowed":"pointer"},children:e})},"FONT",0,'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',"LINE",0,n,"Mono",0,function({children:e}){return(0,t.jsx)("code",{style:{background:"rgba(255,255,255,0.08)",padding:"1px 5px",borderRadius:4,wordBreak:"break-all"},children:e})},"Section",0,function({id:e,title:i,intro:a,children:r}){return(0,t.jsxs)("section",{id:e,style:{padding:"24px 0",borderBottom:n,scrollMarginTop:16},children:[(0,t.jsx)("h2",{style:{fontSize:16,fontWeight:650,margin:"0 0 6px"},children:i}),a&&(0,t.jsx)(o,{style:{marginTop:0,marginBottom:12},children:a}),r]})},"Status",0,function({children:e,tone:n}){return(0,t.jsxs)("div",{role:"status",style:{marginTop:10,padding:"10px 14px",borderRadius:8,fontSize:13.5,lineHeight:1.6,color:"ok"===n?"#00ff88":"bad"===n?"#ff7676":"#e8e8ee",background:"ok"===n?"rgba(0,255,136,0.08)":"bad"===n?"rgba(255,80,80,0.08)":"rgba(255,255,255,0.05)",border:`1px solid ${"ok"===n?"rgba(0,255,136,0.3)":"bad"===n?"rgba(255,80,80,0.3)":"rgba(255,255,255,0.12)"}`},children:["ok"===n&&"✓ ",e]})}])},5445,e=>{"use strict";var t=e.i(43476),n=e.i(71645),o=e.i(22016),i=e.i(18566),a=e.i(2776),r=e.i(8819);function s(){let[e,o]=(0,n.useState)(null);return((0,n.useEffect)(()=>{fetch("/api/update").then(e=>e.json()).then(o).catch(()=>{})},[]),e)?e.installed?(0,t.jsx)(h,{local:e}):(0,t.jsx)(d,{local:e}):null}async function l(e){let t=await fetch("/api/update",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}),n=await t.json().catch(()=>({}));return{ok:t.ok,d:n}}function d({local:e}){let[o,i]=(0,n.useState)(null),[a,s]=(0,n.useState)(null),[c,h]=(0,n.useState)(null),[p,u]=(0,n.useState)(null);async function y(e){s(e),h(null);try{let{ok:t,d:n}=await l({action:e});if(!t){h(n.error||"Something went wrong."),n.dirty&&i({dirty:n.dirty});return}"check"===e?i(n):(u(n),i(null))}catch(e){h(e.message)}finally{s(null)}}return(0,n.useEffect)(()=>{"updates"===new URLSearchParams(window.location.search).get("check")&&(document.getElementById("updates")?.scrollIntoView({block:"center"}),y("check"),window.history.replaceState(null,"",window.location.pathname))},[]),(0,t.jsxs)(r.Section,{id:"updates",title:"Updates",children:[p?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(r.Body,{children:["Updated to ",(0,t.jsx)(r.Mono,{children:p.sha})," — “",p.subject,"”."]}),(0,t.jsx)(r.Body,{style:{color:p.needsRestart?"#FFD700":void 0},children:p.needsRestart?"Stop the app in your terminal and start it again — this update changed how it starts.":"The page will pick up most changes on its own. Restart the app if anything looks odd."})]}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(r.Body,{children:["You are on ",(0,t.jsx)(r.Mono,{children:e.sha})," — “",e.subject,"”."]}),o&&0===o.behind&&(0,t.jsx)(r.Status,{tone:"ok",children:"You’re up to date."}),o&&o.behind>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(r.Body,{style:{color:"#00ff88"},children:[o.behind," update",1===o.behind?"":"s"," available."]}),(0,t.jsx)("pre",{style:x,children:o.commits.join("\n")})]}),o?.dirty?.length>0&&(0,t.jsxs)(r.Body,{children:["Changed files here:"," ",(0,t.jsx)(r.Mono,{children:o.dirty.join(", ")}),". Commit or discard them first — this will not throw away your work."]}),(0,t.jsxs)(f,{children:[(0,t.jsx)(r.Btn,{onClick:()=>y("check"),disabled:!!a,children:"check"===a?"Checking…":"Check for updates"}),o?.behind>0&&(0,t.jsx)(r.Btn,{onClick:()=>y("pull"),disabled:!!a,primary:!0,children:"pull"===a?"Updating…":`Install ${o.behind} update${1===o.behind?"":"s"}`})]})]}),c&&(0,t.jsx)(r.Body,{style:{color:"#ff7676"},children:c}),(0,t.jsxs)(r.Body,{style:{fontSize:12,color:"#667",marginTop:12},children:["Nothing is checked automatically and nothing about you is sent — this runs the same ",(0,t.jsx)(r.Mono,{children:"git fetch"})," and ",(0,t.jsx)(r.Mono,{children:"git pull"})," you would type yourself."]})]})}let c=["checking","downloading","verifying","preparing","restarting"];function h({local:e}){let o="mac-app"===e.kind,[i,a]=(0,n.useState)(!1),[s,d]=(0,n.useState)(null),[m,b]=(0,n.useState)(null),[j,w]=(0,n.useState)(!1),[k,S]=(0,n.useState)(null),[v,B]=(0,n.useState)(e.job||null),[T,C]=(0,n.useState)(!1),[D,I]=(0,n.useState)(null),[$,F]=(0,n.useState)(null),[M,R]=(0,n.useState)(void 0),[z,E]=(0,n.useState)(0),[L,N]=(0,n.useState)(!1),A=!!(v&&c.includes(v.phase)),O=A&&("restarting"===v.phase||z>0);async function U(){a(!0),d(null),b(null),I(null),F(null),R(void 0),B(e=>e&&c.includes(e.phase)?e:null);try{let{ok:e,d:t}=await l({action:"check-release"});e?(d(t),S(new Date)):b(t.error||"Could not check.")}catch(e){b(e.message)}finally{a(!1)}}async function W(){C(!0),I(null),F(null),R(void 0),E(0),N(!1);try{let{ok:e,d:t}=await l({action:"install-release"});t.job&&B(t.job),!e&&(I(t.error||"The update could not start."),F(t.refusal||null),"fallback"in t&&R(t.fallback))}catch(e){I(e.message)}finally{C(!1)}}async function Y(){try{let{d:e}=await l({action:"cancel-install"});e.job&&B(e.job)}catch{}}async function P(){try{await navigator.clipboard.writeText(e.command),w(!0),setTimeout(()=>w(!1),1600)}catch{b("Could not copy — select the line and copy it by hand.")}}(0,n.useEffect)(()=>{"#updates"===window.location.hash&&document.getElementById("updates")?.scrollIntoView({block:"start"}),"updates"!==new URLSearchParams(window.location.search).get("check")||(window.history.replaceState(null,"",window.location.pathname),e.job&&c.includes(e.job.phase)||(document.getElementById("updates")?.scrollIntoView({block:"center"}),U().then(()=>document.getElementById("updates")?.scrollIntoView({block:"end",behavior:"smooth"}))))},[e.job]),(0,n.useEffect)(()=>{if(!A)return;let e=!0,t=setTimeout(async()=>{try{if(O){let t=await fetch("/api/update",{cache:"no-store"}),n=await t.json();if(!e)return;if(!n.job||n.job.id!==v.id)return void window.location.reload();E(0),B(n.job)}else{let{ok:t,d:n}=await l({action:"update-status"});e&&t&&n.job&&B(n.job)}}catch{e&&E(e=>e+1)}},O?1500:600);return()=>{e=!1,clearTimeout(t)}},[v,z,A,O]),(0,n.useEffect)(()=>{if(!O)return;let e=setTimeout(()=>N(!0),6e4);return()=>clearTimeout(e)},[O]);let H=v?.phase==="failed",V=o&&s?.install?.possible,G=H&&"stale-check"===v.code||"not-checked"===$,K=void 0!==M?M:s?.fallback,_=s?.newer&&(!o||K)&&(!V||H||D||e.lastUpdate?.tone==="bad"),q=function({mac:e,kind:t,canInstall:n,fallback:o}){if(!e)return"source"===t?"A copy built from the source code updates by fetching the code and building it again, which it can't do while it runs. Stop it (Ctrl-C), then run this in the six-degrees folder. Your network stays where it is.":"This copy runs inside the terminal that started it, so it can't replace itself while it runs. Stop it first (Ctrl-C), then run this to start the newest version. Your network stays where it is.";if(!o)return null;let i=o.dataDir?` It opens the new version on the usual data folder, not on ${o.dataDir}: to use that one, quit it and open it again with --data-dir, as you opened this one.`:"";return"replace"===o.mode?`${n?"Or paste this into Terminal.":"Paste this into Terminal instead."} It closes this app, puts the new version in its place and opens it. Your network stays where it is.${i}`:`${n?"Or copy":"Copy"} this line, quit Six Degrees, then paste it into Terminal. It installs the new version at ${o.installsTo}, not where this copy is, and opens it: use that one from then on. Your network stays where it is.${i}`}({mac:o,kind:e.kind,canInstall:V,fallback:K});return(0,t.jsxs)(r.Section,{id:"updates",title:"Updates",children:[e.lastUpdate&&!A&&(0,t.jsx)(y,{report:e.lastUpdate}),(0,t.jsxs)(r.Body,{children:["You have version ",(0,t.jsx)(r.Mono,{children:e.version}),"."]}),A?(0,t.jsx)(u,{job:v,restarting:O,slow:L,onCancel:Y}):(0,t.jsxs)(t.Fragment,{children:[H&&(0,t.jsxs)(r.Status,{tone:"bad",children:[(0,t.jsx)("strong",{children:"The update didn’t finish."})," ",v.error," Nothing was changed."]}),v?.phase==="cancelled"&&(0,t.jsx)(r.Status,{children:"Cancelled. Nothing was changed."}),D&&(0,t.jsx)(r.Status,{tone:"bad",children:D}),s&&!s.latest&&(0,t.jsx)(r.Status,{children:"No release has been published yet."}),s?.latest&&!s.newer&&(0,t.jsxs)(r.Status,{tone:"ok",children:["You’re up to date: ",s.latest.version," is the newest version.",k&&(0,t.jsxs)("span",{style:{color:"#8b9a9a"},children:[" Checked at ",k.toLocaleTimeString([],{hour:"numeric",minute:"2-digit"}),"."]})]}),s?.newer&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(r.Body,{style:{color:"#00ff88"},children:["Version ",s.latest.version," is available."]}),V&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(r.Body,{children:["It downloads ",s.install.size?`about ${p(s.install.size)} MB`:"the new version"," from GitHub, checks it, then closes, replaces itself and reopens. Your network isn’t touched, and a backup of it is made first."]}),(0,t.jsxs)(f,{children:[G?(0,t.jsx)(r.Btn,{onClick:U,disabled:i,primary:!0,children:i?"Checking…":"Check again"}):(0,t.jsx)(r.Btn,{onClick:W,disabled:T,primary:!0,children:T?"Starting…":H||D?"Try again":"Install and restart"}),(0,t.jsx)(g,{url:s.latest.url})]})]}),o&&!V&&s.install?.reason&&(0,t.jsx)(r.Body,{children:s.install.reason}),_&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(r.Body,{children:q}),e.testReleases?(0,t.jsx)("pre",{style:x,children:"Not shown in test mode: it would install the real release from GitHub into Applications."}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("pre",{style:x,children:e.command}),(0,t.jsxs)(f,{children:[(0,t.jsx)(r.Btn,{onClick:P,primary:!V,children:j?"Copied":"Copy"}),!V&&(0,t.jsx)(g,{url:s.latest.url})]})]})]}),!V&&!_&&(0,t.jsx)(f,{children:(0,t.jsx)(g,{url:s.latest.url})})]}),!s?.newer&&(0,t.jsx)(f,{children:(0,t.jsx)(r.Btn,{onClick:U,disabled:i,children:i?"Checking…":s?"Check again":"Check for updates"})})]}),m&&(0,t.jsx)(r.Body,{style:{color:"#ff7676"},children:m}),(0,t.jsxs)(r.Body,{style:{fontSize:12,color:"#667",marginTop:12},children:["Nothing is checked automatically. The button asks GitHub for the newest version number, and nothing about you is sent.",o&&" Only a second click, Install and restart, downloads the new version."]}),e.testReleases&&(0,t.jsxs)(r.Body,{style:{fontSize:12,color:"#FFD700",marginTop:6},children:["Test mode: releases are read from ",(0,t.jsx)(r.Mono,{children:e.testReleases})," on this computer, not from GitHub."]})]})}let p=e=>Math.max(1,Math.round(e/1e6));function u({job:e,restarting:n,slow:o,onCancel:i}){let a=e.total?Math.min(100,Math.round(e.received/e.total*100)):null,s=n?"Restarting… Six Degrees closes and opens again in a moment.":"checking"===e.phase?"Asking GitHub for the newest version…":"downloading"===e.phase?`Downloading ${e.version}…${null!==a?` ${a}% (${p(e.received)} of ${p(e.total)} MB)`:""}`:"verifying"===e.phase?"Checking the download…":"Preparing the new version…";return(0,t.jsxs)("div",{role:"status","aria-live":"polite",style:{marginTop:12},children:[(0,t.jsx)(r.Body,{style:{color:"#e8e8ee"},children:s}),"downloading"===e.phase&&null!==a&&(0,t.jsx)("div",{role:"progressbar","aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":a,"aria-label":"Download",style:{height:6,borderRadius:3,background:"rgba(255,255,255,0.08)",marginTop:10,overflow:"hidden",maxWidth:420},children:(0,t.jsx)("div",{style:{width:`${a}%`,height:"100%",background:"linear-gradient(90deg, #9B59B6, #3498DB)",transition:"width 0.4s ease"}})}),o&&(0,t.jsx)(r.Body,{children:"This is taking longer than it should. If Six Degrees doesn’t open again by itself, open it from your Applications folder."}),!n&&(0,t.jsx)(f,{children:(0,t.jsx)(r.Btn,{onClick:i,children:"Cancel"})})]})}function y({report:e}){let n=new Date(e.at).toLocaleString([],{dateStyle:"medium",timeStyle:"short"});return(0,t.jsxs)(r.Status,{tone:"ok"===e.tone?"ok":"bad",children:[e.text," ",(0,t.jsxs)("span",{style:{color:"#8b9a9a"},children:["(",n,")"]}),"ok"===e.tone&&e.previous&&(0,t.jsxs)("span",{style:{display:"block",fontSize:12.5,color:"#8b9a9a",marginTop:4},children:["A copy of the version you had is kept in ",(0,t.jsx)(r.Mono,{children:e.previous})," until the next update. To go back to it, open that file and drag the app it gives you into your Applications folder."]})]})}function g({url:e}){return e?(0,t.jsx)("a",{href:e,target:"_blank",rel:"noreferrer",style:{color:"#3498DB",fontSize:13.5},children:"What changed →"}):null}function f({children:e}){return(0,t.jsx)("div",{style:{display:"flex",gap:10,marginTop:12,flexWrap:"wrap",alignItems:"center"},children:e})}let x={background:"rgba(0,0,0,0.45)",border:r.LINE,borderRadius:8,padding:12,margin:"8px 0 0",fontSize:12,lineHeight:1.7,color:"#b9c6c6",fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace",whiteSpace:"pre-wrap",maxHeight:180,overflow:"auto"};function m(e){if(!e)return"0 KB";if(e<1048576)return`${Math.max(1,Math.round(e/1024))} KB`;let t=e/1048576;return`${t<10?t.toFixed(1):Math.round(t)} MB`}let b=e=>Number(e||0).toLocaleString("en-US"),j=(e,t,n=`${t}s`)=>`${b(e)} ${1===Number(e)?t:n}`;function w(e,t=!0){if(!e)return null;let n=new Date(e);return Number.isNaN(n.getTime())?null:n.toLocaleString(void 0,t?{dateStyle:"medium",timeStyle:"short"}:{dateStyle:"medium"})}let k={auto:"before a new version",import:"before an import",manual:"made by hand"};async function S(e,t){let n=await e.json().catch(()=>({}));if(!e.ok)throw Object.assign(Error(n.error||t),{data:n});return n}let v={display:"flex",gap:10,marginTop:12,flexWrap:"wrap",alignItems:"center"},B={fontSize:12,color:"#667",marginTop:10},T={fontSize:14,fontWeight:650,margin:"26px 0 4px",color:"#e8e8ee"},C={display:"flex",gap:8,alignItems:"flex-start",marginTop:12,fontSize:13,color:"#c8d0d0",lineHeight:1.5,cursor:"pointer"};function D({label:e,children:n}){return(0,t.jsxs)("div",{style:{display:"flex",gap:12,justifyContent:"space-between",padding:"7px 0",borderTop:r.LINE,fontSize:13.5},children:[(0,t.jsx)("span",{style:{color:"#8b9a9a"},children:e}),(0,t.jsx)("span",{style:{color:"#e8e8ee",textAlign:"right"},children:n})]})}function I(){return(0,t.jsx)("a",{href:"https://github.com/blakeb056/six-degrees#undo-an-import",target:"_blank",rel:"noreferrer",style:{color:"inherit",textDecoration:"underline"},children:"Undo an import"})}function $(){let[e,o]=(0,n.useState)(null),[i,a]=(0,n.useState)(null),[s,l]=(0,n.useState)(null),[d,c]=(0,n.useState)(null),[h,p]=(0,n.useState)(null),[u,y]=(0,n.useState)(null),[g,f]=(0,n.useState)(!0),[x,$]=(0,n.useState)(null),[F,M]=(0,n.useState)(!1),[R,z]=(0,n.useState)(!1),E=(0,n.useRef)(null),L=(0,n.useRef)(!1),N=(0,n.useCallback)(()=>fetch("/api/data",{cache:"no-store"}).then(e=>S(e,"The data folder could not be read.")).then(e=>{let t=Date.parse(e.lastImport?.appliedAt||"");o({...e,importIsRecent:Number.isFinite(t)&&Date.now()-t<864e5}),a(null)}).catch(e=>a(e.message)),[]);async function A(){c(null);try{await navigator.clipboard.writeText(e.dataDir),c({tone:"ok",text:"Copied the folder’s path."})}catch{c({tone:"bad",text:"This window can’t copy. Select the path above and copy it instead."})}}async function O(){l("reveal"),c(null);try{await S(await fetch("/api/data/reveal",{method:"POST"}),"The folder could not be opened."),c({tone:"ok",text:"darwin"===e.platform?"Opened in Finder.":"Opened in your file browser."})}catch(e){c({tone:"bad",text:e.message})}finally{l(null)}}async function U(){l("export"),p(null);try{let e,t=await fetch("/api/data/export",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({photos:g})});t.ok||await S(t,"The copy could not be made.");let n=await t.blob(),o=/filename="([^"]+)"/.exec(t.headers.get("content-disposition")||"")?.[1]||"Six Degrees backup.sixdegrees",i=URL.createObjectURL(n),a=document.createElement("a");a.href=i,a.download=o,a.style.position="fixed",a.style.left="-9999px",document.body.appendChild(a),a.click(),a.remove(),setTimeout(()=>URL.revokeObjectURL(i),6e4);let r=[(e=Number(t.headers.get("x-six-degrees-people")),j(e,"person","people"))];r.push(g?j(Number(t.headers.get("x-six-degrees-photos")),"photo"):"no photos"),p({tone:"ok",text:`Made “${o}” (${m(n.size)}: ${r.join(", ")}). Look for it in your Downloads folder, or wherever you chose to save it.`})}catch(e){p({tone:"bad",text:e.message})}finally{l(null)}}async function W(){if(x){l("import"),y(null);try{let t={"Content-Type":"application/octet-stream","X-Six-Degrees-Size":String(x.size)};e.people>0&&(t["X-Six-Degrees-Replace"]=String(e.people)),await S(await fetch("/api/data/import",{method:"POST",headers:t,body:x}),"The file could not be imported."),$(null),M(!1),E.current&&(E.current.value=""),await N()}catch(e){e.data?.needsConfirm&&(M(!1),await N()),y({tone:"bad",text:e.message})}finally{l(null)}}}async function Y(){l("cancel"),y(null);try{await S(await fetch("/api/data/import",{method:"DELETE"}),"The import could not be cancelled."),await N(),y({tone:"ok",text:"Cancelled. The network here stays as it is."})}catch(e){y({tone:"bad",text:e.message})}finally{l(null)}}async function P(){l("restart"),y(null);try{await S(await fetch("/api/data/restart",{method:"POST"}),"Six Degrees could not restart."),z(!0);let e=e=>new Promise(t=>setTimeout(t,e)),t=Date.now()+9e4;for(await e(2500);Date.now()<t;){try{if((await fetch("/api/data",{cache:"no-store"})).ok)return void window.location.reload()}catch{}await e(1e3)}z(!1),y({tone:"bad",text:"Six Degrees didn’t come back. Quit it and open it again: the import finishes as it starts."})}catch(e){y({tone:"bad",text:e.message})}finally{l(null)}}if((0,n.useEffect)(()=>{N()},[N]),(0,n.useEffect)(()=>{e&&!L.current&&(L.current=!0,"#data"===window.location.hash&&document.getElementById("data")?.scrollIntoView({block:"start"}))},[e]),!e)return(0,t.jsx)(r.Section,{id:"data",title:"Your data",children:i?(0,t.jsx)(r.Status,{tone:"bad",children:i}):(0,t.jsx)(r.Body,{children:"Loading…"})});let H=e.pending,V=e.photosInCopy||e.photos,G=e.backups||[],K=G.reduce((e,t)=>e+(t.bytes||0),0),_=!!(x&&x.size>e.maxImportBytes),q=e.people>0,J=e.lastImport;return(0,t.jsxs)(r.Section,{id:"data",title:"Your data",intro:"Everything Six Degrees knows about your network is in one folder on this computer.",children:[(0,t.jsx)(r.Body,{children:(0,t.jsx)(r.Mono,{children:e.dataDir})}),(0,t.jsxs)("div",{style:v,children:[(0,t.jsx)(r.Btn,{onClick:A,children:"Copy the path"}),(0,t.jsx)(r.Btn,{onClick:O,disabled:"reveal"===s,children:"reveal"===s?"Opening…":"darwin"===e.platform?"Show in Finder":"Open the folder"})]}),d&&(0,t.jsx)(r.Status,{tone:d.tone,children:d.text}),(0,t.jsxs)("div",{style:{marginTop:16,borderBottom:r.LINE},children:[(0,t.jsxs)(D,{label:"Your network",children:[j(e.people,"person","people")," · ",m(e.databaseBytes)]}),(0,t.jsx)(D,{label:"Profile photos",children:e.photos.count?`${b(e.photos.count)} \xb7 ${m(e.photos.bytes)}`:"none saved yet"}),(0,t.jsx)(D,{label:"Backups",children:G.length?`${j(G.length,"copy","copies")} \xb7 ${m(K)}`:"none yet"}),(0,t.jsx)(D,{label:"LinkedIn sign-in for scanning",children:e.linkedinSignIn?"kept here, never put in a copy":"not signed in on this computer"})]}),G.length>0&&(0,t.jsxs)("details",{style:{marginTop:10,fontSize:13,color:"#8b9a9a"},children:[(0,t.jsx)("summary",{style:{cursor:"pointer"},children:"The backups"}),(0,t.jsx)("div",{style:{display:"grid",gridTemplateColumns:"minmax(0, 1fr) auto auto",gap:"6px 14px",marginTop:8},children:G.map(e=>(0,t.jsxs)("div",{style:{display:"contents"},children:[(0,t.jsxs)("span",{style:{wordBreak:"break-all",color:"#c8d0d0"},children:[e.name,e.folder?"/":"",(0,t.jsxs)("span",{style:{color:"#667"},children:[" · ",e.folder?"its photos and files":k[e.kind]||e.kind]})]}),(0,t.jsx)("span",{children:w(e.modifiedAt)}),(0,t.jsx)("span",{style:{textAlign:"right"},children:m(e.bytes)})]},e.name))})]}),(0,t.jsx)(r.Body,{style:B,children:"Backups are copies of your network from before a new version or an import. The newest five from new versions are kept; copies from before an import stay until you delete them."}),(0,t.jsx)(r.Body,{style:B,children:"The folder can’t be moved from here. A database that a sync service (iCloud Drive, Dropbox) copies while it’s open can be damaged, and this folder also holds your LinkedIn sign-in, which should never be synced. To use your network on another computer, save a copy below and import it there."}),(0,t.jsx)("h3",{style:T,children:"Move your network to another computer"}),(0,t.jsx)(r.Body,{children:"Save a copy here, then on the new computer install Six Degrees, open Settings → Your data and import the copy. Sign in to LinkedIn again there before you scan: your sign-in never goes into a copy."}),(0,t.jsxs)("label",{style:C,children:[(0,t.jsx)("input",{type:"checkbox",checked:g,onChange:e=>f(e.target.checked),style:{marginTop:3}}),(0,t.jsxs)("span",{children:["Include profile photos",V.count?` (${b(V.count)}, ${m(V.bytes)})`:"",". They can’t be downloaded again without a new scan."]})]}),(0,t.jsxs)("div",{style:v,children:[(0,t.jsx)(r.Btn,{primary:!0,onClick:U,disabled:!!s||R||0===e.people,children:"export"===s?"Saving…":"Save a copy of my network"}),0===e.people&&(0,t.jsx)("span",{style:{fontSize:13,color:"#8b9a9a"},children:"There’s no network here to save yet."})]}),h&&(0,t.jsx)(r.Status,{tone:h.tone,children:h.text}),(0,t.jsx)(r.Body,{style:B,children:"The copy holds the names, headlines and photos of the people in your network. Keep it private: don’t post it or share it, and delete it once it has been imported. A network opened from a LinkedIn CSV lives only in its browser tab, so it isn’t in the copy; import the CSV again on the new computer."}),(0,t.jsx)("h3",{style:T,children:"Bring in a network from another computer"}),H?(0,t.jsxs)(r.Status,{children:[(0,t.jsx)("div",{style:{fontWeight:650},children:"An import is waiting to finish."}),(0,t.jsxs)("div",{children:["The network in the copy",H.exportedAt?` saved ${w(H.exportedAt,!1)}`:""," ","(",j(H.people,"person","people"),H.photos?`, ${j(H.photos,"photo")}`:"",H.fromVersion?`, from Six Degrees ${H.fromVersion}`:"",")",H.replacedPeople>0?` replaces the ${j(H.replacedPeople,"person","people")} here the next time Six Degrees starts. A copy of what’s here now is kept in backups first, so the import can be undone.`:" becomes the network here the next time Six Degrees starts."," ","Your LinkedIn search budget and any pause on scanning are kept."]}),H.error&&(0,t.jsxs)("div",{style:{color:"#ff7676",marginTop:6},children:["The last try stopped: ",H.error.replace(/\.$/,""),". It tries again the next time Six Degrees starts."]}),R?(0,t.jsx)("div",{style:{marginTop:8},children:"Restarting… this page comes back in a few seconds."}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("div",{style:{marginTop:8},children:e.restart.how}),e.restart.command&&(0,t.jsx)("div",{style:{marginTop:6},children:(0,t.jsx)(r.Mono,{children:e.restart.command})}),(0,t.jsxs)("div",{style:v,children:[e.restart.canRestart&&(0,t.jsx)(r.Btn,{primary:!0,onClick:P,disabled:!!s,children:"restart"===s?"Restarting…":"Restart now"}),!H.started&&(0,t.jsx)(r.Btn,{onClick:Y,disabled:!!s,children:"cancel"===s?"Cancelling…":"Cancel the import"})]})]})]}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(r.Body,{children:"Pick the copy you saved on the other computer (a .sixdegrees file). It replaces the network here; the two networks are never merged. Your LinkedIn search budget and any pause on scanning are kept, with the other computer’s searches added."}),(0,t.jsx)("input",{ref:E,type:"file",accept:".sixdegrees",onChange:function(e){y(null),M(!1),$(e.target.files?.[0]||null)},style:{display:"none"}}),(0,t.jsxs)("div",{style:v,children:[(0,t.jsx)(r.Btn,{onClick:()=>E.current?.click(),disabled:!!s,children:"Choose a file…"}),x&&(0,t.jsxs)("span",{style:{fontSize:13,color:"#c8d0d0",wordBreak:"break-all"},children:[x.name," · ",m(x.size)]})]}),_&&(0,t.jsxs)(r.Status,{tone:"bad",children:["That file is ",m(x.size),". This copy can import files up to ",m(e.maxImportBytes),"."]}),x&&q&&!_&&(0,t.jsxs)("label",{style:C,children:[(0,t.jsx)("input",{type:"checkbox",checked:F,onChange:e=>M(e.target.checked),style:{marginTop:3}}),(0,t.jsxs)("span",{children:["Replace the ",j(e.people,"person","people")," in this copy’s network with the network in this file. A copy of what’s here is kept in backups first. Your search budget and any pause on scanning are kept too."]})]}),(0,t.jsx)("div",{style:v,children:(0,t.jsx)(r.Btn,{primary:!0,onClick:W,disabled:!x||_||q&&!F||!!s,children:"import"===s?"Checking the file…":"Import"})})]}),u&&(0,t.jsx)(r.Status,{tone:u.tone,children:u.text}),J&&!H&&(e.importIsRecent?(0,t.jsxs)(r.Status,{tone:"ok",children:["Imported ",w(J.appliedAt),": ",j(J.people,"person","people"),J.exportedAt?` from the copy saved ${w(J.exportedAt,!1)}`:"",".",J.keptDatabase&&(0,t.jsxs)(t.Fragment,{children:[" ","What was here before is kept in ",(0,t.jsx)(r.Mono,{children:J.keptDatabase}),J.keptFiles?", with its photos and files beside it":"",".",J.keptAsIs&&" It couldn’t be read, so it was kept exactly as it was."," ","To go back to it, see ",(0,t.jsx)(I,{}),"."]})]}):(0,t.jsxs)(r.Body,{style:B,children:["Last import: ",w(J.appliedAt)," (",j(J.people,"person","people"),").",J.keptDatabase&&(0,t.jsxs)(t.Fragment,{children:[" What was here before is kept in ",(0,t.jsx)(r.Mono,{children:J.keptDatabase})," (",(0,t.jsx)(I,{}),")."]})]}))]})}var F=e.i(64745);let M={"mac-app":"the Mac app",npm:"the npm package (npx six-degrees)",source:"a copy built from the source code",git:"a git checkout of the source code"};function R(){let[e,a]=(0,n.useState)(null),[l,d]=(0,n.useState)(null),c=(0,i.useRouter)();if((0,n.useEffect)(()=>{let e=window.location.hash;("#sector"===e||"#tiers"===e)&&c.replace(`/scores${e}`)},[c]),(0,n.useEffect)(()=>{fetch("/api/settings").then(e=>e.json().then(t=>e.ok?t:Promise.reject(Error(t.error||"Could not load settings.")))).then(a).catch(e=>d(e.message))},[]),F.IS_DEMO)return(0,t.jsxs)("div",{style:{minHeight:"100vh",background:"#0a0a1a",color:"rgba(255,255,255,0.7)",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:12,textAlign:"center",padding:24,fontFamily:r.FONT},children:[(0,t.jsx)("h2",{style:{margin:0,fontSize:20,fontWeight:700,color:"#fff"},children:"Not part of the demo"}),(0,t.jsx)("p",{style:{margin:0,fontSize:13},children:"The public demo includes the Network Circle and Degrees views only."}),(0,t.jsx)(o.default,{href:"/",style:{fontSize:12,color:"rgba(255,255,255,0.5)",textDecoration:"none"},children:"← Back to the network"})]});let h=e?.about;return(0,t.jsxs)("div",{style:{minHeight:"100vh",background:"#0a0a1a",color:"#fff",fontFamily:r.FONT},children:[(0,t.jsxs)("header",{style:{padding:"16px 24px",borderBottom:r.LINE,display:"flex",alignItems:"center",gap:16},children:[(0,t.jsx)(o.default,{href:"/",style:{display:"flex",alignItems:"center",gap:6,color:"#888",textDecoration:"none",fontSize:13,fontWeight:600,padding:"6px 14px",borderRadius:6,background:"rgba(255,255,255,0.06)",border:r.LINE},children:"← Back to Map"}),(0,t.jsx)("h1",{style:{fontSize:22,fontWeight:700,margin:0,background:"linear-gradient(135deg, #FFD700, #9B59B6, #3498DB)",WebkitBackgroundClip:"text",WebkitTextFillColor:"transparent"},children:"Settings"})]}),(0,t.jsxs)("main",{style:{maxWidth:720,margin:"0 auto",padding:"8px 24px 64px"},children:[l&&(0,t.jsx)(r.Body,{style:{color:"#ff7676",marginTop:16},children:l}),(0,t.jsx)(s,{}),(0,t.jsx)(r.Section,{id:"scoring",title:"Your field and tiers",children:(0,t.jsxs)(r.Body,{children:["They’re on the ",(0,t.jsx)(o.default,{href:"/scores",style:{color:"#3498DB"},children:"Scores"})," tab now, beside every company’s score: ",(0,t.jsx)(o.default,{href:"/scores#sector",style:{color:"#3498DB"},children:"your field"})," and"," ",(0,t.jsx)(o.default,{href:"/scores#tiers",style:{color:"#3498DB"},children:"how tiers are graded"}),"."]})}),(0,t.jsx)($,{}),(0,t.jsx)(r.Section,{id:"about",title:"About this copy",children:h?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(r.Body,{children:["Version ",(0,t.jsx)(r.Mono,{children:h.version}),", running as ",M[h.kind]||h.kind,"."]}),(0,t.jsxs)(r.Body,{children:["Your network is kept in ",(0,t.jsx)(r.Mono,{children:h.dataDir}),h.customDataDir?" (a folder you chose).":".","mac-app"===h.kind&&" Help → Show the Data Folder opens it."]}),(0,t.jsx)(r.Body,{style:{fontSize:12,color:"#667",marginTop:10},children:"Settings are saved with your network, on this computer. Nothing here is sent anywhere."})]}):!l&&(0,t.jsx)(r.Body,{children:"Loading…"})})]})]})}e.s(["default",0,function(){return(0,t.jsx)(a.default,{children:(0,t.jsx)(R,{})})}],5445)},18566,(e,t,n)=>{t.exports=e.r(76562)}]);
1
+ (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,2776,e=>{"use strict";var t=e.i(43476),n=e.i(15812);e.s(["default",0,function({children:e}){let{userId:o,ready:i}=(0,n.useUser)();return i&&o?e:(0,t.jsx)("div",{style:{minHeight:"100vh",display:"flex",alignItems:"center",justifyContent:"center",background:"#0a0a1a",color:"#fff",padding:24,textAlign:"center",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'},children:i?(0,t.jsxs)("div",{style:{maxWidth:420},children:[(0,t.jsx)("div",{style:{fontSize:18,fontWeight:700,marginBottom:8},children:"Can’t reach Six Degrees’ local server"}),(0,t.jsx)("div",{style:{color:"#888",fontSize:14,lineHeight:1.6},children:"The page loaded but the app behind it is not answering. If you started it from a terminal, check that window for an error, then reload this page."})]}):(0,t.jsx)("div",{style:{fontSize:18,fontWeight:600},children:"Loading…"})})}])},8819,e=>{"use strict";var t=e.i(43476);let n="1px solid rgba(255,255,255,0.1)";function o({children:e,style:n}){return(0,t.jsx)("div",{style:{fontSize:13.5,color:"#8b9a9a",lineHeight:1.6,marginTop:4,...n},children:e})}e.s(["Body",0,o,"Btn",0,function({children:e,onClick:o,disabled:i,primary:a,tone:s,type:r="button"}){return(0,t.jsx)("button",{type:r,onClick:o,disabled:i,style:{padding:"9px 18px",borderRadius:7,fontSize:13.5,fontWeight:650,color:i?"#667":"#fff",border:n,background:i?"rgba(255,255,255,0.05)":"bad"===s?"rgba(255,80,80,0.15)":a?"linear-gradient(135deg, #9B59B6, #3498DB)":"rgba(255,255,255,0.08)",cursor:i?"not-allowed":"pointer"},children:e})},"FONT",0,'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',"LINE",0,n,"Mono",0,function({children:e}){return(0,t.jsx)("code",{style:{background:"rgba(255,255,255,0.08)",padding:"1px 5px",borderRadius:4,wordBreak:"break-all"},children:e})},"Section",0,function({id:e,title:i,intro:a,children:s}){return(0,t.jsxs)("section",{id:e,style:{padding:"24px 0",borderBottom:n,scrollMarginTop:16},children:[(0,t.jsx)("h2",{style:{fontSize:16,fontWeight:650,margin:"0 0 6px"},children:i}),a&&(0,t.jsx)(o,{style:{marginTop:0,marginBottom:12},children:a}),s]})},"Status",0,function({children:e,tone:n}){return(0,t.jsxs)("div",{role:"status",style:{marginTop:10,padding:"10px 14px",borderRadius:8,fontSize:13.5,lineHeight:1.6,color:"ok"===n?"#00ff88":"bad"===n?"#ff7676":"#e8e8ee",background:"ok"===n?"rgba(0,255,136,0.08)":"bad"===n?"rgba(255,80,80,0.08)":"rgba(255,255,255,0.05)",border:`1px solid ${"ok"===n?"rgba(0,255,136,0.3)":"bad"===n?"rgba(255,80,80,0.3)":"rgba(255,255,255,0.12)"}`},children:["ok"===n&&"✓ ",e]})}])},5445,e=>{"use strict";var t=e.i(43476),n=e.i(71645),o=e.i(22016),i=e.i(18566),a=e.i(2776),s=e.i(8819);function r(){let[e,o]=(0,n.useState)(null);return((0,n.useEffect)(()=>{fetch("/api/update").then(e=>e.json()).then(o).catch(()=>{})},[]),e)?e.installed?(0,t.jsx)(h,{local:e}):(0,t.jsx)(d,{local:e}):null}async function l(e){let t=await fetch("/api/update",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}),n=await t.json().catch(()=>({}));return{ok:t.ok,d:n}}function d({local:e}){let[o,i]=(0,n.useState)(null),[a,r]=(0,n.useState)(null),[c,h]=(0,n.useState)(null),[p,u]=(0,n.useState)(null);async function y(e){r(e),h(null);try{let{ok:t,d:n}=await l({action:e});if(!t){h(n.error||"Something went wrong."),n.dirty&&i({dirty:n.dirty});return}"check"===e?i(n):(u(n),i(null))}catch(e){h(e.message)}finally{r(null)}}return(0,n.useEffect)(()=>{"updates"===new URLSearchParams(window.location.search).get("check")&&(document.getElementById("updates")?.scrollIntoView({block:"center"}),y("check"),window.history.replaceState(null,"",window.location.pathname))},[]),(0,t.jsxs)(s.Section,{id:"updates",title:"Updates",children:[p?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(s.Body,{children:["Updated to ",(0,t.jsx)(s.Mono,{children:p.sha})," — “",p.subject,"”."]}),(0,t.jsx)(s.Body,{style:{color:p.needsRestart?"#FFD700":void 0},children:p.needsRestart?"Stop the app in your terminal and start it again — this update changed how it starts.":"The page will pick up most changes on its own. Restart the app if anything looks odd."})]}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(s.Body,{children:["You are on ",(0,t.jsx)(s.Mono,{children:e.sha})," — “",e.subject,"”."]}),o&&0===o.behind&&(0,t.jsx)(s.Status,{tone:"ok",children:"You’re up to date."}),o&&o.behind>0&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(s.Body,{style:{color:"#00ff88"},children:[o.behind," update",1===o.behind?"":"s"," available."]}),(0,t.jsx)("pre",{style:x,children:o.commits.join("\n")})]}),o?.dirty?.length>0&&(0,t.jsxs)(s.Body,{children:["Changed files here:"," ",(0,t.jsx)(s.Mono,{children:o.dirty.join(", ")}),". Commit or discard them first — this will not throw away your work."]}),(0,t.jsxs)(f,{children:[(0,t.jsx)(s.Btn,{onClick:()=>y("check"),disabled:!!a,children:"check"===a?"Checking…":"Check for updates"}),o?.behind>0&&(0,t.jsx)(s.Btn,{onClick:()=>y("pull"),disabled:!!a,primary:!0,children:"pull"===a?"Updating…":`Install ${o.behind} update${1===o.behind?"":"s"}`})]})]}),c&&(0,t.jsx)(s.Body,{style:{color:"#ff7676"},children:c}),(0,t.jsxs)(s.Body,{style:{fontSize:12,color:"#667",marginTop:12},children:["Nothing is checked automatically and nothing about you is sent — this runs the same ",(0,t.jsx)(s.Mono,{children:"git fetch"})," and ",(0,t.jsx)(s.Mono,{children:"git pull"})," you would type yourself."]})]})}let c=["checking","downloading","verifying","preparing","restarting"];function h({local:e}){let o="mac-app"===e.kind,[i,a]=(0,n.useState)(!1),[r,d]=(0,n.useState)(null),[m,b]=(0,n.useState)(null),[j,w]=(0,n.useState)(!1),[k,S]=(0,n.useState)(null),[v,B]=(0,n.useState)(e.job||null),[T,C]=(0,n.useState)(!1),[D,I]=(0,n.useState)(null),[$,F]=(0,n.useState)(null),[M,R]=(0,n.useState)(void 0),[z,E]=(0,n.useState)(0),[L,N]=(0,n.useState)(!1),A=!!(v&&c.includes(v.phase)),O=A&&("restarting"===v.phase||z>0);async function U(){a(!0),d(null),b(null),I(null),F(null),R(void 0),B(e=>e&&c.includes(e.phase)?e:null);try{let{ok:e,d:t}=await l({action:"check-release"});e?(d(t),S(new Date)):b(t.error||"Could not check.")}catch(e){b(e.message)}finally{a(!1)}}async function W(){C(!0),I(null),F(null),R(void 0),E(0),N(!1);try{let{ok:e,d:t}=await l({action:"install-release"});t.job&&B(t.job),!e&&(I(t.error||"The update could not start."),F(t.refusal||null),"fallback"in t&&R(t.fallback))}catch(e){I(e.message)}finally{C(!1)}}async function Y(){try{let{d:e}=await l({action:"cancel-install"});e.job&&B(e.job)}catch{}}async function P(){try{await navigator.clipboard.writeText(e.command),w(!0),setTimeout(()=>w(!1),1600)}catch{b("Could not copy — select the line and copy it by hand.")}}(0,n.useEffect)(()=>{"#updates"===window.location.hash&&document.getElementById("updates")?.scrollIntoView({block:"start"}),"updates"!==new URLSearchParams(window.location.search).get("check")||(window.history.replaceState(null,"",window.location.pathname),e.job&&c.includes(e.job.phase)||(document.getElementById("updates")?.scrollIntoView({block:"center"}),U().then(()=>document.getElementById("updates")?.scrollIntoView({block:"end",behavior:"smooth"}))))},[e.job]),(0,n.useEffect)(()=>{if(!A)return;let e=!0,t=setTimeout(async()=>{try{if(O){let t=await fetch("/api/update",{cache:"no-store"}),n=await t.json();if(!e)return;if(!n.job||n.job.id!==v.id)return void window.location.reload();E(0),B(n.job)}else{let{ok:t,d:n}=await l({action:"update-status"});e&&t&&n.job&&B(n.job)}}catch{e&&E(e=>e+1)}},O?1500:600);return()=>{e=!1,clearTimeout(t)}},[v,z,A,O]),(0,n.useEffect)(()=>{if(!O)return;let e=setTimeout(()=>N(!0),6e4);return()=>clearTimeout(e)},[O]);let H=v?.phase==="failed",V=o&&r?.install?.possible,G=H&&"stale-check"===v.code||"not-checked"===$,K=void 0!==M?M:r?.fallback,_=r?.newer&&(!o||K)&&(!V||H||D||e.lastUpdate?.tone==="bad"),q=function({mac:e,kind:t,canInstall:n,fallback:o}){if(!e)return"source"===t?"A copy built from the source code updates by fetching the code and building it again, which it can't do while it runs. Stop it (Ctrl-C), then run this in the six-degrees folder. Your network stays where it is.":"This copy runs inside the terminal that started it, so it can't replace itself while it runs. Stop it first (Ctrl-C), then run this to start the newest version. Your network stays where it is.";if(!o)return null;let i=o.dataDir?` It opens the new version on the usual data folder, not on ${o.dataDir}: to use that one, quit it and open it again with --data-dir, as you opened this one.`:"";return"replace"===o.mode?`${n?"Or paste this into Terminal.":"Paste this into Terminal instead."} It closes this app, puts the new version in its place and opens it. Your network stays where it is.${i}`:`${n?"Or copy":"Copy"} this line, quit Six Degrees, then paste it into Terminal. It installs the new version at ${o.installsTo}, not where this copy is, and opens it: use that one from then on. Your network stays where it is.${i}`}({mac:o,kind:e.kind,canInstall:V,fallback:K});return(0,t.jsxs)(s.Section,{id:"updates",title:"Updates",children:[e.lastUpdate&&!A&&(0,t.jsx)(y,{report:e.lastUpdate}),(0,t.jsxs)(s.Body,{children:["You have version ",(0,t.jsx)(s.Mono,{children:e.version}),"."]}),A?(0,t.jsx)(u,{job:v,restarting:O,slow:L,onCancel:Y}):(0,t.jsxs)(t.Fragment,{children:[H&&(0,t.jsxs)(s.Status,{tone:"bad",children:[(0,t.jsx)("strong",{children:"The update didn’t finish."})," ",v.error," Nothing was changed."]}),v?.phase==="cancelled"&&(0,t.jsx)(s.Status,{children:"Cancelled. Nothing was changed."}),D&&(0,t.jsx)(s.Status,{tone:"bad",children:D}),r&&!r.latest&&(0,t.jsx)(s.Status,{children:"No release has been published yet."}),r?.latest&&!r.newer&&(0,t.jsxs)(s.Status,{tone:"ok",children:["You’re up to date: ",r.latest.version," is the newest version.",k&&(0,t.jsxs)("span",{style:{color:"#8b9a9a"},children:[" Checked at ",k.toLocaleTimeString([],{hour:"numeric",minute:"2-digit"}),"."]})]}),r?.newer&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(s.Body,{style:{color:"#00ff88"},children:["Version ",r.latest.version," is available."]}),V&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(s.Body,{children:["It downloads ",r.install.size?`about ${p(r.install.size)} MB`:"the new version"," from GitHub, checks it, then closes, replaces itself and reopens. Your network isn’t touched, and a backup of it is made first."]}),(0,t.jsxs)(f,{children:[G?(0,t.jsx)(s.Btn,{onClick:U,disabled:i,primary:!0,children:i?"Checking…":"Check again"}):(0,t.jsx)(s.Btn,{onClick:W,disabled:T,primary:!0,children:T?"Starting…":H||D?"Try again":"Install and restart"}),(0,t.jsx)(g,{url:r.latest.url})]})]}),o&&!V&&r.install?.reason&&(0,t.jsx)(s.Body,{children:r.install.reason}),_&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(s.Body,{children:q}),e.testReleases?(0,t.jsx)("pre",{style:x,children:"Not shown in test mode: it would install the real release from GitHub into Applications."}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("pre",{style:x,children:e.command}),(0,t.jsxs)(f,{children:[(0,t.jsx)(s.Btn,{onClick:P,primary:!V,children:j?"Copied":"Copy"}),!V&&(0,t.jsx)(g,{url:r.latest.url})]})]})]}),!V&&!_&&(0,t.jsx)(f,{children:(0,t.jsx)(g,{url:r.latest.url})})]}),!r?.newer&&(0,t.jsx)(f,{children:(0,t.jsx)(s.Btn,{onClick:U,disabled:i,children:i?"Checking…":r?"Check again":"Check for updates"})})]}),m&&(0,t.jsx)(s.Body,{style:{color:"#ff7676"},children:m}),(0,t.jsxs)(s.Body,{style:{fontSize:12,color:"#667",marginTop:12},children:["Nothing is checked automatically. The button asks GitHub for the newest version number, and nothing about you is sent.",o&&" Only a second click, Install and restart, downloads the new version."]}),e.testReleases&&(0,t.jsxs)(s.Body,{style:{fontSize:12,color:"#FFD700",marginTop:6},children:["Test mode: releases are read from ",(0,t.jsx)(s.Mono,{children:e.testReleases})," on this computer, not from GitHub."]})]})}let p=e=>Math.max(1,Math.round(e/1e6));function u({job:e,restarting:n,slow:o,onCancel:i}){let a=e.total?Math.min(100,Math.round(e.received/e.total*100)):null,r=n?"Restarting… Six Degrees closes and opens again in a moment.":"checking"===e.phase?"Asking GitHub for the newest version…":"downloading"===e.phase?`Downloading ${e.version}…${null!==a?` ${a}% (${p(e.received)} of ${p(e.total)} MB)`:""}`:"verifying"===e.phase?"Checking the download…":"Preparing the new version…";return(0,t.jsxs)("div",{role:"status","aria-live":"polite",style:{marginTop:12},children:[(0,t.jsx)(s.Body,{style:{color:"#e8e8ee"},children:r}),"downloading"===e.phase&&null!==a&&(0,t.jsx)("div",{role:"progressbar","aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":a,"aria-label":"Download",style:{height:6,borderRadius:3,background:"rgba(255,255,255,0.08)",marginTop:10,overflow:"hidden",maxWidth:420},children:(0,t.jsx)("div",{style:{width:`${a}%`,height:"100%",background:"linear-gradient(90deg, #9B59B6, #3498DB)",transition:"width 0.4s ease"}})}),o&&(0,t.jsx)(s.Body,{children:"This is taking longer than it should. If Six Degrees doesn’t open again by itself, open it from your Applications folder."}),!n&&(0,t.jsx)(f,{children:(0,t.jsx)(s.Btn,{onClick:i,children:"Cancel"})})]})}function y({report:e}){let n=new Date(e.at).toLocaleString([],{dateStyle:"medium",timeStyle:"short"});return(0,t.jsxs)(s.Status,{tone:"ok"===e.tone?"ok":"bad",children:[e.text," ",(0,t.jsxs)("span",{style:{color:"#8b9a9a"},children:["(",n,")"]}),"ok"===e.tone&&e.previous&&(0,t.jsxs)("span",{style:{display:"block",fontSize:12.5,color:"#8b9a9a",marginTop:4},children:["A copy of the version you had is kept in ",(0,t.jsx)(s.Mono,{children:e.previous})," until the next update. To go back to it, open that file and drag the app it gives you into your Applications folder."]})]})}function g({url:e}){return e?(0,t.jsx)("a",{href:e,target:"_blank",rel:"noreferrer",style:{color:"#3498DB",fontSize:13.5},children:"What changed →"}):null}function f({children:e}){return(0,t.jsx)("div",{style:{display:"flex",gap:10,marginTop:12,flexWrap:"wrap",alignItems:"center"},children:e})}let x={background:"rgba(0,0,0,0.45)",border:s.LINE,borderRadius:8,padding:12,margin:"8px 0 0",fontSize:12,lineHeight:1.7,color:"#b9c6c6",fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace",whiteSpace:"pre-wrap",maxHeight:180,overflow:"auto"};function m(e){if(!e)return"0 KB";if(e<1048576)return`${Math.max(1,Math.round(e/1024))} KB`;let t=e/1048576;return`${t<10?t.toFixed(1):Math.round(t)} MB`}let b=e=>Number(e||0).toLocaleString("en-US"),j=(e,t,n=`${t}s`)=>`${b(e)} ${1===Number(e)?t:n}`;function w(e,t=!0){if(!e)return null;let n=new Date(e);return Number.isNaN(n.getTime())?null:n.toLocaleString(void 0,t?{dateStyle:"medium",timeStyle:"short"}:{dateStyle:"medium"})}let k={auto:"before a new version",import:"before an import",manual:"made by hand"};async function S(e,t){let n=await e.json().catch(()=>({}));if(!e.ok)throw Object.assign(Error(n.error||t),{data:n});return n}let v={display:"flex",gap:10,marginTop:12,flexWrap:"wrap",alignItems:"center"},B={fontSize:12,color:"#667",marginTop:10},T={fontSize:14,fontWeight:650,margin:"26px 0 4px",color:"#e8e8ee"},C={display:"flex",gap:8,alignItems:"flex-start",marginTop:12,fontSize:13,color:"#c8d0d0",lineHeight:1.5,cursor:"pointer"};function D({label:e,children:n}){return(0,t.jsxs)("div",{style:{display:"flex",gap:12,justifyContent:"space-between",padding:"7px 0",borderTop:s.LINE,fontSize:13.5},children:[(0,t.jsx)("span",{style:{color:"#8b9a9a"},children:e}),(0,t.jsx)("span",{style:{color:"#e8e8ee",textAlign:"right"},children:n})]})}function I(){return(0,t.jsx)("a",{href:"https://github.com/blakeb056/six-degrees#undo-an-import",target:"_blank",rel:"noreferrer",style:{color:"inherit",textDecoration:"underline"},children:"Undo an import"})}function $(){let[e,o]=(0,n.useState)(null),[i,a]=(0,n.useState)(null),[r,l]=(0,n.useState)(null),[d,c]=(0,n.useState)(null),[h,p]=(0,n.useState)(null),[u,y]=(0,n.useState)(null),[g,f]=(0,n.useState)(!0),[x,$]=(0,n.useState)(null),[F,M]=(0,n.useState)(!1),[R,z]=(0,n.useState)(!1),E=(0,n.useRef)(null),L=(0,n.useRef)(!1),N=(0,n.useCallback)(()=>fetch("/api/data",{cache:"no-store"}).then(e=>S(e,"The data folder could not be read.")).then(e=>{let t=Date.parse(e.lastImport?.appliedAt||"");o({...e,importIsRecent:Number.isFinite(t)&&Date.now()-t<864e5}),a(null)}).catch(e=>a(e.message)),[]);async function A(){c(null);try{await navigator.clipboard.writeText(e.dataDir),c({tone:"ok",text:"Copied the folder’s path."})}catch{c({tone:"bad",text:"This window can’t copy. Select the path above and copy it instead."})}}async function O(){l("reveal"),c(null);try{await S(await fetch("/api/data/reveal",{method:"POST"}),"The folder could not be opened."),c({tone:"ok",text:"darwin"===e.platform?"Opened in Finder.":"Opened in your file browser."})}catch(e){c({tone:"bad",text:e.message})}finally{l(null)}}async function U(){l("export"),p(null);try{let e,t=await fetch("/api/data/export",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({photos:g})});t.ok||await S(t,"The copy could not be made.");let n=await t.blob(),o=/filename="([^"]+)"/.exec(t.headers.get("content-disposition")||"")?.[1]||"Six Degrees backup.sixdegrees",i=URL.createObjectURL(n),a=document.createElement("a");a.href=i,a.download=o,a.style.position="fixed",a.style.left="-9999px",document.body.appendChild(a),a.click(),a.remove(),setTimeout(()=>URL.revokeObjectURL(i),6e4);let s=[(e=Number(t.headers.get("x-six-degrees-people")),j(e,"person","people"))];s.push(g?j(Number(t.headers.get("x-six-degrees-photos")),"photo"):"no photos"),p({tone:"ok",text:`Made “${o}” (${m(n.size)}: ${s.join(", ")}). Look for it in your Downloads folder, or wherever you chose to save it.`})}catch(e){p({tone:"bad",text:e.message})}finally{l(null)}}async function W(){if(x){l("import"),y(null);try{let t={"Content-Type":"application/octet-stream","X-Six-Degrees-Size":String(x.size)};e.people>0&&(t["X-Six-Degrees-Replace"]=String(e.people)),await S(await fetch("/api/data/import",{method:"POST",headers:t,body:x}),"The file could not be imported."),$(null),M(!1),E.current&&(E.current.value=""),await N()}catch(e){e.data?.needsConfirm&&(M(!1),await N()),y({tone:"bad",text:e.message})}finally{l(null)}}}async function Y(){l("cancel"),y(null);try{await S(await fetch("/api/data/import",{method:"DELETE"}),"The import could not be cancelled."),await N(),y({tone:"ok",text:"Cancelled. The network here stays as it is."})}catch(e){y({tone:"bad",text:e.message})}finally{l(null)}}async function P(){l("restart"),y(null);try{await S(await fetch("/api/data/restart",{method:"POST"}),"Six Degrees could not restart."),z(!0);let e=e=>new Promise(t=>setTimeout(t,e)),t=Date.now()+9e4;for(await e(2500);Date.now()<t;){try{if((await fetch("/api/data",{cache:"no-store"})).ok)return void window.location.reload()}catch{}await e(1e3)}z(!1),y({tone:"bad",text:"Six Degrees didn’t come back. Quit it and open it again: the import finishes as it starts."})}catch(e){y({tone:"bad",text:e.message})}finally{l(null)}}if((0,n.useEffect)(()=>{N()},[N]),(0,n.useEffect)(()=>{e&&!L.current&&(L.current=!0,"#data"===window.location.hash&&document.getElementById("data")?.scrollIntoView({block:"start"}))},[e]),!e)return(0,t.jsx)(s.Section,{id:"data",title:"Your data",children:i?(0,t.jsx)(s.Status,{tone:"bad",children:i}):(0,t.jsx)(s.Body,{children:"Loading…"})});let H=e.pending,V=e.photosInCopy||e.photos,G=e.backups||[],K=G.reduce((e,t)=>e+(t.bytes||0),0),_=!!(x&&x.size>e.maxImportBytes),q=e.people>0,J=e.lastImport;return(0,t.jsxs)(s.Section,{id:"data",title:"Your data",intro:"Everything Six Degrees knows about your network is in one folder on this computer.",children:[(0,t.jsx)(s.Body,{children:(0,t.jsx)(s.Mono,{children:e.dataDir})}),(0,t.jsxs)("div",{style:v,children:[(0,t.jsx)(s.Btn,{onClick:A,children:"Copy the path"}),(0,t.jsx)(s.Btn,{onClick:O,disabled:"reveal"===r,children:"reveal"===r?"Opening…":"darwin"===e.platform?"Show in Finder":"Open the folder"})]}),d&&(0,t.jsx)(s.Status,{tone:d.tone,children:d.text}),(0,t.jsxs)("div",{style:{marginTop:16,borderBottom:s.LINE},children:[(0,t.jsxs)(D,{label:"Your network",children:[j(e.people,"person","people")," · ",m(e.databaseBytes)]}),(0,t.jsx)(D,{label:"Profile photos",children:e.photos.count?`${b(e.photos.count)} \xb7 ${m(e.photos.bytes)}`:"none saved yet"}),(0,t.jsx)(D,{label:"Backups",children:G.length?`${j(G.length,"copy","copies")} \xb7 ${m(K)}`:"none yet"}),(0,t.jsx)(D,{label:"LinkedIn sign-in for scanning",children:e.linkedinSignIn?"kept here, never put in a copy":"not signed in on this computer"})]}),G.length>0&&(0,t.jsxs)("details",{style:{marginTop:10,fontSize:13,color:"#8b9a9a"},children:[(0,t.jsx)("summary",{style:{cursor:"pointer"},children:"The backups"}),(0,t.jsx)("div",{style:{display:"grid",gridTemplateColumns:"minmax(0, 1fr) auto auto",gap:"6px 14px",marginTop:8},children:G.map(e=>(0,t.jsxs)("div",{style:{display:"contents"},children:[(0,t.jsxs)("span",{style:{wordBreak:"break-all",color:"#c8d0d0"},children:[e.name,e.folder?"/":"",(0,t.jsxs)("span",{style:{color:"#667"},children:[" · ",e.folder?"its photos and files":k[e.kind]||e.kind]})]}),(0,t.jsx)("span",{children:w(e.modifiedAt)}),(0,t.jsx)("span",{style:{textAlign:"right"},children:m(e.bytes)})]},e.name))})]}),(0,t.jsx)(s.Body,{style:B,children:"Backups are copies of your network from before a new version or an import. The newest five from new versions are kept; copies from before an import stay until you delete them."}),(0,t.jsx)(s.Body,{style:B,children:"The folder can’t be moved from here. A database that a sync service (iCloud Drive, Dropbox) copies while it’s open can be damaged, and this folder also holds your LinkedIn sign-in, which should never be synced. To use your network on another computer, save a copy below and import it there."}),(0,t.jsx)("h3",{style:T,children:"Move your network to another computer"}),(0,t.jsx)(s.Body,{children:"Save a copy here, then on the new computer install Six Degrees, open Settings → Your data and import the copy. Sign in to LinkedIn again there before you scan: your sign-in never goes into a copy."}),(0,t.jsxs)("label",{style:C,children:[(0,t.jsx)("input",{type:"checkbox",checked:g,onChange:e=>f(e.target.checked),style:{marginTop:3}}),(0,t.jsxs)("span",{children:["Include profile photos",V.count?` (${b(V.count)}, ${m(V.bytes)})`:"",". They can’t be downloaded again without a new scan."]})]}),(0,t.jsxs)("div",{style:v,children:[(0,t.jsx)(s.Btn,{primary:!0,onClick:U,disabled:!!r||R||0===e.people,children:"export"===r?"Saving…":"Save a copy of my network"}),0===e.people&&(0,t.jsx)("span",{style:{fontSize:13,color:"#8b9a9a"},children:"There’s no network here to save yet."})]}),h&&(0,t.jsx)(s.Status,{tone:h.tone,children:h.text}),(0,t.jsx)(s.Body,{style:B,children:"The copy holds the names, headlines and photos of the people in your network. Keep it private: don’t post it or share it, and delete it once it has been imported. A network opened from a LinkedIn CSV lives only in its browser tab, so it isn’t in the copy; import the CSV again on the new computer. The Social tab’s findings, and any messages you keep there, stay on this computer and aren’t in the copy either."}),(0,t.jsx)("h3",{style:T,children:"Bring in a network from another computer"}),H?(0,t.jsxs)(s.Status,{children:[(0,t.jsx)("div",{style:{fontWeight:650},children:"An import is waiting to finish."}),(0,t.jsxs)("div",{children:["The network in the copy",H.exportedAt?` saved ${w(H.exportedAt,!1)}`:""," ","(",j(H.people,"person","people"),H.photos?`, ${j(H.photos,"photo")}`:"",H.fromVersion?`, from Six Degrees ${H.fromVersion}`:"",")",H.replacedPeople>0?` replaces the ${j(H.replacedPeople,"person","people")} here the next time Six Degrees starts. A copy of what’s here now is kept in backups first, so the import can be undone.`:" becomes the network here the next time Six Degrees starts."," ","Your LinkedIn search budget and any pause on scanning are kept."]}),H.error&&(0,t.jsxs)("div",{style:{color:"#ff7676",marginTop:6},children:["The last try stopped: ",H.error.replace(/\.$/,""),". It tries again the next time Six Degrees starts."]}),R?(0,t.jsx)("div",{style:{marginTop:8},children:"Restarting… this page comes back in a few seconds."}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("div",{style:{marginTop:8},children:e.restart.how}),e.restart.command&&(0,t.jsx)("div",{style:{marginTop:6},children:(0,t.jsx)(s.Mono,{children:e.restart.command})}),(0,t.jsxs)("div",{style:v,children:[e.restart.canRestart&&(0,t.jsx)(s.Btn,{primary:!0,onClick:P,disabled:!!r,children:"restart"===r?"Restarting…":"Restart now"}),!H.started&&(0,t.jsx)(s.Btn,{onClick:Y,disabled:!!r,children:"cancel"===r?"Cancelling…":"Cancel the import"})]})]})]}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(s.Body,{children:"Pick the copy you saved on the other computer (a .sixdegrees file). It replaces the network here; the two networks are never merged. Your LinkedIn search budget and any pause on scanning are kept, with the other computer’s searches added."}),(0,t.jsx)("input",{ref:E,type:"file",accept:".sixdegrees",onChange:function(e){y(null),M(!1),$(e.target.files?.[0]||null)},style:{display:"none"}}),(0,t.jsxs)("div",{style:v,children:[(0,t.jsx)(s.Btn,{onClick:()=>E.current?.click(),disabled:!!r,children:"Choose a file…"}),x&&(0,t.jsxs)("span",{style:{fontSize:13,color:"#c8d0d0",wordBreak:"break-all"},children:[x.name," · ",m(x.size)]})]}),_&&(0,t.jsxs)(s.Status,{tone:"bad",children:["That file is ",m(x.size),". This copy can import files up to ",m(e.maxImportBytes),"."]}),x&&q&&!_&&(0,t.jsxs)("label",{style:C,children:[(0,t.jsx)("input",{type:"checkbox",checked:F,onChange:e=>M(e.target.checked),style:{marginTop:3}}),(0,t.jsxs)("span",{children:["Replace the ",j(e.people,"person","people")," in this copy’s network with the network in this file. A copy of what’s here is kept in backups first. Your search budget and any pause on scanning are kept too."]})]}),(0,t.jsx)("div",{style:v,children:(0,t.jsx)(s.Btn,{primary:!0,onClick:W,disabled:!x||_||q&&!F||!!r,children:"import"===r?"Checking the file…":"Import"})})]}),u&&(0,t.jsx)(s.Status,{tone:u.tone,children:u.text}),J&&!H&&(e.importIsRecent?(0,t.jsxs)(s.Status,{tone:"ok",children:["Imported ",w(J.appliedAt),": ",j(J.people,"person","people"),J.exportedAt?` from the copy saved ${w(J.exportedAt,!1)}`:"",".",J.keptDatabase&&(0,t.jsxs)(t.Fragment,{children:[" ","What was here before is kept in ",(0,t.jsx)(s.Mono,{children:J.keptDatabase}),J.keptFiles?", with its photos and files beside it":"",".",J.keptAsIs&&" It couldn’t be read, so it was kept exactly as it was."," ","To go back to it, see ",(0,t.jsx)(I,{}),"."]})]}):(0,t.jsxs)(s.Body,{style:B,children:["Last import: ",w(J.appliedAt)," (",j(J.people,"person","people"),").",J.keptDatabase&&(0,t.jsxs)(t.Fragment,{children:[" What was here before is kept in ",(0,t.jsx)(s.Mono,{children:J.keptDatabase})," (",(0,t.jsx)(I,{}),")."]})]}))]})}var F=e.i(64745);let M={"mac-app":"the Mac app",npm:"the npm package (npx six-degrees)",source:"a copy built from the source code",git:"a git checkout of the source code"};function R(){let[e,a]=(0,n.useState)(null),[l,d]=(0,n.useState)(null),c=(0,i.useRouter)();if((0,n.useEffect)(()=>{let e=window.location.hash;("#sector"===e||"#tiers"===e)&&c.replace(`/scores${e}`)},[c]),(0,n.useEffect)(()=>{fetch("/api/settings").then(e=>e.json().then(t=>e.ok?t:Promise.reject(Error(t.error||"Could not load settings.")))).then(a).catch(e=>d(e.message))},[]),F.IS_DEMO)return(0,t.jsxs)("div",{style:{minHeight:"100vh",background:"#0a0a1a",color:"rgba(255,255,255,0.7)",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:12,textAlign:"center",padding:24,fontFamily:s.FONT},children:[(0,t.jsx)("h2",{style:{margin:0,fontSize:20,fontWeight:700,color:"#fff"},children:"Not part of the demo"}),(0,t.jsx)("p",{style:{margin:0,fontSize:13},children:"The public demo includes the Network Circle and Degrees views only."}),(0,t.jsx)(o.default,{href:"/",style:{fontSize:12,color:"rgba(255,255,255,0.5)",textDecoration:"none"},children:"← Back to the network"})]});let h=e?.about;return(0,t.jsxs)("div",{style:{minHeight:"100vh",background:"#0a0a1a",color:"#fff",fontFamily:s.FONT},children:[(0,t.jsxs)("header",{style:{padding:"16px 24px",borderBottom:s.LINE,display:"flex",alignItems:"center",gap:16},children:[(0,t.jsx)(o.default,{href:"/",style:{display:"flex",alignItems:"center",gap:6,color:"#888",textDecoration:"none",fontSize:13,fontWeight:600,padding:"6px 14px",borderRadius:6,background:"rgba(255,255,255,0.06)",border:s.LINE},children:"← Back to Map"}),(0,t.jsx)("h1",{style:{fontSize:22,fontWeight:700,margin:0,background:"linear-gradient(135deg, #FFD700, #9B59B6, #3498DB)",WebkitBackgroundClip:"text",WebkitTextFillColor:"transparent"},children:"Settings"})]}),(0,t.jsx)("div",{id:"scan-bar-slot"}),(0,t.jsxs)("main",{style:{maxWidth:720,margin:"0 auto",padding:"8px 24px 64px"},children:[l&&(0,t.jsx)(s.Body,{style:{color:"#ff7676",marginTop:16},children:l}),(0,t.jsx)(r,{}),(0,t.jsx)(s.Section,{id:"scoring",title:"Your field and tiers",children:(0,t.jsxs)(s.Body,{children:["They’re on the ",(0,t.jsx)(o.default,{href:"/scores",style:{color:"#3498DB"},children:"Scores"})," tab now, beside every company’s score: ",(0,t.jsx)(o.default,{href:"/scores#sector",style:{color:"#3498DB"},children:"your field"})," and"," ",(0,t.jsx)(o.default,{href:"/scores#tiers",style:{color:"#3498DB"},children:"how tiers are graded"}),"."]})}),(0,t.jsx)($,{}),(0,t.jsx)(s.Section,{id:"about",title:"About this copy",children:h?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(s.Body,{children:["Version ",(0,t.jsx)(s.Mono,{children:h.version}),", running as ",M[h.kind]||h.kind,"."]}),(0,t.jsxs)(s.Body,{children:["Your network is kept in ",(0,t.jsx)(s.Mono,{children:h.dataDir}),h.customDataDir?" (a folder you chose).":".","mac-app"===h.kind&&" Help → Show the Data Folder opens it."]}),(0,t.jsx)(s.Body,{style:{fontSize:12,color:"#667",marginTop:10},children:"Settings are saved with your network, on this computer. Nothing here is sent anywhere."})]}):!l&&(0,t.jsx)(s.Body,{children:"Loading…"})})]})]})}e.s(["default",0,function(){return(0,t.jsx)(a.default,{children:(0,t.jsx)(R,{})})}],5445)}]);
package/CHANGELOG.md CHANGED
@@ -6,6 +6,78 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.4.9] - 2026-09-29
10
+
11
+ ### Added
12
+ - **Conversations, in the Social tab.** Every conversation with one of your connections, from your
13
+ export and the live messages sync: who it's with (name and tier), when it was last active, who
14
+ wrote last, unread, how many messages, and *Open on LinkedIn* (the thread when the sync found
15
+ its link, else their profile). Waiting on you comes first, then S and A tier, then the most
16
+ recent. Group conversations are shown and marked, and aren't counted in warmth. A search box
17
+ finds people by name.
18
+ - **Keep my messages on this computer**, a switch that's off unless you turn it on. When it's on,
19
+ the messages themselves, what other people wrote to you included, are kept in the app's data
20
+ folder (a file of their own beside the Social tab's), and a conversation opens as a thread,
21
+ newest at the bottom, a page at a time so a thread of thousands opens as fast as a short one.
22
+ The search box then finds what was said, too. They're never sent anywhere, and "Save a copy of
23
+ my network" doesn't carry them (Settings says so). Switching it off asks first, then deletes
24
+ them; *Forget it* deletes them with everything else.
25
+ - **The live messages sync reads a little more of the list.** Each conversation's link, whether
26
+ it's a group, and its newest message: who wrote last, which now feeds warmth and Waiting on you
27
+ where your export is missing or older, and its words, which go to the app only while Keep my
28
+ messages is on. It still opens no conversation, and its saved samples still keep no words.
29
+
30
+ ### Changed
31
+ - **Auto scan is slower and has its own ceilings.** Sittings of 8 pages, then an hour's rest;
32
+ searches only from 9:00 to 18:00; never more than 40 searches in 24 hours or 200 in 7 days,
33
+ however high the daily budget is set (the account restricted on 28 September did 373 in a
34
+ day with the budget at 500); and two days with no searches after any check from LinkedIn.
35
+ - **The scan status bar sits under the buttons.** On each page it now sits in its own row
36
+ under the header, pushing the page down instead of covering it. On Network Circle it floats
37
+ just under the header, measured, so a header that wraps to two rows no longer hides it.
38
+
39
+ ### Fixed
40
+ - **The live messages sync keeps what it finds.** It read your conversations but matched none of
41
+ them: the pattern for a profile link never matched, and LinkedIn's messaging gives a member
42
+ link your connections list doesn't have. It now matches each person to your connections by
43
+ link, or by a name only one connection has (the name isn't kept), and scrolls the list's own
44
+ panel so more than the first 20 conversations load.
45
+ - **Messaging samples keep no words.** The sync's saved samples of LinkedIn's data (for tuning
46
+ the reader) now drop every piece of writing and every name before they're saved.
47
+
48
+ ## [0.4.8] - 2026-09-29
49
+
50
+ ### Changed
51
+ - **A new icon.** A 6 drawn in one gold line around you, a glowing core, ending in a degree
52
+ ring, with your tier rings fading behind it. It's the app's icon, the favicon and the
53
+ website's.
54
+ - **The website is a proper site now, and the README matches.** The home page tells one story,
55
+ feature by feature, each with a real screenshot of the invented sample network: see your
56
+ network, find your way in, know your network, watch it grow, and scan carefully, then privacy,
57
+ a fair comparison with LinkedIn's own search, spreadsheets and CRMs, and SocNetV and Gephi,
58
+ and a strip of true, checkable numbers. It has one download button, for your computer: the Mac
59
+ download on a Mac, and on Linux and Windows a dimmed *Coming soon* button, never a link, with
60
+ `npx six-degrees` offered on Linux. New pages: **/download/** (every platform, install steps,
61
+ checksums, requirements, troubleshooting), **/docs/** (getting started, your data, privacy,
62
+ questions), **/releases/** (every version in this changelog), **/blog/** with four posts on how
63
+ it works, **/roadmap/** and **/about/**, with Atom feeds for the blog and releases and every
64
+ page in the sitemap. `scripts/build-site.mjs` builds it all from `site/`, and the website's
65
+ deploy runs it, so the news and numbers never go stale (`site/README.md` says how to add a
66
+ post or a page). The README has badges, a download table for all three platforms, features,
67
+ latest news and why Six Degrees.
68
+
69
+ ### Fixed
70
+ - **Paths opens about 9× faster on a large network** (Map 19.8 s → 2.2 s, Industries 25.8 s →
71
+ 1.7 s, at 1,500 connections and 25,000 people in their circles). Each headline and company
72
+ name is now read once, not once per pass: Paths read everyone's headline five or more times,
73
+ and each read tries the whole company list. The same fix makes Scores open in under a
74
+ second (was 11 s), and setting a company's score rescores everyone in a third of a second
75
+ (was 6 s). Scores themselves are unchanged.
76
+ - **Opening a company's path to the top in Paths no longer hangs.** Every row compared itself
77
+ with everyone at the company each time the page drew: at a company of 1,900 people that took
78
+ minutes. It now opens in a fifth of a second, and a row works out what adding them would do
79
+ only when you open it.
80
+
9
81
  ## [0.4.7] - 2026-09-29
10
82
 
11
83
  ### Added
package/README.md CHANGED
@@ -1,24 +1,68 @@
1
1
  <p align="center">
2
- <a href="https://sixdegreesapp.com/"><img src="desktop/icon/icon.svg" width="128" height="128" alt="Six Degrees website"></a>
2
+ <a href="https://sixdegreesapp.com/"><img src="desktop/icon/icon.svg" width="112" height="112" alt="Six Degrees website"></a>
3
3
  </p>
4
4
 
5
5
  <h1 align="center">Six Degrees</h1>
6
6
 
7
7
  <p align="center">
8
- <em>Map your LinkedIn network as a galaxy — see who bridges you to everyone else,<br />
9
- and find the shortest path to someone you haven't met.</em>
8
+ <strong>See your LinkedIn network as a galaxy.</strong><br>
9
+ Who can introduce you, who only one of your connections can reach, and the shortest path to<br>
10
+ someone you haven't met. Free, open source, and it runs on your own computer.
10
11
  </p>
11
12
 
12
- ## Install it
13
+ <p align="center">
14
+ <a href="https://github.com/blakeb056/six-degrees/releases/latest"><img src="https://img.shields.io/github/v/release/blakeb056/six-degrees?label=release&color=ffd700" alt="Latest release"></a>
15
+ <a href="https://github.com/blakeb056/six-degrees/releases/latest"><img src="https://img.shields.io/github/release-date/blakeb056/six-degrees?label=released&color=3ee08f" alt="Release date"></a>
16
+ <a href="LICENSE"><img src="https://img.shields.io/github/license/blakeb056/six-degrees?color=9b59b6" alt="MIT licence"></a>
17
+ <a href="https://www.npmjs.com/package/six-degrees"><img src="https://img.shields.io/npm/v/six-degrees?label=npm&color=3498db" alt="npm version"></a>
18
+ <a href="https://github.com/blakeb056/six-degrees/actions/workflows/ci.yml"><img src="https://github.com/blakeb056/six-degrees/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
19
+ </p>
13
20
 
14
- <p align="center"><strong>Click the button for your Mac to download the app.</strong></p>
21
+ <p align="center">
22
+ <a href="https://sixdegreesapp.com/"><strong>Website</strong></a> ·
23
+ <a href="#download">Download</a> ·
24
+ <a href="#features">Features</a> ·
25
+ <a href="#latest-news">News</a> ·
26
+ <a href="#why-six-degrees">Why Six Degrees</a> ·
27
+ <a href="#docs">Docs</a> ·
28
+ <a href="https://sixdegreesapp.com/blog/">Blog</a> ·
29
+ <a href="https://sixdegreesapp.com/roadmap/">Roadmap</a> ·
30
+ <a href="#contributing">Contributing</a>
31
+ </p>
32
+
33
+ <p align="center">
34
+ <a href="https://sixdegreesapp.com/"><img src="site/img/og-image.jpg" alt="Six Degrees on a Mac: a sample network drawn as rings around you, the most powerful people closest" width="100%"></a>
35
+ </p>
36
+
37
+ <p align="center"><sub>Every person shown in this README is invented — see <a href="scripts/gen-synthetic.mjs"><code>gen-synthetic.mjs</code></a>.</sub></p>
38
+
39
+ Your network has a shape, and you can't see it. Six Degrees draws it: everyone you
40
+ know placed on rings by how much they can open up for you, the handful of people
41
+ whose own circles reach the furthest, and the shortest chain from you to a stranger
42
+ worth meeting.
43
+
44
+ It's a Mac app (or `npx six-degrees` on Linux). It runs on your computer, against your own data, with no account and
45
+ no server.
46
+
47
+ ## Download
15
48
 
16
49
  <p align="center">
17
50
  <a href="https://github.com/blakeb056/six-degrees/releases/latest/download/Six-Degrees-Mac-Apple-Silicon.dmg"><img src="docs/img/download-apple-silicon.png" width="346" alt="Download Six Degrees for a Mac with Apple Silicon (M1 or newer)"></a>
18
51
  <a href="https://github.com/blakeb056/six-degrees/releases/latest/download/Six-Degrees-Mac-Intel.dmg"><img src="docs/img/download-intel.png" width="346" alt="Download Six Degrees for a Mac with an Intel chip"></a>
19
52
  </p>
20
53
 
21
- <p align="center"><sub>Free Mac app · macOS 13.5 or later · <a href="https://sixdegreesapp.com/">website</a> · <a href="https://github.com/blakeb056/six-degrees/releases/latest">what's new</a></sub></p>
54
+ | Platform | Download | Needs |
55
+ |---|---|---|
56
+ | **macOS**, Apple Silicon (M1 or newer) | [Six-Degrees-Mac-Apple-Silicon.dmg](https://github.com/blakeb056/six-degrees/releases/latest/download/Six-Degrees-Mac-Apple-Silicon.dmg) | macOS 13.5 (Ventura) or later |
57
+ | **macOS**, Intel | [Six-Degrees-Mac-Intel.dmg](https://github.com/blakeb056/six-degrees/releases/latest/download/Six-Degrees-Mac-Intel.dmg) | macOS 13.5 (Ventura) or later |
58
+ | **Linux** | App: *coming soon.* Run it today from the Terminal: `npx six-degrees` ([how](https://sixdegreesapp.com/download/#linux)) | Node 22.13 or later |
59
+ | **Windows** | *Coming soon.* [Watch releases](https://github.com/blakeb056/six-degrees) (Watch → Custom → Releases) to hear when it's out | — |
60
+
61
+ <sub>Every release is on [GitHub Releases](https://github.com/blakeb056/six-degrees/releases) with a
62
+ `SHA256SUMS` file ([latest](https://github.com/blakeb056/six-degrees/releases/latest/download/SHA256SUMS)); the Terminal install below checks the download against it.
63
+ The links above always fetch the newest release.</sub>
64
+
65
+ ## Install it
22
66
 
23
67
  **Which download?** Apple menu → **About This Mac**. If it says "Chip: Apple M…", take
24
68
  **Apple Silicon**. If it says "Processor: …Intel…", take **Intel**. It needs **macOS 13.5
@@ -109,21 +153,104 @@ Scanning LinkedIn also needs Google Chrome, and Python 3.10 to 3.14 or the Scan
109
153
  **Set up the scanner** (see below).
110
154
  </details>
111
155
 
112
- ## What it is
156
+ ## Features
113
157
 
114
- <p align="center">
115
- <img src="docs/img/app-window.png" alt="Six Degrees on a Mac: your network drawn as circles around you, the most powerful people closest" width="100%">
158
+ **Network Circle.** Everyone you know, on rings by tier, the most powerful closest to
159
+ you. Switch the drawing between **Galaxy**, **Pyramid** and **List** in the panel on
160
+ the left.
161
+
162
+ **Degrees** *(needs a scan or the sample)*. The people two steps away. **Separation**
163
+ ranks every one of them with every way in: which of your connections knows them, and
164
+ how many do. **Orbit**, **Bridge Chains**, **Pyramid** and **List** draw the same people
165
+ differently.
166
+
167
+ <img src="docs/img/degrees.png" alt="Degrees → Separation: people two steps away, ranked, each with the connection who can introduce you" width="100%">
168
+
169
+ **Paths.** Your network by company and industry, in the spirit of LinkedIn's old
170
+ InMaps:
171
+ - **Map**: your companies as bubbles (the 140 largest), grouped by industry and linked
172
+ where your connections at one know people at another.
173
+ - **Industries**: a card per industry.
174
+ - **Companies**: pick one to see its people level by level, up to the top.
175
+
176
+ Click a company for its analyzer: who you know there, who you can reach, the warmest way
177
+ in, and its most powerful people.
178
+
179
+ <img src="docs/img/paths.png" alt="Paths → Map with the company analyzer open: companies grouped by industry, and one company's people by level and ways in" width="100%">
180
+
181
+ **Scores.** How a power score is worked out, and the three things you can change about
182
+ it, in one place: your field (the sectors you work in), how tiers are graded (on your
183
+ network's curve or the fixed scale), and every scanned company's score.
184
+
185
+ **Outlink** *(needs a scan)*. Getting introduced, as a game. Each mapped connection's
186
+ circle offers its best five people at a time; mark invites as sent to fill the ring and
187
+ unlock the next five. It also shows the next best moves, levels and points (from
188
+ invites sent and people who accepted, never from browsing).
189
+
190
+ **Scan.** The guided scanner. It shows progress, the budget that's left, the cooldown
191
+ lock, and a **Paused** list you can carry on from.
192
+
193
+ **Also in the app:**
194
+ - **Who only one connection reaches.** For every connection whose circle you've scanned,
195
+ the people none of your other connections reach: in Bridge Chains, and in the
196
+ *Insights* on their card, with *Show them* to list exactly who.
197
+ - **Network health** (Scores). How much of your 2nd degree you reach two or more ways,
198
+ your effective reach, and the five connections who reach the most people no one else
199
+ does. Only your own numbers, never a percentile against other people.
200
+ - **A physics lab for the Galaxy** (experimental, in Filters). Sliders for gravity, rings,
201
+ push, pull and distance; colour by tier, degree, company or warmth; find anyone; and a
202
+ **replay** of your network growing by the date you connected, saved as a picture or a
203
+ video.
204
+ - **Social** (experimental). From your own LinkedIn data: who's warm, dormant or waiting
205
+ on a reply, and your career chapters. Message text is never kept.
206
+
207
+ ## Latest news
208
+
209
+ <p>
210
+ <a href="https://github.com/blakeb056/six-degrees/releases/latest"><img src="https://img.shields.io/github/v/release/blakeb056/six-degrees?label=latest&color=ffd700" alt="Latest release"></a>
211
+ <a href="https://github.com/blakeb056/six-degrees/releases/latest"><img src="https://img.shields.io/github/release-date/blakeb056/six-degrees?label=released&color=3ee08f" alt="Release date"></a>
116
212
  </p>
117
213
 
118
- <p align="center"><sub>Every person shown in this README is invented — see <a href="scripts/gen-synthetic.mjs"><code>gen-synthetic.mjs</code></a>.</sub></p>
214
+ Six Degrees ships often, and every release says what it added, changed and fixed:
119
215
 
120
- Your network has a shape, and you can't see it. Six Degrees draws it: everyone you
121
- know placed on rings by how much they can open up for you, the handful of people
122
- whose own circles reach the furthest, and the shortest chain from you to a stranger
123
- worth meeting.
216
+ - **[Releases](https://github.com/blakeb056/six-degrees/releases)**: each version's
217
+ downloads and notes ([Atom feed](https://github.com/blakeb056/six-degrees/releases.atom)).
218
+ - **[CHANGELOG.md](CHANGELOG.md)**: everything, newest first, including what's
219
+ coming in the next release.
220
+ - **[Release notes on the website](https://sixdegreesapp.com/releases/)**: every version,
221
+ built from the changelog each time the site is published, with a
222
+ [feed](https://sixdegreesapp.com/releases/feed.xml).
223
+ - **[The blog](https://sixdegreesapp.com/blog/)**: how it works, and why.
124
224
 
125
- It's a Mac app (or `npx six-degrees` on Linux). It runs on your computer, against your own data, with no account and
126
- no server.
225
+ ## Why Six Degrees
226
+
227
+ A connections list tells you who you know. Six Degrees shows what that network can do:
228
+
229
+ - **Who can introduce you, ranked.** Everyone two steps away, each with every way in.
230
+ - **Who only one connection reaches.** Where a single person is your only door.
231
+ - **Your network's health.** How much of it you reach more than one way.
232
+ - **A physics lab and a replay.** Tune the Galaxy's layout, and watch your network grow.
233
+ - **All on your own computer.** No account, no server, no telemetry.
234
+
235
+ In the sample network that ships with the app (150 invented connections), 598 people are
236
+ two steps away, and 503 of them, 84%, are reached through only one connection.
237
+
238
+ **How it compares**, as fairly as we can put it
239
+ ([the full table](https://sixdegreesapp.com/#compare)):
240
+
241
+ | | Six Degrees | LinkedIn's own search | Spreadsheets and CRMs | Network tools (SocNetV, Gephi) |
242
+ |---|---|---|---|---|
243
+ | Your connections, from LinkedIn's export | ✓ | ✓ | ✓ | as nodes, with no ties |
244
+ | Everyone two steps away, with who can introduce you | ✓ (needs a scan, or the sample) | 2nd-degree search, mutual connections on each | — (the export is 1st degree only) | if you bring the ties |
245
+ | Who only one connection reaches | ✓ | not shown | — | brokerage measures, on your data |
246
+ | A score per person, with the working shown | ✓ | not shown | your own formulas | general centrality |
247
+ | A layout you can tune, and a replay by date | ✓ (experimental) | — | — | ✓ many layouts; Gephi's timeline |
248
+ | Any network, any data, research-grade statistics | — (LinkedIn networks only) | — | any data | ✓ what they're built for |
249
+ | Runs on your computer, with no account | ✓ | — (online, with your account) | varies | ✓ |
250
+ | Price | free, MIT | free, with paid plans | free to paid | free, open source |
251
+ | Windows | coming soon | ✓ | ✓ | ✓ |
252
+
253
+ Something out of date, or unfair to another tool? [Open an issue](https://github.com/blakeb056/six-degrees/issues).
127
254
 
128
255
  ## Before you scan LinkedIn
129
256
 
@@ -179,43 +306,6 @@ While the sample or a CSV is loaded, the top bar shows *Sample network ×* or *Y
179
306
  ×* (click × to go back), and Outlink and Scan are hidden. Neither is ever added to your
180
307
  network: they last as long as the app's window is open.
181
308
 
182
- ## What it does
183
-
184
- **Network Circle.** Everyone you know, on rings by tier, the most powerful closest to
185
- you. Switch the drawing between **Galaxy**, **Orbit**, **Pyramid** and **List** in the
186
- panel on the left.
187
-
188
- **Degrees** *(needs a scan or the sample)*. The people two steps away. **Separation**
189
- ranks every one of them with every way in: which of your connections knows them, and
190
- how many do. **Orbit**, **Bridge Chains**, **Pyramid** and **List** draw the same people
191
- differently.
192
-
193
- <img src="docs/img/degrees.png" alt="Degrees → Separation: people two steps away, ranked, each with the connection who can introduce you" width="100%">
194
-
195
- **Paths.** Your network by company and industry, in the spirit of LinkedIn's old
196
- InMaps:
197
- - **Map**: your companies as bubbles (the 140 largest), grouped by industry and linked
198
- where your connections at one know people at another.
199
- - **Industries**: a card per industry.
200
- - **Companies**: pick one to see its people level by level, up to the top.
201
-
202
- Click a company for its analyzer: who you know there, who you can reach, the warmest way
203
- in, and its most powerful people.
204
-
205
- <img src="docs/img/paths.png" alt="Paths → Map with the company analyzer open: companies grouped by industry, and one company's people by level and ways in" width="100%">
206
-
207
- **Scores.** How a power score is worked out, and the three things you can change about
208
- it, in one place: your field (the sectors you work in), how tiers are graded (on your
209
- network's curve or the fixed scale), and every scanned company's score.
210
-
211
- **Outlink** *(needs a scan)*. Getting introduced, as a game. Each mapped connection's
212
- circle offers its best five people at a time; mark invites as sent to fill the ring and
213
- unlock the next five. It also shows the next best moves, levels and points (from
214
- invites sent and people who accepted, never from browsing).
215
-
216
- **Scan.** The guided scanner. It shows progress, the budget that's left, the cooldown
217
- lock, and a **Paused** list you can carry on from.
218
-
219
309
  ## How scoring works
220
310
 
221
311
  ```
@@ -403,11 +493,33 @@ Nothing to configure. Two optional environment variables exist:
403
493
  | `SIX_DEGREES_HOME` | Where your data lives. Defaults to `~/.six-degrees`. It's read at launch, so it applies to `npx six-degrees` and source runs (npx also takes `--data-dir`; see `npx six-degrees --help`), not when the Mac app is opened from the Dock or Finder. A relative folder is taken from the folder you run the command in. |
404
494
  | `ADMIN_TOKEN` | Not needed on your own computer. The app listens only on 127.0.0.1 and isn't built to be exposed: don't put it behind a tunnel or bind it to another address ([SECURITY.md](SECURITY.md)). If it's ever bound elsewhere, the ten routes that delete, replace or hand over your data, run the scanner, open the data folder or update a copy run from source refuse every caller without this token, including the app's own buttons. Everything else, including reading your whole network, stays open. |
405
495
 
496
+ ## Docs
497
+
498
+ | You want | Read |
499
+ |---|---|
500
+ | To install it, step by step | [Install it](#install-it), or [the website's guide](https://sixdegreesapp.com/download/#install) with videos |
501
+ | How scanning works, and what it risks | [docs/SCRAPING.md](docs/SCRAPING.md) |
502
+ | How a power score is worked out | [How scoring works](#how-scoring-works), and [docs/brain/SCORING.md](docs/brain/SCORING.md) |
503
+ | Where your data lives, moving computers | [How your data is stored](#how-your-data-is-stored) |
504
+ | The security model, and reporting a problem | [SECURITY.md](SECURITY.md) |
505
+ | What changed in each version | [CHANGELOG.md](CHANGELOG.md), or the [release notes](https://sixdegreesapp.com/releases/) on the website |
506
+ | How it works, and why | [The blog](https://sixdegreesapp.com/blog/): who can introduce you, local-first, the physics lab, scanning slowly |
507
+ | What's next | [The roadmap](https://sixdegreesapp.com/roadmap/) |
508
+ | The website itself | [site/README.md](site/README.md): previewing it, adding a post or a page |
509
+ | To change the code | [CONTRIBUTING.md](CONTRIBUTING.md), then [docs/brain/](docs/brain/00-START-HERE.md) |
510
+
406
511
  ## Contributing
407
512
 
408
- See [CONTRIBUTING.md](CONTRIBUTING.md). The rule that matters most: **never commit real
409
- network data**. That means no exported CSVs, no avatars, and no screenshots of real
410
- people.
513
+ Bug reports, ideas and pull requests are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md)
514
+ to run it from source, and the [code of conduct](CODE_OF_CONDUCT.md). Report a security
515
+ problem privately, through
516
+ [GitHub's security advisories](https://github.com/blakeb056/six-degrees/security/advisories/new)
517
+ ([SECURITY.md](SECURITY.md)), not in an issue.
518
+
519
+ The rule that matters most: **never commit real network data**. That means no exported
520
+ CSVs, no avatars, and no screenshots of real people. When you file an
521
+ [issue](https://github.com/blakeb056/six-degrees/issues), redact names before attaching
522
+ anything.
411
523
 
412
524
  ## License
413
525
 
package/lib/galaxy-lab.js CHANGED
@@ -215,7 +215,12 @@ export function mergeSocial(social) {
215
215
  for (const [url, v] of Object.entries(social?.live || {})) {
216
216
  const k = keyFor({ profile_url: url });
217
217
  const cur = merged.get(k) || { total: 0, recent: 0 };
218
- if (v.last && (!cur.last || v.last > cur.last)) cur.last = v.last;
218
+ // The live sync's word on who wrote last counts when it's the newer news:
219
+ // no export yet, or the conversation moved on since the export was made.
220
+ if (v.last && (!cur.last || v.last > cur.last)) {
221
+ cur.last = v.last;
222
+ if (typeof v.lastFromThem === 'boolean') cur.lastFromThem = v.lastFromThem;
223
+ }
219
224
  cur.unread = v.unread;
220
225
  cur.total = Math.max(cur.total || 0, 1);
221
226
  merged.set(k, cur);