six-degrees 0.2.0 → 0.3.0-beta.1

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 (478) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +10 -0
  3. package/.next/standalone/.next/build-manifest.json +3 -3
  4. package/.next/standalone/.next/prerender-manifest.json +39 -11
  5. package/.next/standalone/.next/required-server-files.json +4 -1
  6. package/.next/standalone/.next/routes-manifest.json +60 -0
  7. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  17. package/.next/standalone/.next/server/app/_not-found.rsc +11 -11
  18. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +11 -11
  19. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +9 -9
  20. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  21. package/.next/standalone/.next/server/app/api/admin-delete/route.js +3 -2
  22. package/.next/standalone/.next/server/app/api/admin-delete/route.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/api/admin-update/route.js +3 -2
  24. package/.next/standalone/.next/server/app/api/admin-update/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/bridges/route.js +3 -2
  26. package/.next/standalone/.next/server/app/api/bridges/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/bulk-import/route.js +3 -2
  28. package/.next/standalone/.next/server/app/api/bulk-import/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/company-scores/legacy/route/app-paths-manifest.json +3 -0
  30. package/.next/standalone/.next/server/app/api/company-scores/legacy/route/build-manifest.json +12 -0
  31. package/.next/standalone/.next/server/app/api/company-scores/legacy/route/server-reference-manifest.json +4 -0
  32. package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js +9 -0
  33. package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.map +5 -0
  34. package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.nft.json +1 -0
  35. package/.next/standalone/.next/server/app/api/company-scores/legacy/route_client-reference-manifest.js +3 -0
  36. package/.next/standalone/.next/server/app/api/company-scores/route.js +3 -2
  37. package/.next/standalone/.next/server/app/api/company-scores/route.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/api/connections/route.js +3 -2
  39. package/.next/standalone/.next/server/app/api/connections/route.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/api/data/export/route/app-paths-manifest.json +3 -0
  41. package/.next/standalone/.next/server/app/api/data/export/route/build-manifest.json +12 -0
  42. package/.next/standalone/.next/server/app/api/data/export/route/server-reference-manifest.json +4 -0
  43. package/.next/standalone/.next/server/app/api/data/export/route.js +7 -0
  44. package/.next/standalone/.next/server/app/api/data/export/route.js.map +5 -0
  45. package/.next/standalone/.next/server/app/api/data/export/route.js.nft.json +1 -0
  46. package/.next/standalone/.next/server/app/api/data/export/route_client-reference-manifest.js +3 -0
  47. package/.next/standalone/.next/server/app/api/data/import/route/app-paths-manifest.json +3 -0
  48. package/.next/standalone/.next/server/app/api/data/import/route/build-manifest.json +12 -0
  49. package/.next/standalone/.next/server/app/api/data/import/route/server-reference-manifest.json +4 -0
  50. package/.next/standalone/.next/server/app/api/data/import/route.js +8 -0
  51. package/.next/standalone/.next/server/app/api/data/import/route.js.map +5 -0
  52. package/.next/standalone/.next/server/app/api/data/import/route.js.nft.json +1 -0
  53. package/.next/standalone/.next/server/app/api/data/import/route_client-reference-manifest.js +3 -0
  54. package/.next/standalone/.next/server/app/api/data/restart/route/app-paths-manifest.json +3 -0
  55. package/.next/standalone/.next/server/app/api/data/restart/route/build-manifest.json +12 -0
  56. package/.next/standalone/.next/server/app/api/data/restart/route/server-reference-manifest.json +4 -0
  57. package/.next/standalone/.next/server/app/api/data/restart/route.js +8 -0
  58. package/.next/standalone/.next/server/app/api/data/restart/route.js.map +5 -0
  59. package/.next/standalone/.next/server/app/api/data/restart/route.js.nft.json +1 -0
  60. package/.next/standalone/.next/server/app/api/data/restart/route_client-reference-manifest.js +3 -0
  61. package/.next/standalone/.next/server/app/api/data/reveal/route/app-paths-manifest.json +3 -0
  62. package/.next/standalone/.next/server/app/api/data/reveal/route/build-manifest.json +12 -0
  63. package/.next/standalone/.next/server/app/api/data/reveal/route/server-reference-manifest.json +4 -0
  64. package/.next/standalone/.next/server/app/api/data/reveal/route.js +7 -0
  65. package/.next/standalone/.next/server/app/api/data/reveal/route.js.map +5 -0
  66. package/.next/standalone/.next/server/app/api/data/reveal/route.js.nft.json +1 -0
  67. package/.next/standalone/.next/server/app/api/data/reveal/route_client-reference-manifest.js +3 -0
  68. package/.next/standalone/.next/server/app/api/data/route/app-paths-manifest.json +3 -0
  69. package/.next/standalone/.next/server/app/api/data/route/build-manifest.json +12 -0
  70. package/.next/standalone/.next/server/app/api/data/route/server-reference-manifest.json +4 -0
  71. package/.next/standalone/.next/server/app/api/data/route.js +7 -0
  72. package/.next/standalone/.next/server/app/api/data/route.js.map +5 -0
  73. package/.next/standalone/.next/server/app/api/data/route.js.nft.json +1 -0
  74. package/.next/standalone/.next/server/app/api/data/route_client-reference-manifest.js +3 -0
  75. package/.next/standalone/.next/server/app/api/delete-cluster/route.js +3 -2
  76. package/.next/standalone/.next/server/app/api/delete-cluster/route.js.nft.json +1 -1
  77. package/.next/standalone/.next/server/app/api/ingest/route.js +2 -2
  78. package/.next/standalone/.next/server/app/api/ingest/route.js.nft.json +1 -1
  79. package/.next/standalone/.next/server/app/api/network/route.js +3 -2
  80. package/.next/standalone/.next/server/app/api/network/route.js.nft.json +1 -1
  81. package/.next/standalone/.next/server/app/api/notifications/route.js +3 -2
  82. package/.next/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  83. package/.next/standalone/.next/server/app/api/outreach/route.js +3 -2
  84. package/.next/standalone/.next/server/app/api/outreach/route.js.nft.json +1 -1
  85. package/.next/standalone/.next/server/app/api/queue/route.js +3 -2
  86. package/.next/standalone/.next/server/app/api/queue/route.js.nft.json +1 -1
  87. package/.next/standalone/.next/server/app/api/scraper/route.js +3 -2
  88. package/.next/standalone/.next/server/app/api/scraper/route.js.nft.json +1 -1
  89. package/.next/standalone/.next/server/app/api/settings/route/app-paths-manifest.json +3 -0
  90. package/.next/standalone/.next/server/app/api/settings/route/build-manifest.json +12 -0
  91. package/.next/standalone/.next/server/app/api/settings/route/server-reference-manifest.json +4 -0
  92. package/.next/standalone/.next/server/app/api/settings/route.js +9 -0
  93. package/.next/standalone/.next/server/app/api/settings/route.js.map +5 -0
  94. package/.next/standalone/.next/server/app/api/settings/route.js.nft.json +1 -0
  95. package/.next/standalone/.next/server/app/api/settings/route_client-reference-manifest.js +3 -0
  96. package/.next/standalone/.next/server/app/api/settings/sector-preview/route/app-paths-manifest.json +3 -0
  97. package/.next/standalone/.next/server/app/api/settings/sector-preview/route/build-manifest.json +12 -0
  98. package/.next/standalone/.next/server/app/api/settings/sector-preview/route/server-reference-manifest.json +4 -0
  99. package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js +8 -0
  100. package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.map +5 -0
  101. package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.nft.json +1 -0
  102. package/.next/standalone/.next/server/app/api/settings/sector-preview/route_client-reference-manifest.js +3 -0
  103. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route/app-paths-manifest.json +3 -0
  104. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route/build-manifest.json +12 -0
  105. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route/server-reference-manifest.json +4 -0
  106. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js +8 -0
  107. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.map +5 -0
  108. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.nft.json +1 -0
  109. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route_client-reference-manifest.js +3 -0
  110. package/.next/standalone/.next/server/app/api/setup-profile/route.js +3 -2
  111. package/.next/standalone/.next/server/app/api/setup-profile/route.js.nft.json +1 -1
  112. package/.next/standalone/.next/server/app/api/unlock/route.js +3 -2
  113. package/.next/standalone/.next/server/app/api/unlock/route.js.nft.json +1 -1
  114. package/.next/standalone/.next/server/app/api/update/route.js +1 -1
  115. package/.next/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  116. package/.next/standalone/.next/server/app/api/update-images/route.js +3 -2
  117. package/.next/standalone/.next/server/app/api/update-images/route.js.nft.json +1 -1
  118. package/.next/standalone/.next/server/app/api/users/route.js +3 -2
  119. package/.next/standalone/.next/server/app/api/users/route.js.nft.json +1 -1
  120. package/.next/standalone/.next/server/app/avatars/[file]/route.js +2 -1
  121. package/.next/standalone/.next/server/app/avatars/[file]/route.js.nft.json +1 -1
  122. package/.next/standalone/.next/server/app/favicon.ico/route.js +2 -1
  123. package/.next/standalone/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  124. package/.next/standalone/.next/server/app/import/page.js.nft.json +1 -1
  125. package/.next/standalone/.next/server/app/import/page_client-reference-manifest.js +1 -1
  126. package/.next/standalone/.next/server/app/import.html +1 -1
  127. package/.next/standalone/.next/server/app/import.rsc +13 -13
  128. package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +13 -13
  129. package/.next/standalone/.next/server/app/import.segments/_tree.segment.rsc +1 -1
  130. package/.next/standalone/.next/server/app/import.segments/import/__PAGE__.segment.rsc +11 -11
  131. package/.next/standalone/.next/server/app/index.html +1 -1
  132. package/.next/standalone/.next/server/app/index.rsc +13 -13
  133. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +11 -11
  134. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +13 -13
  135. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  136. package/.next/standalone/.next/server/app/launch/page.js.nft.json +1 -1
  137. package/.next/standalone/.next/server/app/launch/page_client-reference-manifest.js +1 -1
  138. package/.next/standalone/.next/server/app/launch.html +2 -2
  139. package/.next/standalone/.next/server/app/launch.rsc +13 -13
  140. package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +13 -13
  141. package/.next/standalone/.next/server/app/launch.segments/_tree.segment.rsc +1 -1
  142. package/.next/standalone/.next/server/app/launch.segments/launch/__PAGE__.segment.rsc +11 -11
  143. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  144. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  145. package/.next/standalone/.next/server/app/paths/page.js.nft.json +1 -1
  146. package/.next/standalone/.next/server/app/paths/page_client-reference-manifest.js +1 -1
  147. package/.next/standalone/.next/server/app/paths.html +1 -1
  148. package/.next/standalone/.next/server/app/paths.rsc +13 -13
  149. package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +13 -13
  150. package/.next/standalone/.next/server/app/paths.segments/_tree.segment.rsc +1 -1
  151. package/.next/standalone/.next/server/app/paths.segments/paths/__PAGE__.segment.rsc +11 -11
  152. package/.next/standalone/.next/server/app/profile/page.js.nft.json +1 -1
  153. package/.next/standalone/.next/server/app/profile/page_client-reference-manifest.js +1 -1
  154. package/.next/standalone/.next/server/app/profile.html +1 -1
  155. package/.next/standalone/.next/server/app/profile.rsc +13 -13
  156. package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +13 -13
  157. package/.next/standalone/.next/server/app/profile.segments/_tree.segment.rsc +1 -1
  158. package/.next/standalone/.next/server/app/profile.segments/profile/__PAGE__.segment.rsc +11 -11
  159. package/.next/standalone/.next/server/app/queue/page.js.nft.json +1 -1
  160. package/.next/standalone/.next/server/app/queue/page_client-reference-manifest.js +1 -1
  161. package/.next/standalone/.next/server/app/queue.html +1 -1
  162. package/.next/standalone/.next/server/app/queue.rsc +13 -13
  163. package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +13 -13
  164. package/.next/standalone/.next/server/app/queue.segments/_tree.segment.rsc +1 -1
  165. package/.next/standalone/.next/server/app/queue.segments/queue/__PAGE__.segment.rsc +11 -11
  166. package/.next/standalone/.next/server/app/settings/page/app-paths-manifest.json +3 -0
  167. package/.next/standalone/.next/server/app/settings/page/build-manifest.json +20 -0
  168. package/.next/standalone/.next/server/app/settings/page/next-font-manifest.json +11 -0
  169. package/.next/standalone/.next/server/app/settings/page/react-loadable-manifest.json +1 -0
  170. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -0
  171. package/.next/standalone/.next/server/app/settings/page.js +13 -0
  172. package/.next/standalone/.next/server/app/settings/page.js.map +5 -0
  173. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -0
  174. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +3 -0
  175. package/.next/standalone/.next/server/app/settings.html +1 -0
  176. package/.next/standalone/.next/server/app/settings.meta +26 -0
  177. package/.next/standalone/.next/server/app/settings.rsc +24 -0
  178. package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +24 -0
  179. package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +4 -0
  180. package/.next/standalone/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +28 -0
  181. package/.next/standalone/.next/server/app/setup/page.js.nft.json +1 -1
  182. package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  183. package/.next/standalone/.next/server/app/setup.html +1 -1
  184. package/.next/standalone/.next/server/app/setup.rsc +13 -13
  185. package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +13 -13
  186. package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +1 -1
  187. package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +11 -11
  188. package/.next/standalone/.next/server/app-paths-manifest.json +10 -0
  189. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-rnla2._.js +3 -0
  190. package/.next/standalone/.next/server/chunks/[root-of-the-server]__00la_y0._.js +3 -0
  191. package/.next/standalone/.next/server/chunks/[root-of-the-server]__07t47cm._.js +3 -0
  192. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cj5jqc._.js +3 -0
  193. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e0fei3._.js +3 -0
  194. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0i5hdu4._.js +3 -0
  195. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ljcioj._.js +3 -0
  196. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ljnyho._.js +3 -0
  197. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o5-tcg._.js +3 -0
  198. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qrnous._.js +3 -0
  199. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t3v1a1._.js +3 -0
  200. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0uag-k5._.js +8 -0
  201. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0um1uey._.js +3 -0
  202. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wmexuc._.js +3 -0
  203. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0xu34sz._.js +3 -0
  204. package/.next/standalone/.next/server/chunks/[root-of-the-server]__133knx1._.js +3 -0
  205. package/.next/standalone/.next/server/chunks/[root-of-the-server]__14ou7j5._.js +3 -0
  206. package/.next/standalone/.next/server/chunks/[root-of-the-server]__15-17hl._.js +3 -0
  207. package/.next/standalone/.next/server/chunks/[root-of-the-server]__16iu0hv._.js +3 -0
  208. package/.next/standalone/.next/server/chunks/[root-of-the-server]__19b7mig._.js +3 -0
  209. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1bbcwub._.js +8 -0
  210. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1eris29._.js +3 -0
  211. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1gjo_cq._.js +3 -0
  212. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1kbl21f._.js +3 -0
  213. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qcm08_._.js +3 -0
  214. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rphsdk._.js +3 -0
  215. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1t3rugi._.js +3 -0
  216. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1w25q0m._.js +3 -0
  217. package/.next/standalone/.next/server/chunks/_072jl0y._.js +3 -0
  218. package/.next/standalone/.next/server/chunks/_0lw8_i0._.js +3 -0
  219. package/.next/standalone/.next/server/chunks/_1_fynia._.js +21 -3
  220. package/.next/standalone/.next/server/chunks/_1fn30_l._.js +3 -0
  221. package/.next/standalone/.next/server/chunks/_1itd1o_._.js +2 -1
  222. package/.next/standalone/.next/server/chunks/_1iwkh8t._.js +1 -1
  223. package/.next/standalone/.next/server/chunks/_1mxn_lb._.js +3 -0
  224. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_company-scores_legacy_route_actions_1ncspu_.js +3 -0
  225. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_export_route_actions_1lkimty.js +3 -0
  226. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_import_route_actions_1eji0kd.js +3 -0
  227. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_restart_route_actions_00_-u6o.js +3 -0
  228. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_reveal_route_actions_0-moqtn.js +3 -0
  229. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_data_route_actions_0j0w5ep.js +3 -0
  230. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_settings_route_actions_1bpm9ac.js +3 -0
  231. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_settings_sector-preview_route_actions_0w79454.js +3 -0
  232. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_settings_sector-suggestions_route_actions_1eoqugp.js +3 -0
  233. package/.next/standalone/.next/server/chunks/lib_db-client_15le7cw.js +155 -0
  234. package/.next/standalone/.next/server/chunks/{lib_rpc_0mc73lk.js → lib_rpc_00tx2sm.js} +1 -1
  235. package/.next/standalone/.next/server/chunks/lib_rpc_02-qa4d.js +3 -0
  236. package/.next/standalone/.next/server/chunks/lib_rpc_02ndsg2.js +3 -0
  237. package/.next/standalone/.next/server/chunks/lib_rpc_08q5vp6.js +3 -0
  238. package/.next/standalone/.next/server/chunks/lib_rpc_0_8i3ft.js +3 -0
  239. package/.next/standalone/.next/server/chunks/lib_rpc_0c9d9ti.js +5 -2
  240. package/.next/standalone/.next/server/chunks/lib_rpc_0huvw-3.js +3 -0
  241. package/.next/standalone/.next/server/chunks/lib_rpc_0ip2vdh.js +3 -0
  242. package/.next/standalone/.next/server/chunks/lib_rpc_0jzisgh.js +3 -0
  243. package/.next/standalone/.next/server/chunks/lib_rpc_0yi9xvd.js +3 -0
  244. package/.next/standalone/.next/server/chunks/lib_rpc_1jyhd0o.js +3 -0
  245. package/.next/standalone/.next/server/chunks/lib_rpc_1kn59-i.js +3 -0
  246. package/.next/standalone/.next/server/chunks/lib_rpc_1q2jkza.js +3 -0
  247. package/.next/standalone/.next/server/chunks/lib_rpc_1vpm1sk.js +3 -0
  248. package/.next/standalone/.next/server/chunks/lib_rpc_1x6p_31.js +3 -0
  249. package/.next/standalone/.next/server/chunks/node_modules_next_1zc5q0a._.js +158 -0
  250. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0mocm6d._.js → [root-of-the-server]__0an6blh._.js} +3 -3
  251. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h1_f_2._.js +1 -1
  252. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1m0255u._.js +3 -0
  253. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0bipr5s._.js → [root-of-the-server]__1z1j3ek._.js} +2 -2
  254. package/.next/standalone/.next/server/chunks/ssr/_07u8byv._.js +3 -0
  255. package/.next/standalone/.next/server/chunks/ssr/_08r_mlf._.js +3 -0
  256. package/.next/standalone/.next/server/chunks/ssr/{_0ggabjc._.js → _0942v8n._.js} +1 -1
  257. package/.next/standalone/.next/server/chunks/ssr/{_1djpk8t._.js → _0hl_t7r._.js} +2 -2
  258. package/.next/standalone/.next/server/chunks/ssr/_0tb83dw._.js +132 -0
  259. package/.next/standalone/.next/server/chunks/ssr/_1-87bs1._.js +3 -0
  260. package/.next/standalone/.next/server/chunks/ssr/_17gui6a._.js +1 -1
  261. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_settings_page_actions_11x4dq5.js +3 -0
  262. package/.next/standalone/.next/server/chunks/ssr/app_import_page_1fmu6_l.js +1 -1
  263. package/.next/standalone/.next/server/chunks/ssr/app_launch_page_19t0dyd.js +2 -2
  264. package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +4 -4
  265. package/.next/standalone/.next/server/chunks/ssr/app_profile_page_0u3-l5y.js +1 -1
  266. package/.next/standalone/.next/server/chunks/ssr/app_queue_page_0c6znd6.js +5 -5
  267. package/.next/standalone/.next/server/chunks/ssr/app_settings_page_1f8mjj_.js +3 -0
  268. package/.next/standalone/.next/server/chunks/ssr/app_setup_page_1-282zx.js +2 -2
  269. package/.next/standalone/.next/server/chunks/ssr/lib_0i8v-s3._.js +1 -1
  270. package/.next/standalone/.next/server/chunks/ssr/node_modules_1f8t_rp._.js +23 -0
  271. package/.next/standalone/.next/server/chunks/ssr/node_modules_1nkgb45._.js +2 -2
  272. package/.next/standalone/.next/server/chunks/ssr/{node_modules_01xbj_9._.js → node_modules_1wax83z._.js} +3 -3
  273. package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_00nap8h._.js → node_modules_next_dist_1bunoni._.js} +2 -2
  274. package/.next/standalone/.next/server/edge/chunks/[root-of-the-server]__0pco7a6._.js +2 -2
  275. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  276. package/.next/standalone/.next/server/middleware-manifest.json +15 -7
  277. package/.next/standalone/.next/server/next-font-manifest.js +1 -1
  278. package/.next/standalone/.next/server/next-font-manifest.json +4 -0
  279. package/.next/standalone/.next/server/pages/404.html +1 -1
  280. package/.next/standalone/.next/server/pages/500.html +1 -1
  281. package/.next/standalone/.next/server/prefetch-hints.json +14 -0
  282. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  283. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  284. package/.next/standalone/.next/static/chunks/06x3jiiz96m5t.js +1 -0
  285. package/.next/{static/chunks/34at5d2ifl62i.js → standalone/.next/static/chunks/0ngx9s6-zgshe.js} +5 -5
  286. package/.next/standalone/.next/static/chunks/0q-_khndfxubv.js +2 -0
  287. package/.next/standalone/.next/static/chunks/1c79veqedvubt.js +1 -0
  288. package/.next/standalone/.next/static/chunks/1chp3nx45meg5.js +44 -0
  289. package/.next/standalone/.next/static/chunks/1irqj0lf-fu3d.js +1 -0
  290. package/.next/standalone/.next/static/chunks/1uadqylrod5_v.js +1 -0
  291. package/.next/standalone/.next/static/chunks/23u0zclgwpc4d.js +1 -0
  292. package/.next/standalone/.next/static/chunks/289ktj97di6zg.js +1 -0
  293. package/.next/standalone/.next/static/chunks/2b3lmf8e6uj8m.js +16 -0
  294. package/.next/standalone/.next/static/chunks/2jz311xl1pp_8.js +1 -0
  295. package/.next/standalone/.next/static/chunks/2ot61qsv6_0eq.js +1 -0
  296. package/.next/standalone/.next/static/chunks/3npq5yd7c4dmn.js +2 -0
  297. package/.next/standalone/.next/static/frfHFnRYTA0Wjrw8oZJtY/_clientMiddlewareManifest.js +14 -0
  298. package/.next/standalone/AGENTS.md +10 -0
  299. package/.next/standalone/CHANGELOG.md +325 -0
  300. package/.next/standalone/CONTRIBUTING.md +14 -2
  301. package/.next/standalone/README.md +181 -53
  302. package/.next/standalone/SECURITY.md +120 -10
  303. package/.next/standalone/app/api/company-scores/legacy/route.js +32 -0
  304. package/.next/standalone/app/api/company-scores/route.js +20 -11
  305. package/.next/standalone/app/api/data/export/route.js +49 -0
  306. package/.next/standalone/app/api/data/import/route.js +83 -0
  307. package/.next/standalone/app/api/data/restart/route.js +37 -0
  308. package/.next/standalone/app/api/data/reveal/route.js +14 -0
  309. package/.next/standalone/app/api/data/route.js +39 -0
  310. package/.next/standalone/app/api/ingest/route.js +15 -47
  311. package/.next/standalone/app/api/scraper/route.js +268 -128
  312. package/.next/standalone/app/api/settings/route.js +58 -0
  313. package/.next/standalone/app/api/settings/sector-preview/route.js +38 -0
  314. package/.next/standalone/app/api/settings/sector-suggestions/route.js +20 -0
  315. package/.next/standalone/app/api/update/route.js +197 -24
  316. package/.next/standalone/app/avatars/[file]/route.js +4 -2
  317. package/.next/standalone/app/components/CompanyScores.js +28 -7
  318. package/.next/standalone/app/components/EmptyState.js +8 -0
  319. package/.next/standalone/app/components/ForceGraph.js +40 -36
  320. package/.next/standalone/app/components/LegacyScoresCard.js +129 -0
  321. package/.next/standalone/app/components/Sidebar.js +19 -18
  322. package/.next/standalone/app/components/UpdatePanel.js +317 -99
  323. package/.next/standalone/app/components/UserProvider.js +4 -3
  324. package/.next/standalone/app/components/settings/DataSection.js +437 -0
  325. package/.next/standalone/app/components/settings/SectorSection.js +445 -0
  326. package/.next/standalone/app/components/ui.js +62 -0
  327. package/.next/standalone/app/import/page.js +3 -3
  328. package/.next/standalone/app/launch/page.js +30 -20
  329. package/.next/standalone/app/layout.js +2 -2
  330. package/.next/standalone/app/page.js +15 -2
  331. package/.next/standalone/app/paths/page.js +13 -5
  332. package/.next/standalone/app/profile/page.js +41 -186
  333. package/.next/standalone/app/queue/page.js +8 -2
  334. package/.next/standalone/app/settings/page.js +96 -0
  335. package/.next/standalone/app/setup/page.js +35 -19
  336. package/.next/standalone/bin/args.mjs +44 -0
  337. package/.next/standalone/bin/six-degrees.mjs +16 -17
  338. package/.next/standalone/install.sh +1 -1
  339. package/.next/standalone/lib/companies.js +44 -119
  340. package/.next/standalone/lib/csv.js +61 -27
  341. package/.next/standalone/lib/data-export.js +170 -0
  342. package/.next/standalone/lib/data-folder.js +238 -0
  343. package/.next/standalone/lib/data-import.js +878 -0
  344. package/.next/standalone/lib/db-client.js +48 -3
  345. package/.next/standalone/lib/durable.js +73 -0
  346. package/.next/standalone/lib/gate.js +90 -1
  347. package/.next/standalone/lib/ingest.js +40 -0
  348. package/.next/standalone/lib/legacy-offer.js +185 -0
  349. package/.next/standalone/lib/legacy-scores.js +77 -0
  350. package/.next/standalone/lib/linkedin-limits.js +124 -1
  351. package/.next/standalone/lib/release.js +5 -2
  352. package/.next/standalone/lib/rpc.js +121 -13
  353. package/.next/standalone/lib/sample-stats.js +16 -0
  354. package/.next/standalone/lib/scan-progress.js +13 -0
  355. package/.next/standalone/lib/scan-state.js +53 -0
  356. package/.next/standalone/lib/scanner-python.js +685 -0
  357. package/.next/standalone/lib/scanner-setup.js +104 -0
  358. package/.next/standalone/lib/scoring.js +747 -138
  359. package/.next/standalone/lib/scraper-client.js +10 -6
  360. package/.next/standalone/lib/sector-directory.js +1532 -0
  361. package/.next/standalone/lib/sector-focus.js +163 -0
  362. package/.next/standalone/lib/sector-labels.js +81 -0
  363. package/.next/standalone/lib/settings-effects.js +59 -0
  364. package/.next/standalone/lib/settings.js +83 -0
  365. package/.next/standalone/lib/updater-job.js +838 -0
  366. package/.next/standalone/lib/updater.js +494 -0
  367. package/.next/standalone/middleware.js +25 -28
  368. package/.next/standalone/next.config.mjs +19 -3
  369. package/.next/standalone/package-lock.json +103 -9
  370. package/.next/standalone/package.json +12 -11
  371. package/.next/standalone/public/demo-data.json +1 -1
  372. package/.next/standalone/scripts/apply-update.sh +482 -0
  373. package/.next/standalone/scripts/build-app.mjs +251 -9
  374. package/.next/standalone/scripts/gen-synthetic.mjs +16 -1
  375. package/.next/standalone/scripts/readme_buttons.py +89 -0
  376. package/.next/standalone/scripts/requirements.txt +106 -4
  377. package/.next/standalone/scripts/screenshots.py +2 -0
  378. package/.next/standalone/scripts/test-release-server.mjs +143 -0
  379. package/.next/standalone/server.js +1 -1
  380. package/.next/static/chunks/06x3jiiz96m5t.js +1 -0
  381. package/.next/{standalone/.next/static/chunks/34at5d2ifl62i.js → static/chunks/0ngx9s6-zgshe.js} +5 -5
  382. package/.next/static/chunks/0q-_khndfxubv.js +2 -0
  383. package/.next/static/chunks/1c79veqedvubt.js +1 -0
  384. package/.next/static/chunks/1chp3nx45meg5.js +44 -0
  385. package/.next/static/chunks/1irqj0lf-fu3d.js +1 -0
  386. package/.next/static/chunks/1uadqylrod5_v.js +1 -0
  387. package/.next/static/chunks/23u0zclgwpc4d.js +1 -0
  388. package/.next/static/chunks/289ktj97di6zg.js +1 -0
  389. package/.next/static/chunks/2b3lmf8e6uj8m.js +16 -0
  390. package/.next/static/chunks/2jz311xl1pp_8.js +1 -0
  391. package/.next/static/chunks/2ot61qsv6_0eq.js +1 -0
  392. package/.next/static/chunks/3npq5yd7c4dmn.js +2 -0
  393. package/.next/static/frfHFnRYTA0Wjrw8oZJtY/_clientMiddlewareManifest.js +14 -0
  394. package/CHANGELOG.md +325 -0
  395. package/README.md +181 -53
  396. package/SECURITY.md +120 -10
  397. package/bin/args.mjs +44 -0
  398. package/bin/six-degrees.mjs +16 -17
  399. package/lib/companies.js +44 -119
  400. package/lib/csv.js +61 -27
  401. package/lib/data-export.js +170 -0
  402. package/lib/data-folder.js +238 -0
  403. package/lib/data-import.js +878 -0
  404. package/lib/db-client.js +48 -3
  405. package/lib/durable.js +73 -0
  406. package/lib/gate.js +90 -1
  407. package/lib/ingest.js +40 -0
  408. package/lib/legacy-offer.js +185 -0
  409. package/lib/legacy-scores.js +77 -0
  410. package/lib/linkedin-limits.js +124 -1
  411. package/lib/release.js +5 -2
  412. package/lib/rpc.js +121 -13
  413. package/lib/sample-stats.js +16 -0
  414. package/lib/scan-progress.js +13 -0
  415. package/lib/scan-state.js +53 -0
  416. package/lib/scanner-python.js +685 -0
  417. package/lib/scanner-setup.js +104 -0
  418. package/lib/scoring.js +747 -138
  419. package/lib/scraper-client.js +10 -6
  420. package/lib/sector-directory.js +1532 -0
  421. package/lib/sector-focus.js +163 -0
  422. package/lib/sector-labels.js +81 -0
  423. package/lib/settings-effects.js +59 -0
  424. package/lib/settings.js +83 -0
  425. package/lib/updater-job.js +838 -0
  426. package/lib/updater.js +494 -0
  427. package/package.json +12 -11
  428. package/public/demo-data.json +1 -1
  429. package/scripts/requirements.txt +106 -4
  430. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jrmmj-._.js +0 -150
  431. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qx548g._.js +0 -151
  432. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1an3leo._.js +0 -150
  433. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1m8zedk._.js +0 -155
  434. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1zor0ys._.js +0 -3
  435. package/.next/standalone/.next/server/chunks/_0_rp-01._.js +0 -3
  436. package/.next/standalone/.next/server/chunks/_0hzdk79._.js +0 -3
  437. package/.next/standalone/.next/server/chunks/_0ow7u5r._.js +0 -3
  438. package/.next/standalone/.next/server/chunks/_0t0zc2d._.js +0 -3
  439. package/.next/standalone/.next/server/chunks/_0wa631d._.js +0 -3
  440. package/.next/standalone/.next/server/chunks/_13ccnao._.js +0 -3
  441. package/.next/standalone/.next/server/chunks/_13es063._.js +0 -3
  442. package/.next/standalone/.next/server/chunks/_142872j._.js +0 -3
  443. package/.next/standalone/.next/server/chunks/_18wsb_a._.js +0 -8
  444. package/.next/standalone/.next/server/chunks/_1e-4h5h._.js +0 -3
  445. package/.next/standalone/.next/server/chunks/_1gvvd7n._.js +0 -158
  446. package/.next/standalone/.next/server/chunks/_1moda66._.js +0 -3
  447. package/.next/standalone/.next/server/chunks/_1p6ghzv._.js +0 -3
  448. package/.next/standalone/.next/server/chunks/_1xmmi_v._.js +0 -3
  449. package/.next/standalone/.next/server/chunks/_1z-yrlf._.js +0 -3
  450. package/.next/standalone/.next/server/chunks/ssr/_0bf3x4q._.js +0 -3
  451. package/.next/standalone/.next/server/chunks/ssr/app_paths_page_1ol90m7.js +0 -4
  452. package/.next/standalone/.next/static/N9wokeIiC9rUIGmzBhj6T/_clientMiddlewareManifest.js +0 -6
  453. package/.next/standalone/.next/static/chunks/1odow92u6wxz0.js +0 -1
  454. package/.next/standalone/.next/static/chunks/1wb_is4wsdm-u.js +0 -1
  455. package/.next/standalone/.next/static/chunks/1zmpcmngg5c7-.js +0 -2
  456. package/.next/standalone/.next/static/chunks/220-ne82aus0c.js +0 -44
  457. package/.next/standalone/.next/static/chunks/2rrf5kzx2fhin.js +0 -2
  458. package/.next/standalone/.next/static/chunks/2s_k9x4d0gi9h.js +0 -16
  459. package/.next/standalone/.next/static/chunks/3hsi90cejq2dg.js +0 -1
  460. package/.next/standalone/.next/static/chunks/3pfyuezyqd9ob.js +0 -1
  461. package/.next/standalone/.next/static/chunks/3ts-_4i6bfkh2.js +0 -1
  462. package/.next/standalone/scripts/score-connections.sql +0 -80
  463. package/.next/standalone/scripts/score_new_connections.sql +0 -77
  464. package/.next/static/N9wokeIiC9rUIGmzBhj6T/_clientMiddlewareManifest.js +0 -6
  465. package/.next/static/chunks/1odow92u6wxz0.js +0 -1
  466. package/.next/static/chunks/1wb_is4wsdm-u.js +0 -1
  467. package/.next/static/chunks/1zmpcmngg5c7-.js +0 -2
  468. package/.next/static/chunks/220-ne82aus0c.js +0 -44
  469. package/.next/static/chunks/2rrf5kzx2fhin.js +0 -2
  470. package/.next/static/chunks/2s_k9x4d0gi9h.js +0 -16
  471. package/.next/static/chunks/3hsi90cejq2dg.js +0 -1
  472. package/.next/static/chunks/3pfyuezyqd9ob.js +0 -1
  473. package/.next/static/chunks/3ts-_4i6bfkh2.js +0 -1
  474. package/scripts/score_new_connections.sql +0 -77
  475. /package/.next/standalone/.next/static/{N9wokeIiC9rUIGmzBhj6T → frfHFnRYTA0Wjrw8oZJtY}/_buildManifest.js +0 -0
  476. /package/.next/standalone/.next/static/{N9wokeIiC9rUIGmzBhj6T → frfHFnRYTA0Wjrw8oZJtY}/_ssgManifest.js +0 -0
  477. /package/.next/static/{N9wokeIiC9rUIGmzBhj6T → frfHFnRYTA0Wjrw8oZJtY}/_buildManifest.js +0 -0
  478. /package/.next/static/{N9wokeIiC9rUIGmzBhj6T → frfHFnRYTA0Wjrw8oZJtY}/_ssgManifest.js +0 -0
@@ -12,12 +12,14 @@
12
12
  //
13
13
  // What this removes: installing Node, cloning, npm install, and typing a
14
14
  // command. The Node runtime is bundled, so the app has no prerequisites at all
15
- // for the CSV path — download, double-click, drop in your export.
15
+ // for the CSV path — download, double-click, drop in your export. The Electron
16
+ // app also carries the scanner's own Python with its packages installed
17
+ // (bundlePython, DESKTOP.md D2), so scanning needs no install step either.
16
18
  //
17
- // What it does NOT remove: Python and Google Chrome, which the scraper needs.
18
- // Those stay runtime prerequisites and the Scan page already detects both.
19
- // Bundling a Chromium instead would make the scraper MORE detectable, not less,
20
- // which defeats the point of driving the user's real browser.
19
+ // What it does NOT remove: Google Chrome, which the scanner drives. It stays a
20
+ // runtime prerequisite and the Scan page already detects it. Bundling a
21
+ // Chromium instead would make the scanner MORE detectable, not less, which
22
+ // defeats the point of driving the user's real browser.
21
23
  //
22
24
  // Unsigned, because notarisation needs a paid Apple Developer account. macOS
23
25
  // will refuse the first launch; the user allows it once in System Settings.
@@ -25,13 +27,24 @@
25
27
  // separate "app is damaged" failure that unsigned arm64 binaries otherwise hit.
26
28
 
27
29
  import { execFileSync } from 'node:child_process';
28
- import { mkdirSync, rmSync, cpSync, writeFileSync, existsSync, chmodSync, readFileSync, symlinkSync, lstatSync, renameSync, readlinkSync } from 'node:fs';
30
+ import { createHash } from 'node:crypto';
31
+ import {
32
+ mkdirSync, rmSync, cpSync, writeFileSync, existsSync, chmodSync, readFileSync, symlinkSync, lstatSync, renameSync,
33
+ readlinkSync, readdirSync, openSync, readSync, closeSync, realpathSync,
34
+ } from 'node:fs';
29
35
  import path from 'node:path';
30
36
  import os from 'node:os';
31
37
  import { fileURLToPath } from 'node:url';
38
+ import {
39
+ standaloneBuild, downloadVerified, machoSlices, machoSlice, megabytes, IMPORTS,
40
+ } from '../lib/scanner-python.js';
32
41
 
33
42
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
34
43
  const pkg = JSON.parse(readFileSync(path.join(ROOT, 'package.json'), 'utf8'));
44
+ // The oldest macOS the app runs on: the bundled Node 24 needs 13.5 (Electron
45
+ // itself needs 13). Written into Info.plist, and every program in the bundled
46
+ // Python is checked against it (checkPython).
47
+ const MACOS_MIN = '13.5';
35
48
 
36
49
  const NODE_VERSION = process.env.BUNDLE_NODE || 'v24.21.0';
37
50
  const ARCH = process.env.BUNDLE_ARCH || (os.arch() === 'x64' ? 'x64' : 'arm64');
@@ -134,9 +147,13 @@ try {
134
147
  for (const rel of untracked) console.log(` ${rel}`);
135
148
  }
136
149
  } catch { /* not a git checkout: nothing to compare against */ }
137
- // The scraper is not part of the standalone output but the Scan page runs it.
150
+ // The files the app runs from scripts/, copied by name so the app never
151
+ // depends on what Next's tracing happens to bring along (TRAPS §27): the
152
+ // scanner the Scan page runs, and apply-update.sh, the in-app updater's helper.
153
+ // The helper ships inside the app, so the version that swaps the app is the one
154
+ // the user is running, never a script fetched from the main branch.
138
155
  for (const rel of ['scripts/scrape.py', 'scripts/image_store.py', 'scripts/requirements.txt',
139
- 'scripts/score_new_connections.sql', 'scripts/audit-avatars.mjs']) {
156
+ 'scripts/audit-avatars.mjs', 'scripts/apply-update.sh']) {
140
157
  const from = path.join(ROOT, rel);
141
158
  if (existsSync(from)) {
142
159
  mkdirSync(path.join(SERVER_DIR, path.dirname(rel)), { recursive: true });
@@ -171,6 +188,8 @@ export SIX_DEGREES_BIND=127.0.0.1
171
188
  export NEXT_TELEMETRY_DISABLED=1
172
189
  export SIX_DEGREES_ROOT="$HERE/app"
173
190
  export SIX_DEGREES_INSTALL=mac-app
191
+ # This app's own bundle, for the in-app updater (lib/updater.js runningBundle).
192
+ export SIX_DEGREES_APP="$(cd "$HERE/../.." && pwd)"
174
193
  export HOSTNAME=127.0.0.1
175
194
 
176
195
  # Walk up from 6363 so a second copy does not fight the first.
@@ -308,7 +327,7 @@ async function buildElectronShell() {
308
327
  darwinDarkModeSupport: true,
309
328
  // The bundled Node 24 needs macOS 13.5 (Electron itself needs 13), so say
310
329
  // so, and macOS explains it instead of the app failing to start.
311
- extendInfo: { LSMinimumSystemVersion: '13.5' },
330
+ extendInfo: { LSMinimumSystemVersion: MACOS_MIN },
312
331
  osxSign: false, // signed ad hoc below, after everything is in place
313
332
  });
314
333
  console.log(` Electron ${electronVersion} (${ARCH})`);
@@ -316,14 +335,237 @@ async function buildElectronShell() {
316
335
  renameSync(path.join(built, `${APP_NAME}.app`), APP);
317
336
  rmSync(STAGE, { recursive: true, force: true });
318
337
 
338
+ // Put straight into the finished app, so its links are made where they stay
339
+ // and nothing copies them again (TRAPS §37).
340
+ await bundlePython(path.join(APP, 'Contents', 'Resources'));
341
+
319
342
  step('Signing (ad-hoc)');
320
343
  // Electron's framework and helpers must all carry the same kind of signature,
321
344
  // or macOS refuses to load them; re-signing the whole bundle ad hoc does that.
345
+ // --deep reaches nested bundles, not loose programs and libraries in
346
+ // Resources: the Python's were signed one by one first (signPython), and this
347
+ // seals them into the app's signature with everything else.
322
348
  run('codesign', ['--force', '--deep', '--sign', '-', APP]);
323
349
  run('codesign', ['--verify', '--deep', '--strict', APP]);
324
350
  console.log(' signed ad-hoc and verified — no Apple account needed, still unnotarised');
325
351
  }
326
352
 
353
+ // ---- the scanner's Python (Electron app only; DESKTOP.md D2) ------------------
354
+ // A standalone CPython from python-build-standalone, with the scanner's packages
355
+ // installed, at Contents/Resources/python. desktop/main.mjs names it to the
356
+ // server (SIX_DEGREES_PYTHON), which runs the scanner on it before any other
357
+ // Python: no install step, and scanning works offline.
358
+ //
359
+ // Pinned twice: the Python by the release and SHA-256 in lib/scanner-python.js,
360
+ // the packages by the hash of every file in scripts/requirements.txt. Downloads
361
+ // are cached in ~/.cache/six-degrees-build like Node's, and checked every build.
362
+ // Built on a Mac with the same chip (release.yml has one job per chip): pip runs
363
+ // this Python to install into it.
364
+ async function bundlePython(resources) {
365
+ const build = standaloneBuild(`darwin-${ARCH}`);
366
+ const xy = build.version.split('.').slice(0, 2).join('.');
367
+ const py = path.join(resources, 'python');
368
+ const lib = path.join(py, 'lib', `python${xy}`);
369
+
370
+ step(`Fetching Python ${build.version} (${ARCH})`);
371
+ const archive = path.join(CACHE, build.file);
372
+ if (existsSync(archive) && sha256File(archive) === build.sha256) {
373
+ console.log(' using the cached download (its SHA-256 matches the pinned one)');
374
+ } else {
375
+ rmSync(archive, { force: true });
376
+ await downloadVerified(build.url, archive, { sha256: build.sha256, size: build.size, idleMs: 60000 });
377
+ console.log(` downloaded ${megabytes(build.size)} MB; its SHA-256 matches the pinned one`);
378
+ }
379
+ rmSync(py, { recursive: true, force: true });
380
+ run('tar', ['-xzf', archive, '-C', resources]);
381
+ const python = path.join(py, 'bin', 'python3');
382
+ // Only this Python's own packages and settings: nothing from the build
383
+ // machine's user site-packages, PYTHONPATH or pip configuration.
384
+ const env = {
385
+ HOME: os.homedir(), TMPDIR: os.tmpdir(), PATH: '/usr/bin:/bin:/usr/sbin:/sbin', LANG: 'en_US.UTF-8',
386
+ PYTHONNOUSERSITE: '1', PYTHONDONTWRITEBYTECODE: '1',
387
+ };
388
+ try {
389
+ execFileSync(python, ['-c', 'pass'], { env, stdio: 'ignore' });
390
+ } catch {
391
+ console.error(`\n ✗ The ${ARCH} Python can't run on this Mac. Build on a Mac with that chip (release.yml does), or install Rosetta for an Intel build.\n`);
392
+ process.exit(1);
393
+ }
394
+
395
+ step('Installing the scanner\'s packages into it');
396
+ run(python, ['-s', '-m', 'pip', '--isolated', 'install', '--disable-pip-version-check', '--no-input',
397
+ '--no-warn-script-location', '--no-compile', '--index-url', 'https://pypi.org/simple',
398
+ '--cache-dir', path.join(CACHE, 'pip'), '--require-hashes', '--only-binary', ':all:',
399
+ '-r', path.join(ROOT, 'scripts', 'requirements.txt')], { env });
400
+ run(python, ['-s', '-m', 'pip', '--isolated', 'check', '--disable-pip-version-check'], { env });
401
+
402
+ const full = duKb(py);
403
+ trimPython(py, lib, xy);
404
+ const trimmed = duKb(py);
405
+ const shared = shareDriverNode(lib, resources);
406
+ signPython(py);
407
+ checkPython(py, lib, env);
408
+ console.log(` Python ${build.version} and the scanner's packages: ${Math.round(full / 1024)} MB installed, `
409
+ + `${Math.round(trimmed / 1024)} MB after trimming, ${Math.round(duKb(py) / 1024)} MB in the app`
410
+ + (shared ? ' (Playwright runs on the app\'s own Node)' : ''));
411
+ }
412
+
413
+ function sha256File(file) {
414
+ return createHash('sha256').update(readFileSync(file)).digest('hex');
415
+ }
416
+
417
+ function duKb(dir) {
418
+ return Number.parseInt(execFileSync('du', ['-sk', dir]).toString(), 10) || 0;
419
+ }
420
+
421
+ // Every file under `dir`, not following links.
422
+ function* walk(dir) {
423
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
424
+ const at = path.join(dir, entry.name);
425
+ if (entry.isDirectory()) yield* walk(at);
426
+ else yield { at, entry };
427
+ }
428
+ }
429
+
430
+ // The Mach-O programs and libraries under `dir`, as { file, slices, head }.
431
+ function machoFiles(dir) {
432
+ const found = [];
433
+ for (const { at, entry } of walk(dir)) {
434
+ if (!entry.isFile()) continue;
435
+ const head = readAt(at, 0, 65536);
436
+ const slices = machoSlices(head);
437
+ if (slices.length) found.push({ file: at, slices });
438
+ }
439
+ return found;
440
+ }
441
+
442
+ function readAt(file, offset, length) {
443
+ const fd = openSync(file, 'r');
444
+ try {
445
+ const buf = Buffer.alloc(length);
446
+ const n = readSync(fd, buf, 0, length, offset);
447
+ return buf.subarray(0, n);
448
+ } finally {
449
+ closeSync(fd);
450
+ }
451
+ }
452
+
453
+ // What the scanner never uses, taken out to keep the download small. None of
454
+ // it is imported by scrape.py or its packages (checkPython proves the imports
455
+ // still load, and CI runs the scanner's pure functions on this Python):
456
+ // - bin/ keeps only the interpreter. pip's console scripts (idna, normalizer,
457
+ // playwright) name the build machine's path in their first line, and pip
458
+ // itself goes below: nothing installs into the app once it is built.
459
+ // - IDLE, tkinter and Tcl/Tk, turtle, lib2to3, ensurepip, the C headers and
460
+ // build files, man pages, test suites, and bytecode: without
461
+ // __pycache__ a module is compiled as it is imported (about 0.3 s for the
462
+ // scanner's), and ownPythonEnv never lets it write any into the app.
463
+ // - libpython's shared library: the interpreter has Python built in, so it is
464
+ // kept only if something inside links to it.
465
+ function trimPython(py, lib, xy) {
466
+ step('Trimming what the scanner never uses');
467
+ const keepInBin = new Set([`python${xy}`, 'python3', 'python']);
468
+ for (const name of readdirSync(path.join(py, 'bin'))) {
469
+ if (!keepInBin.has(name)) rmSync(path.join(py, 'bin', name), { recursive: true, force: true });
470
+ }
471
+ const remove = [
472
+ 'include', 'share', 'lib/pkgconfig',
473
+ ...readdirSync(path.join(py, 'lib')).filter((n) => /^(libtcl|libtk|tcl|tk|itcl|thread)/.test(n)).map((n) => `lib/${n}`),
474
+ ...['idlelib', 'tkinter', 'turtledemo', 'turtle.py', 'lib2to3', 'ensurepip', 'test', 'idle_test', `config-${xy}-darwin`]
475
+ .map((n) => path.relative(py, path.join(lib, n))),
476
+ ...readdirSync(path.join(lib, 'lib-dynload')).filter((n) => n.startsWith('_tkinter.')).map((n) => path.relative(py, path.join(lib, 'lib-dynload', n))),
477
+ ...readdirSync(path.join(lib, 'site-packages')).filter((n) => n === 'pip' || /^pip-.*\.dist-info$/.test(n))
478
+ .map((n) => path.relative(py, path.join(lib, 'site-packages', n))),
479
+ ];
480
+ for (const rel of remove) rmSync(path.join(py, rel), { recursive: true, force: true });
481
+ for (const dir of [...findDirs(py, (n) => n === '__pycache__'), ...findDirs(path.join(lib, 'site-packages'), (n) => n === 'tests')]) {
482
+ rmSync(dir, { recursive: true, force: true });
483
+ }
484
+ const libpython = path.join(py, 'lib', `libpython${xy}.dylib`);
485
+ if (existsSync(libpython)) {
486
+ const users = machoFiles(py).filter((m) => m.file !== libpython
487
+ && m.slices.some((s) => (machoSlice(readAt(m.file, s.offset, 65536)) || { dylibs: [] }).dylibs.some((d) => d.endsWith(`/libpython${xy}.dylib`))));
488
+ if (users.length) console.log(` keeping libpython${xy}.dylib: ${path.relative(py, users[0].file)} links to it`);
489
+ else rmSync(libpython);
490
+ }
491
+ }
492
+
493
+ function findDirs(dir, match) {
494
+ const found = [];
495
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
496
+ if (!entry.isDirectory()) continue;
497
+ const at = path.join(dir, entry.name);
498
+ if (match(entry.name)) found.push(at);
499
+ else found.push(...findDirs(at, match));
500
+ }
501
+ return found;
502
+ }
503
+
504
+ // Playwright's driver carries its own Node (about 120 MB). When that is byte
505
+ // for byte the Node the app already bundles for its server (Playwright 1.63
506
+ // ships Node 24.21.0, the version build-app pins), the driver's becomes a link
507
+ // to the app's: the same program, about 40 MB less to download. When they
508
+ // differ, the driver keeps its own. Resolves whether it shared.
509
+ function shareDriverNode(lib, resources) {
510
+ const driverNode = path.join(lib, 'site-packages', 'playwright', 'driver', 'node');
511
+ const appNode = path.join(resources, 'node');
512
+ if (!existsSync(driverNode) || !existsSync(appNode)) return false;
513
+ if (sha256File(driverNode) !== sha256File(appNode)) {
514
+ console.log(' Playwright\'s Node differs from the app\'s, so the driver keeps its own');
515
+ return false;
516
+ }
517
+ rmSync(driverNode);
518
+ symlinkSync(path.relative(path.dirname(driverNode), appNode), driverNode);
519
+ if (realpathSync(driverNode) !== realpathSync(appNode)) throw new Error('The driver\'s link to the app\'s Node is wrong.');
520
+ return true;
521
+ }
522
+
523
+ // Every program and library in the Python, signed ad hoc like the rest of the
524
+ // app. On Apple Silicon unsigned code isn't allowed to run at all.
525
+ function signPython(py) {
526
+ const files = machoFiles(py).map((m) => m.file);
527
+ for (let i = 0; i < files.length; i += 64) {
528
+ // Its only chatter is "replacing existing signature", once a file.
529
+ mustRun('codesign', ['--force', '--sign', '-', ...files.slice(i, i + 64)], process.env, 'Signing the app\'s Python failed');
530
+ }
531
+ console.log(` signed ${files.length} programs and libraries ad hoc`);
532
+ }
533
+
534
+ // The Python as the app will run it: every program is for this chip and this
535
+ // app's oldest macOS, the imports load (the compiled parts too: TRAPS §30), and
536
+ // Playwright's driver starts. Any failure fails the build.
537
+ function checkPython(py, lib, env) {
538
+ step('Checking the Python inside the app');
539
+ const newer = (v) => {
540
+ const [a, b] = [String(v).split('.').map(Number), MACOS_MIN.split('.').map(Number)];
541
+ return (a[0] - b[0] || (a[1] || 0) - (b[1] || 0)) > 0;
542
+ };
543
+ for (const m of machoFiles(py)) {
544
+ const slice = m.slices.find((s) => s.arch === ARCH);
545
+ const rel = path.relative(py, m.file);
546
+ if (!slice) throw new Error(`${rel} isn't built for ${ARCH}.`);
547
+ const info = machoSlice(readAt(m.file, slice.offset, 65536));
548
+ if (info?.minos && newer(info.minos)) throw new Error(`${rel} needs macOS ${info.minos}; the app promises ${MACOS_MIN}.`);
549
+ }
550
+ const python = path.join(py, 'bin', 'python3');
551
+ console.log(` ${mustRun(python, ['-s', '-c', `${IMPORTS}; import sys; from importlib.metadata import version as v; `
552
+ + 'print("Python", sys.version.split()[0], "· Playwright", v("playwright"), "· requests", v("requests"), "· Pillow", v("pillow"))'],
553
+ env, 'The scanner\'s packages don\'t load in the app\'s Python')}`);
554
+ const driver = path.join(lib, 'site-packages', 'playwright', 'driver');
555
+ console.log(` Playwright's driver starts: ${mustRun(path.join(driver, 'node'), [path.join(driver, 'package', 'cli.js'), '--version'],
556
+ env, 'Playwright\'s driver doesn\'t start')}`);
557
+ }
558
+
559
+ // What a check printed, or the build stops with what went wrong.
560
+ function mustRun(file, args, env, what) {
561
+ try {
562
+ return execFileSync(file, args, { env, stdio: ['ignore', 'pipe', 'pipe'] }).toString().trim();
563
+ } catch (err) {
564
+ console.error(`\n ✗ ${what}:\n${String(err.stderr || err.message).trim().split('\n').slice(-8).map((l) => ` ${l}`).join('\n')}\n`);
565
+ process.exit(1);
566
+ }
567
+ }
568
+
327
569
  // The app icon, from an SVG: sharp (already here, Next depends on it) draws it
328
570
  // at 1024px, sips makes the sizes macOS wants, iconutil packs them.
329
571
  async function makeIcns(svg, out) {
@@ -179,6 +179,21 @@ function main() {
179
179
  const circle = Array.from({ length: size }, () => person(2, b.id));
180
180
  degree2.push(...circle);
181
181
  }
182
+ // In a real network some people are known by more than one of your
183
+ // connections: that is what "reachable 2+ ways" counts, and what makes
184
+ // sorting Degrees by ways in worth doing. About one in seven gets a second
185
+ // route, and some of those a third. Same person, same profile, another bridge.
186
+ const shared = [];
187
+ for (const p of degree2) {
188
+ if (rand() >= 0.15) continue;
189
+ const others = bridges.filter((b) => b.id !== p.source_connection_id);
190
+ const routes = rand() < 0.3 ? 2 : 1;
191
+ for (let k = 0; k < routes; k++) {
192
+ const b = others.splice(Math.floor(rand() * others.length), 1)[0];
193
+ shared.push({ ...p, id: `${p.id}-via${k + 1}`, source_connection_id: b.id, influence_signals: {} });
194
+ }
195
+ }
196
+ degree2.push(...shared);
182
197
  // Everyone again, together: circles now exist, so bridges get their boost.
183
198
  scoreRows([...degree1, ...degree2]);
184
199
  degree1.sort((a, b) => b.power_score - a.power_score);
@@ -205,7 +220,7 @@ function main() {
205
220
  const kb = Math.round(JSON.stringify(payload).length / 1024);
206
221
  console.log(`wrote ${out} (${kb} KB, seed ${seed})`);
207
222
  console.log(` 1st degree : ${degree1.length}`);
208
- console.log(` 2nd degree : ${degree2.length} across ${BRIDGE_COUNT} bridges`);
223
+ console.log(` 2nd degree : ${degree2.length - shared.length} people across ${BRIDGE_COUNT} bridges, ${new Set(shared.map((r) => r.profile_url)).size} of them reachable 2+ ways`);
209
224
  console.log(` catalysts : ${bridges.filter((b) => b.is_catalyst).length}`);
210
225
  console.log(` tier mix : ${['S','A','B','C','D'].map((t) => `${t}:${tiers[t] || 0}`).join(' ')}`);
211
226
  }
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env python3
2
+ """Draw the README's download buttons.
3
+
4
+ A GitHub README can't style links, so the buttons are pictures: drawn here from
5
+ HTML in Chrome, with the app icon inside, and saved at twice their shown size so
6
+ they stay sharp. Each has its own background, so it reads on GitHub's light and
7
+ dark themes alike. No server needed:
8
+
9
+ python3 scripts/readme_buttons.py
10
+
11
+ Requires playwright (pip3 install playwright) and Google Chrome. Redraw whenever
12
+ the icon (desktop/icon/icon.svg) or the wording changes.
13
+ """
14
+ import pathlib
15
+ import re
16
+ import sys
17
+
18
+ ROOT = pathlib.Path(__file__).resolve().parent.parent
19
+ OUT = ROOT / "docs" / "img"
20
+ ICON = (ROOT / "desktop" / "icon" / "icon.svg").read_text()
21
+ # The icon's artwork sits in its 1024 canvas with a margin (the macOS grid).
22
+ # Cropping to the rounded square lets it fill its spot in the button. A new
23
+ # icon with another canvas needs a new crop, so stop rather than draw it wrong.
24
+ CROP = "100 100 824 824"
25
+ root = re.search(r"<svg\b[^>]*>", ICON)
26
+ if not root or 'viewBox="0 0 1024 1024"' not in root.group(0):
27
+ sys.exit('desktop/icon/icon.svg is no longer a 1024 canvas (viewBox="0 0 1024 1024"): '
28
+ "update CROP in scripts/readme_buttons.py, then look at docs/img/download-*.png")
29
+ tag = re.sub(r'\s(?:viewBox|width|height)="[^"]*"', "", root.group(0))
30
+ ICON = ICON[:root.start()] + tag.replace("<svg", f'<svg viewBox="{CROP}"', 1) + ICON[root.end():]
31
+
32
+ ARROW = """<svg class="arrow" viewBox="0 0 24 24" width="30" height="30" aria-hidden="true">
33
+ <circle cx="12" cy="12" r="11" fill="none" stroke="currentColor" stroke-width="1.6" opacity=".55"/>
34
+ <path d="M12 6.5v9M7.8 11.6 12 15.8l4.2-4.2" fill="none" stroke="currentColor" stroke-width="2"
35
+ stroke-linecap="round" stroke-linejoin="round"/></svg>"""
36
+
37
+ # (file, top line, big line, bottom line, style)
38
+ BUTTONS = [
39
+ ("download-apple-silicon.png", "Click to download for Mac", "Apple Silicon", "M1 or newer", "green"),
40
+ ("download-intel.png", "Click to download for Mac", "Intel", "Macs with an Intel chip", "slate"),
41
+ ]
42
+
43
+ CSS = """
44
+ * { box-sizing: border-box; margin: 0; }
45
+ body { background: transparent; font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
46
+ -webkit-font-smoothing: antialiased; }
47
+ .pad { display: inline-block; padding: 6px 8px 12px; }
48
+ .btn { display: flex; align-items: center; gap: 16px; width: 330px; padding: 13px 18px 13px 14px;
49
+ border-radius: 16px; color: #fff; }
50
+ /* Dark enough that white text passes WCAG AA (4.5:1) everywhere on it. */
51
+ .green { background: linear-gradient(180deg, #1f883d 0%, #1a7f37 55%, #116329 100%);
52
+ box-shadow: 0 1px 0 rgba(255,255,255,.22) inset, 0 0 0 1px rgba(0,0,0,.12), 0 6px 16px rgba(17,99,41,.35); }
53
+ .slate { background: linear-gradient(180deg, #3a414a 0%, #2b3137 55%, #24292f 100%);
54
+ box-shadow: 0 1px 0 rgba(255,255,255,.16) inset, 0 0 0 1px rgba(255,255,255,.14), 0 6px 16px rgba(0,0,0,.28); }
55
+ .icon { flex: none; width: 56px; height: 56px; border-radius: 13px; overflow: hidden;
56
+ box-shadow: 0 0 0 1px rgba(255,255,255,.18), 0 2px 6px rgba(0,0,0,.35); }
57
+ .icon svg { display: block; width: 56px; height: 56px; }
58
+ .text { flex: 1; min-width: 0; line-height: 1.15; }
59
+ .top { font-size: 12.5px; font-weight: 600; letter-spacing: .02em; }
60
+ .big { font-size: 25px; font-weight: 800; letter-spacing: -.01em; margin: 2px 0 3px; }
61
+ .sub { font-size: 13.5px; font-weight: 500; }
62
+ .arrow { flex: none; color: #fff; }
63
+ """
64
+
65
+
66
+ def button_html(top, big, sub, style):
67
+ return f"""<!doctype html><html><head><style>{CSS}</style></head><body>
68
+ <div class="pad" id="shot"><div class="btn {style}">
69
+ <div class="icon">{ICON}</div>
70
+ <div class="text"><div class="top">{top}</div><div class="big">{big}</div><div class="sub">{sub}</div></div>
71
+ {ARROW}
72
+ </div></div></body></html>"""
73
+
74
+
75
+ def main():
76
+ from playwright.sync_api import sync_playwright
77
+
78
+ with sync_playwright() as p:
79
+ browser = p.chromium.launch(channel="chrome")
80
+ page = browser.new_page(viewport={"width": 600, "height": 200}, device_scale_factor=2)
81
+ for name, top, big, sub, style in BUTTONS:
82
+ page.set_content(button_html(top, big, sub, style))
83
+ page.locator("#shot").screenshot(path=str(OUT / name), omit_background=True)
84
+ print(f" wrote docs/img/{name}")
85
+ browser.close()
86
+
87
+
88
+ if __name__ == "__main__":
89
+ main()
@@ -1,4 +1,106 @@
1
- playwright>=1.40.0
2
- requests>=2.31.0
3
- Pillow>=10.0.0
4
- tzdata>=2024.1; sys_platform == "win32"
1
+ # The scanner's Python packages (scripts/scrape.py), pinned to exact versions,
2
+ # with the SHA-256 of every file pip may install for each. The same file goes
3
+ # into the Python inside the Mac app when it is built (scripts/build-app.mjs),
4
+ # and into the scanner's own environment when the Scan page sets one up.
5
+ #
6
+ # To change a version, edit its line and run
7
+ # node scripts/pin-python-packages.mjs
8
+ # which rewrites the hashes from PyPI. Every dependency is listed: once hashes
9
+ # are used, pip refuses anything that isn't.
10
+
11
+ --only-binary :all:
12
+ --require-hashes
13
+
14
+ # Drives the user's own Google Chrome (channel="chrome"), so no browser is downloaded.
15
+ # Its wheel carries Playwright's driver, which it needs.
16
+ playwright==1.63.0 \
17
+ --hash=sha256:354e15b29503565fc598b89f16fbe070459343bef9d7498a93e304864000c6a7 \
18
+ --hash=sha256:84c540759e8e7f01e690e197e04060f48899d37cea322299f255843273d3385d \
19
+ --hash=sha256:ad21bc07516b187965a7521c5cf0df0bd657b17482eaad74335272d35a2b07de \
20
+ --hash=sha256:c89fc4736502a1f0fac2c8ca5d10c0cbc1c669f1f4774a2d8507a43140e4d53f \
21
+ --hash=sha256:fd1aa00631d44d55e56e0975bf3f3f285fac4a9fd2813183f0c12a488f1a1b24
22
+
23
+ # Playwright's own dependencies: greenlet, pyee, and pyee's typing-extensions.
24
+ greenlet==3.5.6 \
25
+ --hash=sha256:1c20ea32a73d17b9b60e3371240e17b0068120c98a5ec01a224a7dd8c89733ba \
26
+ --hash=sha256:45bfd2b51e38aaa5f9849f114d9c7c1d75f69187c849b3549cd64c465283abfa \
27
+ --hash=sha256:8cddea1b8339451c2fb3388e138347b6126744f33b611bdb55b7357361cfef46 \
28
+ --hash=sha256:95e7c44d072db623a1aab04ce488cf9533294a77ed9d072cd503a3596f4106ac \
29
+ --hash=sha256:975736b002ed080d124cf81a79cb7e05cb26d6b3f5c7a7b651c0fcce70353aa1 \
30
+ --hash=sha256:9a09d59bef1db94f384b5bcc2d523694d338f3df6b757aeeaf7baca5d0c0be88 \
31
+ --hash=sha256:a5876d0a60355af98d535c47f6cd6eb0f8a432396dab26845d380b92f8412422 \
32
+ --hash=sha256:a6a4b98a9132e0f45c9fc245a63894cfd8c45fb7a0d6bffc5eab3ec327cf7324 \
33
+ --hash=sha256:b7d501d5eb5d4f67207df364752ad697465b834268744be7581c18d81d35d41d \
34
+ --hash=sha256:c59acfa8eb73a1e0d484392dc002bdf001fd4ce73394e0132df3d1ab6093d7cb \
35
+ --hash=sha256:c75116c9de79949de23006e2d9b35ee82874c594fcf5c0311b439acaa14b8441 \
36
+ --hash=sha256:e85880b538e59a59f55117b81f208a6660ad5ac328aad9305f812d9b8bc67a0f \
37
+ --hash=sha256:eed88b64a5e5da72d6a71cdc5aaeefaa5ced9b748f8d19f89800b339961dad39 \
38
+ --hash=sha256:f96f0e30b5a95c7631b12bfe214cbc90ec8fe8cfa36920596c10514a65743519 \
39
+ --hash=sha256:f98e8215e172f567ce80eeaed9107fb4d32b6c44f26983d9b8334658136a205a
40
+
41
+ pyee==13.0.1 \
42
+ --hash=sha256:af2f8fede4171ef667dfded53f96e2ed0d6e6bd7ee3bb46437f77e3b57689228
43
+
44
+ typing-extensions==4.16.0 \
45
+ --hash=sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8
46
+
47
+ requests==2.34.2 \
48
+ --hash=sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0
49
+
50
+ # requests' own dependencies: certifi, charset-normalizer, idna, urllib3.
51
+ certifi==2026.7.22 \
52
+ --hash=sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775
53
+
54
+ charset-normalizer==3.5.1 \
55
+ --hash=sha256:15f024313246a4ed976c60f440bb8d257815513a681d212ff74fd46f7d715a90 \
56
+ --hash=sha256:2f06b7eae9dbe77fe1d644ca244dad508de8d302870a43f3c559b521270938a0 \
57
+ --hash=sha256:41876ee62a3dddf48ff1121ad8f0798032aa03f2fd35f21f34a4cab14f18d8d2 \
58
+ --hash=sha256:4582c27e8c889d64811987b5967fbd3ae0c823fe1fd933b543d55ac20bb475fa \
59
+ --hash=sha256:5b6d1386bf0096d26d3a863dc0a487a5b4eb9aa93cf5ba69683d29dde6b9d60f \
60
+ --hash=sha256:62b55f6722735a6c472f88361cde6640608773d9443cebdbb51abf436a1fcdd3 \
61
+ --hash=sha256:6df0ec430f9a831772c23ca5a224cba36517a58a84bb32c32bb59a9fa67c47f6 \
62
+ --hash=sha256:94d78ecec2605a8d0398b0f365d5f12a63248438516f5dac536a5eff7337df4a \
63
+ --hash=sha256:96eefc178f8636b9c760c5829345307fd81cfae9ab1e80997dbddeb0f54ee9a3 \
64
+ --hash=sha256:a6dac12ff6b846103483683f60c5f8fee205121adc58ffd87e90a90a3af69e99 \
65
+ --hash=sha256:aa2bb0b37202dca27175591f761108b5d34096ade1191ffe4808bdf6b1571488 \
66
+ --hash=sha256:b9af956078716df40d985fb0dfeb2c2120c5ca92ba4ff4b388acfd01cdc14d08 \
67
+ --hash=sha256:c428c6c31eb5f4277d7f8eccaf767fbd548ddd5ce3c8b4f4cbbfab3d96b5904c \
68
+ --hash=sha256:c7b742bf31c88566b4bb6335a7f393bb322e580b6bb98df7bd0c25e6e3519ce8 \
69
+ --hash=sha256:cee5dd7c6fb5dd52a0fe2a740f9bc6e3593f5f8b1788bde49de02086f30182b2 \
70
+ --hash=sha256:d1ee1e296209fdce05b81b663250eefa02213a2da7b41bf26f7829b8ba3545aa \
71
+ --hash=sha256:e90251c0c7bdd54a100a0dce3c07b7e637278c93af29dbf78ebb89a58c4bac7d \
72
+ --hash=sha256:e9fbdce1e47394b09bc9f26ab117dfc8d6491977a11d86f592bb42c779db2fda \
73
+ --hash=sha256:eda059b6bc8bc0812d626fd91a7ce01bf583df0a61296eff390fd94141a34e30
74
+
75
+ idna==3.20 \
76
+ --hash=sha256:ab7ae7122974553370f0bdb919e1a960b2cd1bc1ef0276416d896db81c14582c
77
+
78
+ urllib3==2.8.0 \
79
+ --hash=sha256:0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3
80
+
81
+ # Profile photos (scripts/image_store.py).
82
+ pillow==12.3.0 \
83
+ --hash=sha256:00808c5e14ef63ac5161091d242999076604ff74b883423a11e5d7bbb38bf756 \
84
+ --hash=sha256:0847a763afefb695bc912d7c131e7e0632d4edc1d8698f58ddabec8e46b8b6d3 \
85
+ --hash=sha256:23d27a3e0307ec2244cc51e7287b919aa68d097504ebe19df4e76a98a3eea5bd \
86
+ --hash=sha256:251bf95b67017e27b13d82f5b326234ca62d70f9cf4c2b9032de2358a3b12c7b \
87
+ --hash=sha256:37d6d0a00072fd2948eb22bce7e1475f34569d90c87c59f7a2ec59541b77f7a6 \
88
+ --hash=sha256:5594fc43d548a7ed94949d139aa1341b270f1863f11cfd37f5a6c8b778a6b67f \
89
+ --hash=sha256:6c0016e7b354317c4e9e525b937ac8596c38d2d232b419529b9cd7a1cd46e39a \
90
+ --hash=sha256:78cb2c6865a35ab8ff8b75fd122f6033b92a62c82801110e48ddd6c936a45d91 \
91
+ --hash=sha256:7a743ff716f746fc19a9557f60dab1600d4613255f8a7aeb3cdde4db7eb15a66 \
92
+ --hash=sha256:ba09209fbe443b4acccebe845d8a138b89a8f4fbaeedd44953490b5315d5e965 \
93
+ --hash=sha256:ba54cfebe86920a559a7c4d6b9050791c20513650a1952ebe3368c7dc70306f8 \
94
+ --hash=sha256:bcb46e2f9feff8d06323983bd83ed00c201fdcab3d74973e7072a889b3979fcd \
95
+ --hash=sha256:bcc33feacfaefce60c12fd500a277533bdc02b10a19f7f6d348763d8140bbba7 \
96
+ --hash=sha256:d69141514cc30b774ceea5e3ed3a6635c8d8a96edf664689b890f4089111fb35 \
97
+ --hash=sha256:d9c7f76c0673154f044e9d78c8655fb4213f6ca31a836df48b40fe5d187717b9 \
98
+ --hash=sha256:e158cb00350dc278f3b91551101aa7d12415a66ebf2c91d8d5ac14e56ddd3ad0 \
99
+ --hash=sha256:e9aeb04d6aef139de265b29683e119b638208f88cf73cdd1658aa07221165321 \
100
+ --hash=sha256:f0606c8bf2cdefea14a43530f7657cbbb7ecf1c4222512492ef4a4434a9501ec \
101
+ --hash=sha256:f7401aebd7f581d7f83a439d87d474999317ee099218e5ad25d125290990ba65 \
102
+ --hash=sha256:ffd0c5368496f41b0944be820fcb7a838aa6e623d250b01acf2643939c3f99d7
103
+
104
+ # Windows only: Python there has no time zone database (docs/brain/DESKTOP.md D3).
105
+ tzdata==2026.4 ; sys_platform == "win32" \
106
+ --hash=sha256:c2169a8b0a7a5e9674da5a135ccdfb2b3e671b333ed9fed17b41f73c34476e81
@@ -102,6 +102,8 @@ def main():
102
102
  if script:
103
103
  page.evaluate(script)
104
104
  page.wait_for_timeout(1500)
105
+ # The dev server's own badge (Next.js's "N" in a corner) isn't part of the app.
106
+ page.add_style_tag(content="nextjs-portal { display: none !important; }")
105
107
  page.screenshot(path=str(OUT / name))
106
108
  print(f" wrote docs/img/{name}")
107
109