fedipod-server 0.28.1 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (438) hide show
  1. package/README.md +38 -34
  2. package/config/server.json +22 -0
  3. package/dist/claims.js +3 -2
  4. package/dist/directory.d.ts +2 -0
  5. package/dist/door.d.ts +4 -0
  6. package/dist/door.js +31 -0
  7. package/dist/fedipod.d.ts +16 -0
  8. package/dist/fedipod.js +13 -0
  9. package/dist/front.d.ts +3 -0
  10. package/dist/front.js +94 -0
  11. package/dist/handler.d.ts +39 -101
  12. package/dist/handler.js +86 -617
  13. package/dist/handler.jsonld +6 -30
  14. package/dist/identities.d.ts +62 -0
  15. package/dist/identities.js +236 -0
  16. package/dist/mounts.d.ts +43 -0
  17. package/dist/mounts.js +123 -0
  18. package/dist/opt-in.d.ts +46 -0
  19. package/dist/opt-in.js +176 -0
  20. package/dist/store-pod.js +37 -0
  21. package/package.json +10 -18
  22. package/lib/client/c2s.mjs +0 -582
  23. package/lib/client/localapi.mjs +0 -87
  24. package/lib/client/masto/accounts.mjs +0 -309
  25. package/lib/client/masto/body.mjs +0 -156
  26. package/lib/client/masto/index.mjs +0 -206
  27. package/lib/client/masto/instance.mjs +0 -112
  28. package/lib/client/masto/media.mjs +0 -79
  29. package/lib/client/masto/oauth.mjs +0 -656
  30. package/lib/client/masto/render.mjs +0 -518
  31. package/lib/client/masto/statuses.mjs +0 -372
  32. package/lib/client/masto/timelines.mjs +0 -438
  33. package/lib/client/oidc-auth.mjs +0 -62
  34. package/lib/client/streaming.mjs +0 -154
  35. package/lib/client/webpush.mjs +0 -98
  36. package/lib/connections/acctfeed.mjs +0 -257
  37. package/lib/connections/atproto.mjs +0 -309
  38. package/lib/connections/bskyfeed.mjs +0 -243
  39. package/lib/connections/bskygroup.mjs +0 -162
  40. package/lib/connections/fediacct.mjs +0 -253
  41. package/lib/connections/import.mjs +0 -357
  42. package/lib/connections/tagfeed.mjs +0 -212
  43. package/lib/connections/vault.mjs +0 -114
  44. package/lib/core/as2.mjs +0 -206
  45. package/lib/core/contexts/activitystreams.json +0 -379
  46. package/lib/core/contexts/anno.json +0 -126
  47. package/lib/core/contexts/did-v1.json +0 -57
  48. package/lib/core/contexts/fep-5711.json +0 -36
  49. package/lib/core/contexts/gotosocial.json +0 -86
  50. package/lib/core/contexts/identity-v1.json +0 -152
  51. package/lib/core/contexts/index.mjs +0 -63
  52. package/lib/core/contexts/join-lemmy.json +0 -33
  53. package/lib/core/contexts/joinmastodon.json +0 -28
  54. package/lib/core/contexts/litepub-0.1.json +0 -60
  55. package/lib/core/contexts/map.json +0 -19
  56. package/lib/core/contexts/miscellany.json +0 -19
  57. package/lib/core/contexts/quotes.json +0 -18
  58. package/lib/core/contexts/schemaorg.json +0 -8845
  59. package/lib/core/contexts/security-data-integrity-v1.json +0 -78
  60. package/lib/core/contexts/security-data-integrity-v2.json +0 -81
  61. package/lib/core/contexts/security-multikey-v1.json +0 -35
  62. package/lib/core/contexts/security-v1.json +0 -74
  63. package/lib/core/contexts/webfinger.json +0 -10
  64. package/lib/core/deliver.mjs +0 -371
  65. package/lib/core/graphview.mjs +0 -327
  66. package/lib/core/intake/activities.mjs +0 -633
  67. package/lib/core/intake/activity.mjs +0 -318
  68. package/lib/core/intake/channel.mjs +0 -144
  69. package/lib/core/intake/group.mjs +0 -256
  70. package/lib/core/intake/index.mjs +0 -701
  71. package/lib/core/intake/notes.mjs +0 -360
  72. package/lib/core/intake/verify.mjs +0 -142
  73. package/lib/core/keys.mjs +0 -153
  74. package/lib/core/lease.mjs +0 -206
  75. package/lib/core/polls.mjs +0 -105
  76. package/lib/core/profile-page.mjs +0 -104
  77. package/lib/core/proof.mjs +0 -79
  78. package/lib/core/publisher/collections.mjs +0 -237
  79. package/lib/core/publisher/index.mjs +0 -500
  80. package/lib/core/publisher/notes.mjs +0 -453
  81. package/lib/core/publisher/questions.mjs +0 -239
  82. package/lib/core/publisher/restore.mjs +0 -224
  83. package/lib/core/shapes/activitystreams.ttl +0 -157
  84. package/lib/core/shapes/index.mjs +0 -132
  85. package/lib/core/shapes/shapes-text.mjs +0 -13
  86. package/lib/core/social.mjs +0 -531
  87. package/lib/core/storage.mjs +0 -176
  88. package/lib/core/store.mjs +0 -568
  89. package/lib/core/wire-quotes.mjs +0 -71
  90. package/lib/core/wire.mjs +0 -889
  91. package/lib/device/account.mjs +0 -87
  92. package/lib/device/admin/index.mjs +0 -13
  93. package/lib/device/admin/origins.mjs +0 -35
  94. package/lib/device/admin/routes/connections.mjs +0 -144
  95. package/lib/device/admin/routes/gateway.mjs +0 -199
  96. package/lib/device/admin/routes/lifecycle.mjs +0 -200
  97. package/lib/device/admin/routes/owner.mjs +0 -322
  98. package/lib/device/admin/routes/setup.mjs +0 -412
  99. package/lib/device/admin/routes/social.mjs +0 -188
  100. package/lib/device/admin/server.mjs +0 -95
  101. package/lib/device/admin/static.mjs +0 -247
  102. package/lib/device/admin/surface.mjs +0 -315
  103. package/lib/device/certs.mjs +0 -281
  104. package/lib/device/cli/commands/account.mjs +0 -586
  105. package/lib/device/cli/commands/run.mjs +0 -278
  106. package/lib/device/cli/commands/service.mjs +0 -221
  107. package/lib/device/cli/commands/setup.mjs +0 -447
  108. package/lib/device/cli/commands/state.mjs +0 -561
  109. package/lib/device/cli/context.mjs +0 -288
  110. package/lib/device/export-collections.mjs +0 -161
  111. package/lib/device/gateway-move.mjs +0 -58
  112. package/lib/device/home.mjs +0 -161
  113. package/lib/device/migrate.mjs +0 -115
  114. package/lib/device/ports.mjs +0 -27
  115. package/lib/device/remote.mjs +0 -54
  116. package/lib/device/setup.mjs +0 -459
  117. package/lib/device/update.mjs +0 -96
  118. package/lib/gateway/caches.mjs +0 -36
  119. package/lib/gateway/directory.mjs +0 -90
  120. package/lib/gateway/front-core.mjs +0 -970
  121. package/lib/gateway/gateway-core.mjs +0 -165
  122. package/lib/gateway/headers.mjs +0 -49
  123. package/lib/gateway/httpsig.mjs +0 -159
  124. package/lib/gateway/notices.mjs +0 -84
  125. package/lib/gateway/quiet.mjs +0 -189
  126. package/lib/pod/README.md +0 -61
  127. package/lib/pod/actor.mjs +0 -96
  128. package/lib/pod/collection.mjs +0 -77
  129. package/lib/pod/containers.mjs +0 -140
  130. package/lib/pod/discovery.mjs +0 -46
  131. package/lib/pod/featured.mjs +0 -18
  132. package/lib/pod/followers.mjs +0 -24
  133. package/lib/pod/following.mjs +0 -10
  134. package/lib/pod/http.mjs +0 -74
  135. package/lib/pod/inbox.mjs +0 -166
  136. package/lib/pod/links.mjs +0 -35
  137. package/lib/pod/media.mjs +0 -27
  138. package/lib/pod/notes.mjs +0 -80
  139. package/lib/pod/notifications.mjs +0 -89
  140. package/lib/pod/outbox.mjs +0 -18
  141. package/lib/pod/package.json +0 -19
  142. package/lib/pod/policy.mjs +0 -58
  143. package/lib/pod/private.mjs +0 -19
  144. package/lib/pod/root.mjs +0 -104
  145. package/lib/pod/state.mjs +0 -40
  146. package/lib/pod/transport.mjs +0 -525
  147. package/lib/pod/urls.mjs +0 -85
  148. package/lib/server/embed.mjs +0 -423
  149. package/lib/session/README.md +0 -137
  150. package/lib/session/demo.html +0 -94
  151. package/lib/session/fedi-account.mjs +0 -408
  152. package/lib/session/fedi-login.mjs +0 -123
  153. package/lib/session/oidc-session.mjs +0 -233
  154. package/lib/session/package.json +0 -49
  155. package/lib/shared/guard.mjs +0 -213
  156. package/lib/shared/links.mjs +0 -9
  157. package/lib/shared/safefetch.mjs +0 -235
  158. package/lib/shared/ua.mjs +0 -29
  159. package/phanpy/dist/404.html +0 -40
  160. package/phanpy/dist/_headers +0 -2
  161. package/phanpy/dist/apple-touch-icon.png +0 -0
  162. package/phanpy/dist/assets/ICONS-DIPJeU0C.js +0 -2
  163. package/phanpy/dist/assets/ICONS-DIPJeU0C.js.map +0 -1
  164. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js +0 -183
  165. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js.map +0 -1
  166. package/phanpy/dist/assets/Temml-CCjoacWt.woff2 +0 -0
  167. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js +0 -2
  168. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js.map +0 -1
  169. package/phanpy/dist/assets/boosts-carousel-BiOaNdMT.jpg +0 -0
  170. package/phanpy/dist/assets/catch-up-O5q5C75Z.png +0 -0
  171. package/phanpy/dist/assets/chunk-aKtaBQYM.js +0 -1
  172. package/phanpy/dist/assets/compose-CFEx7wb4.js +0 -2
  173. package/phanpy/dist/assets/compose-CFEx7wb4.js.map +0 -1
  174. package/phanpy/dist/assets/compose-ZJN5xSb4.js +0 -35
  175. package/phanpy/dist/assets/compose-ZJN5xSb4.js.map +0 -1
  176. package/phanpy/dist/assets/debug.module-YFQgwnIr.js +0 -52
  177. package/phanpy/dist/assets/debug.module-YFQgwnIr.js.map +0 -1
  178. package/phanpy/dist/assets/dom-p1YcJ5Rw.js +0 -2
  179. package/phanpy/dist/assets/dom-p1YcJ5Rw.js.map +0 -1
  180. package/phanpy/dist/assets/home-mobile-dark@2x-Dc-J8-SM.png +0 -0
  181. package/phanpy/dist/assets/home-mobile-light@2x-Bd3fod8m.png +0 -0
  182. package/phanpy/dist/assets/home-tablet-dark@2x-BgcNI8le.png +0 -0
  183. package/phanpy/dist/assets/home-tablet-light@2x-BW2RV9T6.png +0 -0
  184. package/phanpy/dist/assets/icons/add-circle-line-WD0mwORD.js +0 -1
  185. package/phanpy/dist/assets/icons/alert-line-CpFUMf9s.js +0 -1
  186. package/phanpy/dist/assets/icons/android-2-line-Bzxnrd3S.js +0 -1
  187. package/phanpy/dist/assets/icons/announcement-line-5nwaJFJm.js +0 -1
  188. package/phanpy/dist/assets/icons/arrow-down-circle-line-a7Id9-Iv.js +0 -1
  189. package/phanpy/dist/assets/icons/arrow-down-line-B8uzXzq6.js +0 -1
  190. package/phanpy/dist/assets/icons/arrow-left-line-CGrGT9C-.js +0 -1
  191. package/phanpy/dist/assets/icons/arrow-right-line-CE-HERfX.js +0 -1
  192. package/phanpy/dist/assets/icons/arrow-to-up-line-CvdQjmcy.js +0 -1
  193. package/phanpy/dist/assets/icons/arrow-up-circle-line-DEparSNF.js +0 -1
  194. package/phanpy/dist/assets/icons/arrow-up-line-C7yBeugc.js +0 -1
  195. package/phanpy/dist/assets/icons/arrows-right-line-BtbXmJGP.js +0 -1
  196. package/phanpy/dist/assets/icons/at-line-CF66Bznk.js +0 -1
  197. package/phanpy/dist/assets/icons/attachment-line-BY8It-l9.js +0 -1
  198. package/phanpy/dist/assets/icons/blockquote-line-BS6pU_hm.js +0 -1
  199. package/phanpy/dist/assets/icons/board-line-C0UWXyA6.js +0 -1
  200. package/phanpy/dist/assets/icons/bookmark-line-1CtX5JLF.js +0 -1
  201. package/phanpy/dist/assets/icons/building-5-line-Dd59MzbO.js +0 -1
  202. package/phanpy/dist/assets/icons/bus-2-line-6_dvA0GG.js +0 -1
  203. package/phanpy/dist/assets/icons/calendar-day-line-Crpl_fmu.js +0 -1
  204. package/phanpy/dist/assets/icons/calendar-month-line-vommts2C.js +0 -1
  205. package/phanpy/dist/assets/icons/calendar-time-add-line-BU_DTlQk.js +0 -1
  206. package/phanpy/dist/assets/icons/camera-line-Cv69MEei.js +0 -1
  207. package/phanpy/dist/assets/icons/celebrate-line-B8DvIoi0.js +0 -1
  208. package/phanpy/dist/assets/icons/chart-bar-line-FK-QOmtF.js +0 -1
  209. package/phanpy/dist/assets/icons/chart-line-line-BGcJAFWw.js +0 -1
  210. package/phanpy/dist/assets/icons/chat-3-line-YFK2-hwz.js +0 -1
  211. package/phanpy/dist/assets/icons/check-circle-line-DsAxFr5-.js +0 -1
  212. package/phanpy/dist/assets/icons/clipboard-line-BBp364gJ.js +0 -1
  213. package/phanpy/dist/assets/icons/close-circle-line-CICdiuGz.js +0 -1
  214. package/phanpy/dist/assets/icons/close-line-DYrFWcjv.js +0 -1
  215. package/phanpy/dist/assets/icons/cloud-line-tiQAbah8.js +0 -1
  216. package/phanpy/dist/assets/icons/code-line-fAl8iiV3.js +0 -1
  217. package/phanpy/dist/assets/icons/comment-2-line-CR3g7WeB.js +0 -1
  218. package/phanpy/dist/assets/icons/copy-2-line-CLW69yF5.js +0 -1
  219. package/phanpy/dist/assets/icons/delete-2-line-B8xmbr4n.js +0 -1
  220. package/phanpy/dist/assets/icons/document-3-line-DBGNhAg2.js +0 -1
  221. package/phanpy/dist/assets/icons/document-line-C7mb9sb7.js +0 -1
  222. package/phanpy/dist/assets/icons/down-line-BGqSSThd.js +0 -1
  223. package/phanpy/dist/assets/icons/edit-4-line-DcgGaEhx.js +0 -1
  224. package/phanpy/dist/assets/icons/emoji-2-line-D8YgnM-y.js +0 -1
  225. package/phanpy/dist/assets/icons/exit-line-Dc07BS-x.js +0 -1
  226. package/phanpy/dist/assets/icons/external-link-line-BvpSkmjO.js +0 -1
  227. package/phanpy/dist/assets/icons/eye-2-line-CiWXx-f_.js +0 -1
  228. package/phanpy/dist/assets/icons/eye-close-line-BgTaSJ4P.js +0 -1
  229. package/phanpy/dist/assets/icons/filter-2-line-B_mR2usy.js +0 -1
  230. package/phanpy/dist/assets/icons/filter-line-C_nm-3cU.js +0 -1
  231. package/phanpy/dist/assets/icons/flag-1-line-C2HB05I0.js +0 -1
  232. package/phanpy/dist/assets/icons/forbid-circle-line-D3LTT9yd.js +0 -1
  233. package/phanpy/dist/assets/icons/formula-line-DLrt2d6j.js +0 -1
  234. package/phanpy/dist/assets/icons/grid-line-CgUmEikf.js +0 -1
  235. package/phanpy/dist/assets/icons/group-line-C5fnX0wU.js +0 -1
  236. package/phanpy/dist/assets/icons/hand-finger-2-line-BGgxbuL9.js +0 -1
  237. package/phanpy/dist/assets/icons/hashtag-line-CyTEEXBb.js +0 -1
  238. package/phanpy/dist/assets/icons/heart-crack-line-BZddbO2C.js +0 -1
  239. package/phanpy/dist/assets/icons/heart-line-CJ7K47J4.js +0 -1
  240. package/phanpy/dist/assets/icons/history-2-line-kWWvFzqv.js +0 -1
  241. package/phanpy/dist/assets/icons/history-line-bGQiwbTH.js +0 -1
  242. package/phanpy/dist/assets/icons/home-3-line-fRU1zeLG.js +0 -1
  243. package/phanpy/dist/assets/icons/information-line-iNk6-sOY.js +0 -1
  244. package/phanpy/dist/assets/icons/keyboard-line-DsCyuQNz.js +0 -1
  245. package/phanpy/dist/assets/icons/layout-4-line-CZkOX52Z.js +0 -1
  246. package/phanpy/dist/assets/icons/layout-5-line-B_znt5wO.js +0 -1
  247. package/phanpy/dist/assets/icons/left-line-eUw0tya4.js +0 -1
  248. package/phanpy/dist/assets/icons/lightning-line-DaKoDdix.js +0 -1
  249. package/phanpy/dist/assets/icons/link-2-line-DCqLmMA7.js +0 -1
  250. package/phanpy/dist/assets/icons/list-check-line-BAxosBh9.js +0 -1
  251. package/phanpy/dist/assets/icons/lock-line-CPoaXeUW.js +0 -1
  252. package/phanpy/dist/assets/icons/mail-line-B0P8aa1L.js +0 -1
  253. package/phanpy/dist/assets/icons/moon-line-CEqNAToP.js +0 -1
  254. package/phanpy/dist/assets/icons/more-1-fill-Dw2e5xab.js +0 -1
  255. package/phanpy/dist/assets/icons/more-3-line-BIiVjYTz.js +0 -1
  256. package/phanpy/dist/assets/icons/notification-line-BZZq2Gtu.js +0 -1
  257. package/phanpy/dist/assets/icons/pencil-line-CKh8-A1v.js +0 -1
  258. package/phanpy/dist/assets/icons/photo-album-line-Bnfg2u40.js +0 -1
  259. package/phanpy/dist/assets/icons/pin-line-DpTolyhs.js +0 -1
  260. package/phanpy/dist/assets/icons/play-fill-B0-G_8lX.js +0 -1
  261. package/phanpy/dist/assets/icons/qrcode-2-line-B6SPCaHn.js +0 -1
  262. package/phanpy/dist/assets/icons/quill-pen-line-B6LUrnCP.js +0 -1
  263. package/phanpy/dist/assets/icons/quote-left-fill-hQZ1cj_6.js +0 -1
  264. package/phanpy/dist/assets/icons/radar-line-CKyroTth.js +0 -1
  265. package/phanpy/dist/assets/icons/react-line-CoIKhhtK.js +0 -1
  266. package/phanpy/dist/assets/icons/refresh-2-line-D0mTF97S.js +0 -1
  267. package/phanpy/dist/assets/icons/right-line-B3KWJaqc.js +0 -1
  268. package/phanpy/dist/assets/icons/rocket-line-4KZl537D.js +0 -1
  269. package/phanpy/dist/assets/icons/round-fill-C69NTrZ0.js +0 -1
  270. package/phanpy/dist/assets/icons/round-line-B9k_1uo-.js +0 -1
  271. package/phanpy/dist/assets/icons/route-line-B28ReHcE.js +0 -1
  272. package/phanpy/dist/assets/icons/rows-4-line-CrBniagM.js +0 -1
  273. package/phanpy/dist/assets/icons/scan-line-DSf74YdP.js +0 -1
  274. package/phanpy/dist/assets/icons/search-2-line-B6geIU1z.js +0 -1
  275. package/phanpy/dist/assets/icons/settings-3-line-azJwK47w.js +0 -1
  276. package/phanpy/dist/assets/icons/settings-6-line-C_5zc5YR.js +0 -1
  277. package/phanpy/dist/assets/icons/share-2-line-D5MxWjrm.js +0 -1
  278. package/phanpy/dist/assets/icons/share-forward-line-Cp61fZzZ.js +0 -1
  279. package/phanpy/dist/assets/icons/sparkles-2-line-DYYyXTaW.js +0 -1
  280. package/phanpy/dist/assets/icons/sparkles-line-C2hY1s6I.js +0 -1
  281. package/phanpy/dist/assets/icons/time-line-BF3eet1v.js +0 -1
  282. package/phanpy/dist/assets/icons/transfer-4-line-oisfvTBw.js +0 -1
  283. package/phanpy/dist/assets/icons/translate-line-BFWol2Ce.js +0 -1
  284. package/phanpy/dist/assets/icons/unlock-line-X_x5vwv3.js +0 -1
  285. package/phanpy/dist/assets/icons/upload-3-line-DgzwUJeW.js +0 -1
  286. package/phanpy/dist/assets/icons/user-4-line-BVSynZCp.js +0 -1
  287. package/phanpy/dist/assets/icons/user-add-2-line-BlGS5Q8q.js +0 -1
  288. package/phanpy/dist/assets/icons/user-add-line-BbXdHG4z.js +0 -1
  289. package/phanpy/dist/assets/icons/user-edit-line-BFAHOV0X.js +0 -1
  290. package/phanpy/dist/assets/icons/user-follow-line-BXux0wSd.js +0 -1
  291. package/phanpy/dist/assets/icons/user-star-line-DdYlpHLU.js +0 -1
  292. package/phanpy/dist/assets/icons/user-warning-line-Cj43j0_E.js +0 -1
  293. package/phanpy/dist/assets/icons/user-x-line-DIDgNlPH.js +0 -1
  294. package/phanpy/dist/assets/icons/volume-line-Bs390KQt.js +0 -1
  295. package/phanpy/dist/assets/icons/volume-mute-line-DzlzIqFZ.js +0 -1
  296. package/phanpy/dist/assets/icons/walk-line-yNXfB-md.js +0 -1
  297. package/phanpy/dist/assets/icons/world-2-line-CenkGIwj.js +0 -1
  298. package/phanpy/dist/assets/icons/zoom-in-line-CaENUphf.js +0 -1
  299. package/phanpy/dist/assets/icons/zoom-out-line-BDNk0EWo.js +0 -1
  300. package/phanpy/dist/assets/instances-BNPptnn-.json +0 -333
  301. package/phanpy/dist/assets/locales/ar-SA-CfheRbCu.js +0 -1
  302. package/phanpy/dist/assets/locales/ca-ES-DHRW86Tz.js +0 -1
  303. package/phanpy/dist/assets/locales/cs-CZ-CKoqEuA1.js +0 -1
  304. package/phanpy/dist/assets/locales/de-DE-ByRPMRFy.js +0 -1
  305. package/phanpy/dist/assets/locales/eo-UY-CPC7wLCS.js +0 -1
  306. package/phanpy/dist/assets/locales/es-ES-dJa0Fd9t.js +0 -1
  307. package/phanpy/dist/assets/locales/eu-ES-C3djlPR2.js +0 -1
  308. package/phanpy/dist/assets/locales/fa-IR-DTT490Ck.js +0 -1
  309. package/phanpy/dist/assets/locales/fi-FI-B23MCPuz.js +0 -1
  310. package/phanpy/dist/assets/locales/fr-FR-BcaQsO5C.js +0 -1
  311. package/phanpy/dist/assets/locales/gl-ES-BR-CVKBN.js +0 -1
  312. package/phanpy/dist/assets/locales/he-IL-CfheRbCu.js +0 -1
  313. package/phanpy/dist/assets/locales/hu-HU-CfheRbCu.js +0 -1
  314. package/phanpy/dist/assets/locales/it-IT-C1136UFV.js +0 -1
  315. package/phanpy/dist/assets/locales/ja-JP-CRZmRAhD.js +0 -1
  316. package/phanpy/dist/assets/locales/kab-Cz8xH_TT.js +0 -1
  317. package/phanpy/dist/assets/locales/ko-KR-CG9UiY4o.js +0 -1
  318. package/phanpy/dist/assets/locales/lt-LT-CJcI6sHZ.js +0 -1
  319. package/phanpy/dist/assets/locales/nb-NO-CfheRbCu.js +0 -1
  320. package/phanpy/dist/assets/locales/nl-NL-DxN4Yc1t.js +0 -1
  321. package/phanpy/dist/assets/locales/oc-FR-CfheRbCu.js +0 -1
  322. package/phanpy/dist/assets/locales/pl-PL-DkwGXf6P.js +0 -1
  323. package/phanpy/dist/assets/locales/pseudo-LOCALE-CQ4XxkQ0.js +0 -1
  324. package/phanpy/dist/assets/locales/pt-BR-nGL0HdFS.js +0 -1
  325. package/phanpy/dist/assets/locales/pt-PT-Cp17aj2z.js +0 -1
  326. package/phanpy/dist/assets/locales/ru-RU-0Y8cIoaK.js +0 -1
  327. package/phanpy/dist/assets/locales/th-TH-CfheRbCu.js +0 -1
  328. package/phanpy/dist/assets/locales/tok-CfheRbCu.js +0 -1
  329. package/phanpy/dist/assets/locales/tr-TR-CfheRbCu.js +0 -1
  330. package/phanpy/dist/assets/locales/uk-UA-C5E3dFBf.js +0 -1
  331. package/phanpy/dist/assets/locales/zh-CN-BHJi7_et.js +0 -1
  332. package/phanpy/dist/assets/locales/zh-TW-CfheRbCu.js +0 -1
  333. package/phanpy/dist/assets/main-BdqNbG-a.js +0 -26
  334. package/phanpy/dist/assets/main-BdqNbG-a.js.map +0 -1
  335. package/phanpy/dist/assets/mock-home-DGhR__He.js +0 -2
  336. package/phanpy/dist/assets/mock-home-DGhR__He.js.map +0 -1
  337. package/phanpy/dist/assets/multi-column-ROck0NVt.jpg +0 -0
  338. package/phanpy/dist/assets/multi-hashtag-timeline-DH5INVHi.jpg +0 -0
  339. package/phanpy/dist/assets/nested-comments-thread-hv59kZLc.jpg +0 -0
  340. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js +0 -2
  341. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js.map +0 -1
  342. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js +0 -20
  343. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js.map +0 -1
  344. package/phanpy/dist/assets/style-B1iLPTPR.css +0 -2
  345. package/phanpy/dist/assets/temml-DuyIQMei.js +0 -97
  346. package/phanpy/dist/assets/temml-DuyIQMei.js.map +0 -1
  347. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js +0 -2
  348. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js.map +0 -1
  349. package/phanpy/dist/assets/year-in-posts-B2lywqdx.png +0 -0
  350. package/phanpy/dist/assets/year-in-posts-DJv_star.js +0 -3
  351. package/phanpy/dist/assets/year-in-posts-DJv_star.js.map +0 -1
  352. package/phanpy/dist/compose/index.html +0 -20
  353. package/phanpy/dist/favicon.ico +0 -0
  354. package/phanpy/dist/index.html +0 -73
  355. package/phanpy/dist/logo-192.png +0 -0
  356. package/phanpy/dist/logo-512.png +0 -0
  357. package/phanpy/dist/logo-badge-72.png +0 -0
  358. package/phanpy/dist/logo-maskable-512.png +0 -0
  359. package/phanpy/dist/logo-monochrome-512.png +0 -0
  360. package/phanpy/dist/logo-monochrome-maskable-512.png +0 -0
  361. package/phanpy/dist/manifest.webmanifest +0 -1
  362. package/phanpy/dist/og-image-2.jpg +0 -0
  363. package/phanpy/dist/og-image.png +0 -0
  364. package/phanpy/dist/robots.txt +0 -2
  365. package/phanpy/dist/sw.js +0 -2
  366. package/phanpy/dist/sw.js.map +0 -1
  367. package/phanpy/dist/version.json +0 -1
  368. package/run-agent.mjs +0 -897
  369. package/vendor/gate.cjs +0 -138
  370. package/vendor/idp-grant.cjs +0 -394
  371. package/vendor/jfetch.cjs +0 -16
  372. package/web/admin/actors.js +0 -145
  373. package/web/admin/bar.css +0 -126
  374. package/web/admin/bar.js +0 -99
  375. package/web/admin/client/client.js +0 -66
  376. package/web/admin/client/index.html +0 -69
  377. package/web/admin/client-pick.js +0 -79
  378. package/web/admin/common.js +0 -23
  379. package/web/admin/connections.js +0 -112
  380. package/web/admin/gateway.js +0 -133
  381. package/web/admin/group.js +0 -258
  382. package/web/admin/index.html +0 -603
  383. package/web/admin/notices-bar.js +0 -90
  384. package/web/admin/oauth-signin.mjs +0 -37
  385. package/web/admin/record.js +0 -390
  386. package/web/admin/setup/index.html +0 -241
  387. package/web/admin/setup/setup.js +0 -326
  388. package/web/admin/tokens.css +0 -68
  389. package/web/admin/upkeep.js +0 -177
  390. package/web/admin/window.css +0 -55
  391. package/web/admin/window.js +0 -136
  392. package/web/app/README.md +0 -81
  393. package/web/app/admin-facade.mjs +0 -588
  394. package/web/app/agent.mjs +0 -663
  395. package/web/app/atproto-browser.mjs +0 -86
  396. package/web/app/authorize_interaction.html +0 -56
  397. package/web/app/authorize_interaction.js +0 -69
  398. package/web/app/boot.mjs +0 -576
  399. package/web/app/deliver-relay.mjs +0 -129
  400. package/web/app/dist/boot.js +0 -34218
  401. package/web/app/dist/boot.js.map +0 -7
  402. package/web/app/dist/sw.js +0 -72810
  403. package/web/app/dist/sw.js.map +0 -7
  404. package/web/app/fediacct-browser.mjs +0 -146
  405. package/web/app/gateway-move.mjs +0 -60
  406. package/web/app/idb-kv.mjs +0 -35
  407. package/web/app/index.html +0 -242
  408. package/web/app/keys-browser.mjs +0 -71
  409. package/web/app/keystore.mjs +0 -82
  410. package/web/app/oidc-session.mjs +0 -6
  411. package/web/app/pod-auth.mjs +0 -248
  412. package/web/app/pod-remote.mjs +0 -84
  413. package/web/app/shims/_globals.mjs +0 -2
  414. package/web/app/shims/fedify-sig.mjs +0 -77
  415. package/web/app/shims/node-crypto.mjs +0 -113
  416. package/web/app/shims/node-fs.mjs +0 -17
  417. package/web/app/shims/node-path.mjs +0 -19
  418. package/web/app/shims/node-url.mjs +0 -7
  419. package/web/app/shims/prelude.js +0 -58
  420. package/web/app/shims/safefetch.mjs +0 -58
  421. package/web/app/shims/shapes-text.mjs +0 -8
  422. package/web/app/shims/web-push.mjs +0 -14
  423. package/web/app/signup.mjs +0 -318
  424. package/web/app/sw-src.mjs +0 -220
  425. package/web/app/update.js +0 -70
  426. package/web/front/admin.html +0 -55
  427. package/web/front/admin.js +0 -89
  428. package/web/front/install.sh +0 -69
  429. package/web/front/new-account.html +0 -35
  430. package/web/front/new-account.js +0 -13
  431. package/web/front/notices.html +0 -69
  432. package/web/front/notices.js +0 -107
  433. package/web/front/run.html +0 -58
  434. package/web/front/run.js +0 -195
  435. package/web/front/solid-oidc-client.js +0 -6
  436. package/web/icons/forum.svg +0 -11
  437. package/web/icons/gateway.svg +0 -14
  438. package/web/icons/local.svg +0 -11
@@ -1,278 +0,0 @@
1
- // run.mjs — starting and stopping: up, start, stop, status, https.
2
-
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import { spawn } from 'node:child_process';
6
- import { identityHomes, rootOf, profileHome, recordLastUsed } from '../../home.mjs';
7
- import { portFree, freePortFrom } from '../../ports.mjs';
8
- import { localFetch } from '../../../client/localapi.mjs';
9
- import { flag, has, portFlag, PROFILE, AP_ROOT, DEFAULT_ISSUE, HOME, PORT, recordedAgent, recordedPort, recordAgent, useProfile, requireHandle, requireIdentity, ask, endAsking, agentOn, openBrowser } from '../context.mjs';
10
-
11
- export async function up() {
12
- // A signup page may have arranged an identity already: the installer records
13
- // its parameters in first-run.json beside this script's package, and the
14
- // carry-over outranks the last-used identity — whether this machine is fresh
15
- // or already full of accounts, `npm start` right after the installer brings
16
- // up the identity the signup arranged, beside any that exist. An explicitly
17
- // named profile or home still means exactly what it says.
18
- const firstRunFile = process.env.AP_FIRST_RUN
19
- || new URL('../../../../first-run.json', import.meta.url).pathname;
20
- const explicitHome = !!(PROFILE || flag('home', null) || process.env.AP_HOME);
21
- let firstRun = null;
22
- if (!explicitHome) {
23
- try { firstRun = JSON.parse(fs.readFileSync(firstRunFile, 'utf8')); } catch { /* none */ }
24
- }
25
- if (firstRun?.handle) {
26
- const carried = String(firstRun.handle);
27
- requireHandle(carried);
28
- if (fs.existsSync(path.join(profileHome(AP_ROOT, carried), 'credential.json'))) {
29
- console.error(`the signup carried the name "${carried}", but an identity with that name already exists here.`);
30
- console.error('To attach the existing identity instead, use the signup page\'s Manage → Attach —');
31
- console.error(`then remove ${firstRunFile} and run this again.`);
32
- process.exit(2);
33
- }
34
- useProfile(carried);
35
- process.env.AP_FIRST_RUN = firstRunFile;
36
- } else if (DEFAULT_ISSUE && !identityHomes(AP_ROOT).some(h => fs.existsSync(path.join(h.dir, 'credential.json')))) {
37
- // A fresh machine has no identity, and an identity is named after its
38
- // handle, so there is no home to start in until that is asked. One
39
- // question, the same one `setup` opens with — `npm start` stays the
40
- // single command it was.
41
- if (!process.stdin.isTTY) {
42
- console.error('no identities yet — fedipod setup');
43
- process.exit(2);
44
- }
45
- const first = await ask('handle (the name in your address; permanent)');
46
- endAsking();
47
- if (!first) { console.error('a handle is required'); process.exit(2); }
48
- requireHandle(first);
49
- useProfile(first);
50
- } else {
51
- requireIdentity();
52
- }
53
- if (rootOf(HOME) === AP_ROOT) recordLastUsed(AP_ROOT, path.basename(HOME));
54
- const preferred = Number(portFlag() || process.env.AP_PORT || recordedPort() || 8030);
55
- const configured = fs.existsSync(path.join(HOME, 'credential.json'));
56
- const { hostLabel } = await import(new URL('../../../../lib/shared/guard.mjs', import.meta.url));
57
-
58
- let port = preferred;
59
- let already = null;
60
- if (!await portFree(preferred)) {
61
- already = await agentOn(preferred);
62
- // Ours already — nothing to start. The directory door yields to a real
63
- // owner of its port. Anything else is simply not this port; walking on is
64
- // what "occupied" has always meant here.
65
- if (!already) {
66
- const { yieldDirectory } = await import(new URL('../../../../lib/gateway/directory.mjs', import.meta.url));
67
- if (!await yieldDirectory(preferred, { portFree })) {
68
- port = await freePortFrom(preferred + 1);
69
- // The shared helper returns null; the message is this command's to write.
70
- if (port == null) throw new Error(`no free port between ${preferred + 1} and ${preferred + 51}`);
71
- }
72
- }
73
- }
74
-
75
- // Both branches take the named origin: setup at the shared one would file the
76
- // first login under localhost:<port>, and the identity is stuck with it.
77
- // The profile name is the handle — that is what naming identities after them
78
- // bought — so the named origin works on the very first run, before anything
79
- // has been recorded.
80
- const label = hostLabel(recordedAgent().handle || path.basename(HOME));
81
- // One listener, one scheme: the port the agent was given is the port you
82
- // browse, over https.
83
- const originNow = () => `https://${label ? label + '.' : ''}localhost:${port}`;
84
-
85
- if (already) {
86
- console.log(`already running on port ${port}`);
87
- } else {
88
- // The handle too, not just the port: the agent seeds its allowed hosts
89
- // from agent.json, and without it the named origin this command is about
90
- // to open would be refused on the very first run.
91
- recordAgent(recordedAgent().handle ? { port } : { port, handle: path.basename(HOME) });
92
- const child = spawn(process.execPath, [new URL('../../../../run-agent.mjs', import.meta.url).pathname], {
93
- detached: true, stdio: 'ignore',
94
- env: { ...process.env, AP_HOME: HOME, AP_PORT: String(port) },
95
- });
96
- child.on('error', (e) => { console.error(`could not start the agent: ${e.message}`); process.exit(1); });
97
- child.unref();
98
- // Wait for it to answer before pointing a browser at it, or the first
99
- // load races the listen and shows a connection error.
100
- let up = false;
101
- for (let i = 0; i < 60 && !up; i++) {
102
- await new Promise(r => setTimeout(r, 250));
103
- up = !!await agentOn(port);
104
- }
105
- if (!up) {
106
- console.error(`the agent did not come up on port ${port} — see ${path.join(HOME, 'agent.log')}`);
107
- process.exit(1);
108
- }
109
- console.log(`agent running on port ${port} (pid in ${path.join(HOME, 'agent.pid')})`);
110
- if (port !== preferred) console.log(`port ${preferred} was taken, so it moved to ${port}`);
111
- }
112
- // The client pinned to this actor, not the bare root — root serves vendored
113
- // Phanpy with no account bound, which reads as the wrong app entirely.
114
- const url = configured ? `${originNow()}/admin/client/` : `${originNow()}/admin/setup/`;
115
- console.log(`\n ${url}\n`);
116
- console.log(configured ? 'stop it with: fedipod stop'
117
- : 'setup continues in the browser. Stop it with: fedipod stop');
118
- if (!has('no-open')) openBrowser(url);
119
- process.exit(0);
120
- }
121
-
122
- export async function start() {
123
- requireIdentity();
124
- // Starting one is what makes it the default — so `--profile group start`
125
- // today is what a plain command means tomorrow. Recorded before the agent
126
- // comes up, because a start that fails still expressed the intent.
127
- if (rootOf(HOME) === AP_ROOT) recordLastUsed(AP_ROOT, path.basename(HOME));
128
- // This flag is read only by setup; it silently did nothing here, while the
129
- // key guard's own error message told people to use it.
130
- if (has('rotate-key')) {
131
- console.error('start does not rotate keys — use: fedipod rotate-key');
132
- process.exit(2);
133
- }
134
- if (portFlag()) recordAgent({ port: PORT }); // `start --port N` (or bare N) moves it for good
135
-
136
- // Something already on the port? Offer to take it over rather than dying
137
- // with "address in use" and leaving the user to hunt the process down.
138
- const answering = await localFetch(HOME, PORT, `/status`)
139
- .then(r => r.status).catch(() => null);
140
- if (answering !== null) {
141
- const pidFile = path.join(HOME, 'agent.pid');
142
- let pid = null;
143
- try { pid = Number(fs.readFileSync(pidFile, 'utf8').trim()) || null; } catch {}
144
- const who = pid ? `pid ${pid}` : 'started elsewhere';
145
- if (!has('replace') && !process.stdin.isTTY) {
146
- console.error(`an agent is already running on port ${PORT} (${who}).`);
147
- console.error('Stop it with `fedipod stop`, or start this one with --replace.');
148
- process.exit(1);
149
- }
150
- const ans = has('replace')
151
- ? 'y'
152
- : await ask(`an agent is already running on port ${PORT} (${who}) — stop it and start this one? (y/n)`, 'y');
153
- endAsking();
154
- if (!/^y/i.test(ans)) { console.log('left the running agent alone'); process.exit(0); }
155
-
156
- await localFetch(HOME, PORT, `/shutdown`, { method: 'POST' }).catch(() => {});
157
- if (pid) { try { process.kill(pid, 'SIGTERM'); } catch {} }
158
- const freed = await (async () => { // give it a few seconds
159
- for (let i = 0; i < 30; i++) {
160
- await new Promise(r => setTimeout(r, 300));
161
- const still = await localFetch(HOME, PORT, `/status`).then(() => true).catch(() => false);
162
- if (!still) return true;
163
- }
164
- return false;
165
- })();
166
- if (!freed && pid) { try { process.kill(pid, 'SIGKILL'); } catch {} await new Promise(r => setTimeout(r, 500)); }
167
- const clear = await localFetch(HOME, PORT, `/status`).then(() => false).catch(() => true);
168
- if (!clear) {
169
- console.error(`could not stop whatever is on port ${PORT}. Find it with: ss -tlnp | grep :${PORT}`);
170
- process.exit(1);
171
- }
172
- console.log('previous agent stopped');
173
- }
174
-
175
- const { startAgent } = await import(new URL('../../../../run-agent.mjs', import.meta.url));
176
- const startHandle = recordedAgent().handle || null;
177
- await startAgent({
178
- home: HOME, port: PORT, name: flag('name') || null,
179
- takeover: has('takeover'), // claim a lease whose holder is gone
180
- handle: startHandle, // the named origin, before pod state is read
181
- });
182
- {
183
- const { hostLabel } = await import(new URL('../../../../lib/shared/guard.mjs', import.meta.url));
184
- const label = hostLabel(startHandle);
185
- const named = label ? `https://${label}.localhost:${PORT}/` : null;
186
- const plain = `https://localhost:${PORT}/`;
187
- // One origin per identity is the point of the named form: a browser keeps
188
- // its storage per origin, so two agents stop sharing one Phanpy login.
189
- if (named) {
190
- const pad = Math.max(named.length, plain.length);
191
- console.log(`\n ${named.padEnd(pad)} <- browse it here`);
192
- console.log(` ${plain.padEnd(pad)} <- the same agent, if that name will not resolve\n`);
193
- } else {
194
- console.log(`\n ${plain}\n`);
195
- }
196
- // Printed, not opened. `start` is run by supervisors and on every restart;
197
- // a window arriving unasked over whatever you were doing is not a feature.
198
- // `setup` opens one because that is the whole point of `setup`.
199
- if (has('open')) openBrowser(named || plain);
200
- }
201
- }
202
-
203
- export async function stop() {
204
- requireIdentity();
205
- const pidFile = path.join(HOME, 'agent.pid');
206
- let pid = null;
207
- try { pid = Number(fs.readFileSync(pidFile, 'utf8').trim()); } catch {}
208
- if (!pid) {
209
- // The agent may still be listening even with no pidfile — an older
210
- // build, a deleted file, or one started detached from any terminal
211
- // (where Ctrl-C can never reach it). Ask it to stop over the API.
212
- const asked = await localFetch(HOME, PORT, `/shutdown`, { method: 'POST' })
213
- .then(r => r.ok).catch(() => false);
214
- if (asked) { console.log(`agent on port ${PORT} asked to stop`); process.exit(0); }
215
- console.error(`no agent found: no pidfile at ${pidFile}, nothing answering on port ${PORT}.`);
216
- console.error('If it is on another port, add --port N; a service install stops with:');
217
- console.error(' systemctl --user stop fedipod-<name>');
218
- process.exit(1);
219
- }
220
- try { process.kill(pid, 'SIGTERM'); } catch {
221
- // Stale pidfile, but something may still hold the port.
222
- const asked = await localFetch(HOME, PORT, `/shutdown`, { method: 'POST' })
223
- .then(r => r.ok).catch(() => false);
224
- fs.rmSync(pidFile, { force: true });
225
- console.log(asked ? `agent on port ${PORT} asked to stop (pidfile was stale)` : 'agent was not running (stale pidfile)');
226
- process.exit(0);
227
- }
228
- const t0 = Date.now();
229
- while (Date.now() - t0 < 10_000) {
230
- await new Promise(r => setTimeout(r, 300));
231
- try { process.kill(pid, 0); } catch { console.log('agent stopped'); process.exit(0); }
232
- }
233
- console.error('agent did not exit within 10s — kill it with: kill -9 ' + pid);
234
- process.exit(1);
235
- }
236
-
237
- export async function status() {
238
- requireIdentity();
239
- try {
240
- const res = await localFetch(HOME, PORT, `/status`);
241
- console.log(JSON.stringify(await res.json(), null, 2));
242
- } catch (e) {
243
- console.error(`agent not reachable on :${PORT} (${e.message})`);
244
- process.exit(1);
245
- }
246
- }
247
-
248
- export async function https() {
249
- // Agents serve https beside http with a certificate minted on this machine
250
- // (never packaged — a shipped key would be one key for every install).
251
- // Plain: self-signed, a client may ask once. --trust: a local CA signs it,
252
- // and the CA certificate is what a trust store accepts — for clients that
253
- // refuse self-signed outright.
254
- const { ensureLocalTls, enableTrust, certPaths } = await import(new URL('../../../../lib/device/certs.mjs', import.meta.url));
255
- const certDir = path.join(rootOf(HOME), 'certs'); // same resolution the agent uses
256
- if (has('trust')) {
257
- const t = enableTrust(certDir, { log: console.log }); // mints, signs, installs in NSS
258
- console.log(`CA certificate: ${t.caCertPath}`);
259
- if (process.platform === 'linux') {
260
- console.log('for the system store, run:');
261
- console.log(` sudo cp ${t.caCertPath} /usr/local/share/ca-certificates/fedipod-local-ca.crt && sudo update-ca-certificates`);
262
- } else if (process.platform === 'darwin') {
263
- console.log('to trust it system-wide, run:');
264
- console.log(` sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ${t.caCertPath}`);
265
- } else if (process.platform === 'win32') {
266
- console.log('to trust it, run:');
267
- console.log(` certutil -addstore -user Root "${t.caCertPath}"`);
268
- }
269
- console.log('restart your agents to serve the CA-signed certificate');
270
- } else {
271
- const tls = ensureLocalTls(certDir, { log: console.log });
272
- const paths2 = certPaths(certDir);
273
- console.log(`certificate: ${paths2.cert}`);
274
- console.log(` ${tls.trust ? 'signed by the local CA' : 'self-signed'}, ${tls.expiresInDays} days left`);
275
- console.log('agents serve https on the port they were given — e.g. https://localhost:8030');
276
- console.log('strict clients: `fedipod https --trust` mints a local CA your trust store can accept');
277
- }
278
- }
@@ -1,221 +0,0 @@
1
- // service.mjs — the machine's service manager and the update: update,
2
- // install-service, uninstall-service.
3
-
4
- import fs from 'node:fs';
5
- import os from 'node:os';
6
- import path from 'node:path';
7
- import { identityHomes } from '../../home.mjs';
8
- import { portFree } from '../../ports.mjs';
9
- import { localFetch } from '../../../client/localapi.mjs';
10
- import { cmd, has, AP_ROOT, HOME, agentOn } from '../context.mjs';
11
-
12
- export async function update() {
13
- // Pull the latest published FediPod into this checkout and restart the
14
- // agents — what re-running the installer does, as one command.
15
- const { checkLatest, runUpdate, restartAgents } = await import(new URL('../../../../lib/device/update.mjs', import.meta.url));
16
- const u = await checkLatest();
17
- if (u && !u.available) console.log(`already current: ${u.current}`);
18
- const r = runUpdate({ log: console.log });
19
- if (!r.ok) { console.error(r.note); process.exit(1); }
20
- console.log(r.note);
21
- if (restartAgents({ log: console.log }) === 'self') {
22
- console.log('no managed agents found — restart any running agent to serve the new version');
23
- }
24
- process.exit(0);
25
- }
26
-
27
- export async function service() {
28
- const { execFileSync } = await import('node:child_process');
29
- const runAgentPath = new URL('../../../../run-agent.mjs', import.meta.url).pathname;
30
- const sh = (file, a) => { try { execFileSync(file, a, { stdio: 'pipe' }); return true; } catch { return false; } };
31
- // Every identity with a credential gets a service of its own: a stopped
32
- // actor's pod goes on collecting deliveries, so "installed" means ALL of
33
- // them start at boot, each on its recorded port.
34
- const identities = [];
35
- for (const { name, dir } of identityHomes(AP_ROOT)) {
36
- if (!fs.existsSync(path.join(dir, 'credential.json'))) continue;
37
- let rec = {};
38
- try { rec = JSON.parse(fs.readFileSync(path.join(dir, 'agent.json'), 'utf8')) || {}; } catch { /* no record yet */ }
39
- if (!Number(rec.port)) {
40
- console.log(`${name}: no recorded port — start it once (\`up --profile ${name}\`), then re-run install-service`);
41
- continue;
42
- }
43
- identities.push({ name, dir, port: Number(rec.port), handle: rec.handle || name });
44
- }
45
- if (cmd === 'install-service' && !identities.length) {
46
- console.error('no identities with a credential and a recorded port — nothing to install');
47
- process.exit(2);
48
- }
49
- // Graceful handover: an identity already running outside the service is
50
- // stopped through its own /shutdown so the unit can take the port.
51
- const handOver = async ({ name, port }) => {
52
- if (!await agentOn(port)) return;
53
- await localFetch(HOME, port, `/shutdown`, { method: 'POST' }).catch(() => {});
54
- for (let i = 0; i < 20 && !await portFree(port); i++) await new Promise(r => setTimeout(r, 250));
55
- console.log(`${name}: was running detached — stopped for the service to take over`);
56
- };
57
-
58
- if (process.platform === 'linux') {
59
- const unitDir = path.join(os.homedir(), '.config/systemd/user');
60
- const unitOf = (name) => `fedipod-${name}.service`;
61
- // Old shapes are cleared on both paths: units under the pre-rename names
62
- // (activitypod, solid-activitypub), single-identity units, and any
63
- // per-identity unit for an identity that no longer exists here.
64
- const dropOld = () => {
65
- const keep = new Set(cmd === 'install-service' ? identities.map(i => unitOf(i.name)) : []);
66
- let units = [];
67
- try { units = fs.readdirSync(unitDir).filter(u => /^(activitypod|solid-activitypub|fedipod)(-.+)?\.service$/.test(u)); } catch { /* no unit dir */ }
68
- for (const u of units) {
69
- if (keep.has(u)) continue;
70
- sh('systemctl', ['--user', 'disable', '--now', u]);
71
- fs.rmSync(path.join(unitDir, u), { force: true });
72
- console.log(`removed ${u}`);
73
- }
74
- };
75
- if (cmd === 'uninstall-service') {
76
- dropOld();
77
- sh('systemctl', ['--user', 'daemon-reload']);
78
- console.log('service(s) removed');
79
- } else {
80
- fs.mkdirSync(unitDir, { recursive: true });
81
- dropOld();
82
- for (const id of identities) {
83
- fs.writeFileSync(path.join(unitDir, unitOf(id.name)), `[Unit]
84
- Description=FediPod agent — ${id.handle}
85
- After=network-online.target
86
-
87
- [Service]
88
- ExecStart=${process.execPath} ${runAgentPath}
89
- Environment=AP_HOME=${id.dir}
90
- Environment=AP_PORT=${id.port}
91
- Restart=on-failure
92
- RestartSec=30
93
- # A crash loop must not become a request loop against the pod.
94
- StartLimitIntervalSec=600
95
- StartLimitBurst=5
96
-
97
- [Install]
98
- WantedBy=default.target
99
- `);
100
- }
101
- sh('systemctl', ['--user', 'daemon-reload']);
102
- sh('loginctl', ['enable-linger', os.userInfo().username]); // keep running while logged out
103
- for (const id of identities) {
104
- sh('systemctl', ['--user', 'enable', unitOf(id.name)]);
105
- await handOver(id);
106
- if (await portFree(id.port)) {
107
- sh('systemctl', ['--user', 'start', unitOf(id.name)]);
108
- console.log(`${id.handle}: installed, enabled and started on port ${id.port}`);
109
- } else {
110
- console.log(`${id.handle}: installed + enabled (starts at next boot). Port ${id.port} is held by something that is not ours — free it, then: systemctl --user start ${unitOf(id.name)}`);
111
- }
112
- }
113
- console.log('logs: journalctl --user -u fedipod-<name> -f');
114
- }
115
- } else if (process.platform === 'darwin') {
116
- const agents = path.join(os.homedir(), 'Library/LaunchAgents');
117
- const plistOf = (name) => path.join(agents, `net.fedipod.${name}.agent.plist`);
118
- // Old shapes are cleared on both paths: plists under the pre-rename names
119
- // (net.activitypod, net.solid-activitypub), single-identity plists, and any
120
- // per-identity plist for an identity that no longer exists here.
121
- const dropOld = () => {
122
- const keep = new Set(cmd === 'install-service' ? identities.map(i => plistOf(i.name)) : []);
123
- let plists = [];
124
- try {
125
- plists = fs.readdirSync(agents)
126
- .filter(f => /^net\.(activitypod|solid-activitypub|fedipod)(\..+)?\.agent\.plist$/.test(f))
127
- .map(f => path.join(agents, f));
128
- } catch { /* no LaunchAgents dir */ }
129
- for (const p of plists) {
130
- if (keep.has(p)) continue;
131
- sh('launchctl', ['unload', p]);
132
- fs.rmSync(p, { force: true });
133
- console.log(`removed ${path.basename(p)}`);
134
- }
135
- };
136
- if (cmd === 'uninstall-service') {
137
- dropOld();
138
- console.log('service(s) removed');
139
- } else {
140
- fs.mkdirSync(agents, { recursive: true });
141
- dropOld();
142
- for (const id of identities) {
143
- const plist = plistOf(id.name);
144
- sh('launchctl', ['unload', plist]); // replacing our own older copy
145
- fs.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?>
146
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
147
- <plist version="1.0"><dict>
148
- <key>Label</key><string>net.fedipod.${id.name}.agent</string>
149
- <key>ProgramArguments</key><array>
150
- <string>${process.execPath}</string><string>${runAgentPath}</string>
151
- </array>
152
- <key>EnvironmentVariables</key><dict>
153
- <key>AP_HOME</key><string>${id.dir}</string>
154
- <key>AP_PORT</key><string>${id.port}</string>
155
- </dict>
156
- <key>RunAtLoad</key><true/>
157
- <key>KeepAlive</key><dict><key>SuccessfulExit</key><false/></dict>
158
- <key>ThrottleInterval</key><integer>30</integer>
159
- </dict></plist>
160
- `);
161
- await handOver(id);
162
- sh('launchctl', ['load', plist]);
163
- console.log(`${id.handle}: installed and loaded (starts at login)`);
164
- }
165
- }
166
- } else if (process.platform === 'win32') {
167
- // schtasks is scriptable, but this path is UNTESTED here (no Windows
168
- // machine); the equivalent command is printed either way so a failure
169
- // is actionable rather than mysterious.
170
- const taskOf = (name) => `fedipod-${name}`;
171
- // Pre-rename names, single-identity and per-identity, cleared on both paths.
172
- const dropOld = () => {
173
- sh('schtasks', ['/delete', '/tn', 'activitypod', '/f']);
174
- sh('schtasks', ['/delete', '/tn', 'solid-activitypub', '/f']);
175
- for (const id of identities) sh('schtasks', ['/delete', '/tn', `solid-activitypub-${id.name}`, '/f']);
176
- };
177
- if (cmd === 'uninstall-service') {
178
- dropOld();
179
- for (const id of identities) sh('schtasks', ['/delete', '/tn', taskOf(id.name), '/f']);
180
- console.log('scheduled task(s) removed');
181
- } else {
182
- dropOld();
183
- for (const id of identities) {
184
- const tr = `"${process.execPath}" "${runAgentPath}"`;
185
- const made = sh('schtasks', ['/create', '/tn', taskOf(id.name), '/tr', tr, '/sc', 'onlogon', '/rl', 'limited', '/f']);
186
- if (made) {
187
- console.log(`${id.handle}: scheduled task created — starts at log on (untested on Windows; please report)`);
188
- console.log(` set AP_HOME=${id.dir} and AP_PORT=${id.port} in the task's environment`);
189
- } else {
190
- console.log(`${id.handle}: could not create the task automatically. Run this in an elevated prompt:`);
191
- console.log(` schtasks /create /tn ${taskOf(id.name)} /tr ${tr} /sc onlogon /rl limited /f`);
192
- console.log(` with AP_HOME=${id.dir} AP_PORT=${id.port}.`);
193
- }
194
- }
195
- }
196
- } else if (process.platform === 'android' || process.env.PREFIX?.includes('com.termux')) {
197
- // Android has no user service manager: running at boot needs the
198
- // separate termux-boot app, supervision needs the termux-services
199
- // package. Neither can be installed from here, so print the recipe.
200
- // The agent is designed for this: whatever Android kills, the pod
201
- // buffered, and the next start catches up.
202
- if (cmd === 'uninstall-service') {
203
- console.log('Termux: remove ~/.termux/boot/fedipod.sh (solid-activitypub.sh or activitypod.sh on an older install, and `sv-disable` the matching service if you used termux-services).');
204
- } else {
205
- const boot = path.join(os.homedir(), '.termux/boot');
206
- console.log('Android/Termux has no service manager. To start at boot:');
207
- console.log(' 1. install the Termux:Boot app (F-Droid), open it once');
208
- console.log(` 2. mkdir -p ${boot} && cat > ${boot}/fedipod.sh <<'EOF'`);
209
- console.log('#!/data/data/com.termux/files/usr/bin/sh');
210
- console.log('termux-wake-lock');
211
- for (const id of identities) console.log(`AP_HOME=${id.dir} AP_PORT=${id.port} ${process.execPath} ${runAgentPath} &`);
212
- console.log('EOF');
213
- console.log(` 3. chmod +x ${boot}/fedipod.sh`);
214
- console.log('\nWithout Termux:Boot, run `termux-wake-lock` then `fedipod run` —');
215
- console.log('anything Android kills is buffered on the pod and catches up next start.');
216
- }
217
- } else {
218
- console.log(`no service integration for platform "${process.platform}". Run each yourself with:`);
219
- for (const id of identities) console.log(` AP_HOME=${id.dir} AP_PORT=${id.port} ${process.execPath} ${runAgentPath}`);
220
- }
221
- }