fedipod-server 0.29.0 → 0.31.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 (444) hide show
  1. package/README.md +16 -6
  2. package/dist/claims.d.ts +2 -0
  3. package/dist/claims.js +13 -4
  4. package/dist/door.d.ts +4 -0
  5. package/dist/door.js +31 -0
  6. package/dist/fedipod.d.ts +15 -0
  7. package/dist/fedipod.js +13 -0
  8. package/dist/front.d.ts +3 -0
  9. package/dist/front.js +92 -0
  10. package/dist/handler.d.ts +36 -101
  11. package/dist/handler.js +93 -644
  12. package/dist/handler.jsonld +2 -30
  13. package/dist/identities.d.ts +71 -0
  14. package/dist/identities.js +236 -0
  15. package/dist/mounts.d.ts +43 -0
  16. package/dist/mounts.js +123 -0
  17. package/dist/opt-in.d.ts +46 -0
  18. package/dist/opt-in.js +176 -0
  19. package/dist/private-read.d.ts +4 -0
  20. package/dist/private-read.js +34 -0
  21. package/package.json +12 -20
  22. package/lib/client/c2s.mjs +0 -636
  23. package/lib/client/localapi.mjs +0 -87
  24. package/lib/client/masto/accounts.mjs +0 -310
  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 -387
  65. package/lib/core/graphview.mjs +0 -327
  66. package/lib/core/intake/activities.mjs +0 -649
  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 -258
  70. package/lib/core/intake/index.mjs +0 -732
  71. package/lib/core/intake/notes.mjs +0 -367
  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/place.mjs +0 -82
  76. package/lib/core/polls.mjs +0 -105
  77. package/lib/core/profile-page.mjs +0 -104
  78. package/lib/core/proof.mjs +0 -79
  79. package/lib/core/publisher/collections.mjs +0 -272
  80. package/lib/core/publisher/index.mjs +0 -522
  81. package/lib/core/publisher/notes.mjs +0 -519
  82. package/lib/core/publisher/own.mjs +0 -143
  83. package/lib/core/publisher/questions.mjs +0 -241
  84. package/lib/core/publisher/restore.mjs +0 -224
  85. package/lib/core/shapes/activitystreams.ttl +0 -157
  86. package/lib/core/shapes/index.mjs +0 -132
  87. package/lib/core/shapes/shapes-text.mjs +0 -13
  88. package/lib/core/social.mjs +0 -561
  89. package/lib/core/storage.mjs +0 -176
  90. package/lib/core/store.mjs +0 -578
  91. package/lib/core/wire-quotes.mjs +0 -71
  92. package/lib/core/wire.mjs +0 -925
  93. package/lib/device/account.mjs +0 -87
  94. package/lib/device/admin/index.mjs +0 -13
  95. package/lib/device/admin/origins.mjs +0 -35
  96. package/lib/device/admin/routes/connections.mjs +0 -144
  97. package/lib/device/admin/routes/gateway.mjs +0 -199
  98. package/lib/device/admin/routes/lifecycle.mjs +0 -200
  99. package/lib/device/admin/routes/owner.mjs +0 -322
  100. package/lib/device/admin/routes/setup.mjs +0 -428
  101. package/lib/device/admin/routes/social.mjs +0 -188
  102. package/lib/device/admin/server.mjs +0 -95
  103. package/lib/device/admin/static.mjs +0 -247
  104. package/lib/device/admin/surface.mjs +0 -315
  105. package/lib/device/certs.mjs +0 -281
  106. package/lib/device/cli/commands/account.mjs +0 -586
  107. package/lib/device/cli/commands/run.mjs +0 -278
  108. package/lib/device/cli/commands/service.mjs +0 -221
  109. package/lib/device/cli/commands/setup.mjs +0 -489
  110. package/lib/device/cli/commands/state.mjs +0 -561
  111. package/lib/device/cli/context.mjs +0 -288
  112. package/lib/device/export-collections.mjs +0 -161
  113. package/lib/device/gateway-move.mjs +0 -58
  114. package/lib/device/home.mjs +0 -161
  115. package/lib/device/migrate.mjs +0 -115
  116. package/lib/device/ports.mjs +0 -27
  117. package/lib/device/remote.mjs +0 -54
  118. package/lib/device/setup.mjs +0 -496
  119. package/lib/device/update.mjs +0 -96
  120. package/lib/gateway/caches.mjs +0 -36
  121. package/lib/gateway/directory.mjs +0 -90
  122. package/lib/gateway/front-core.mjs +0 -966
  123. package/lib/gateway/gateway-core.mjs +0 -244
  124. package/lib/gateway/headers.mjs +0 -49
  125. package/lib/gateway/httpsig.mjs +0 -159
  126. package/lib/gateway/notices.mjs +0 -84
  127. package/lib/gateway/quiet.mjs +0 -189
  128. package/lib/gateway/relay-extras.mjs +0 -89
  129. package/lib/gateway/token-claims.mjs +0 -16
  130. package/lib/pod/README.md +0 -61
  131. package/lib/pod/actor.mjs +0 -96
  132. package/lib/pod/collection.mjs +0 -77
  133. package/lib/pod/containers.mjs +0 -140
  134. package/lib/pod/discovery.mjs +0 -46
  135. package/lib/pod/featured.mjs +0 -18
  136. package/lib/pod/followers.mjs +0 -24
  137. package/lib/pod/following.mjs +0 -10
  138. package/lib/pod/http.mjs +0 -74
  139. package/lib/pod/inbox.mjs +0 -166
  140. package/lib/pod/links.mjs +0 -35
  141. package/lib/pod/location.mjs +0 -52
  142. package/lib/pod/media.mjs +0 -27
  143. package/lib/pod/notes.mjs +0 -78
  144. package/lib/pod/notifications.mjs +0 -89
  145. package/lib/pod/outbox.mjs +0 -18
  146. package/lib/pod/package.json +0 -19
  147. package/lib/pod/policy.mjs +0 -58
  148. package/lib/pod/private.mjs +0 -19
  149. package/lib/pod/root.mjs +0 -104
  150. package/lib/pod/state.mjs +0 -40
  151. package/lib/pod/transport.mjs +0 -674
  152. package/lib/pod/type-index.mjs +0 -101
  153. package/lib/pod/urls.mjs +0 -91
  154. package/lib/server/embed.mjs +0 -424
  155. package/lib/session/README.md +0 -137
  156. package/lib/session/demo.html +0 -94
  157. package/lib/session/fedi-account.mjs +0 -417
  158. package/lib/session/fedi-login.mjs +0 -123
  159. package/lib/session/oidc-session.mjs +0 -233
  160. package/lib/session/package.json +0 -49
  161. package/lib/shared/guard.mjs +0 -213
  162. package/lib/shared/links.mjs +0 -9
  163. package/lib/shared/safefetch.mjs +0 -235
  164. package/lib/shared/ua.mjs +0 -29
  165. package/phanpy/dist/404.html +0 -40
  166. package/phanpy/dist/_headers +0 -2
  167. package/phanpy/dist/apple-touch-icon.png +0 -0
  168. package/phanpy/dist/assets/ICONS-DIPJeU0C.js +0 -2
  169. package/phanpy/dist/assets/ICONS-DIPJeU0C.js.map +0 -1
  170. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js +0 -183
  171. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js.map +0 -1
  172. package/phanpy/dist/assets/Temml-CCjoacWt.woff2 +0 -0
  173. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js +0 -2
  174. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js.map +0 -1
  175. package/phanpy/dist/assets/boosts-carousel-BiOaNdMT.jpg +0 -0
  176. package/phanpy/dist/assets/catch-up-O5q5C75Z.png +0 -0
  177. package/phanpy/dist/assets/chunk-aKtaBQYM.js +0 -1
  178. package/phanpy/dist/assets/compose-CFEx7wb4.js +0 -2
  179. package/phanpy/dist/assets/compose-CFEx7wb4.js.map +0 -1
  180. package/phanpy/dist/assets/compose-ZJN5xSb4.js +0 -35
  181. package/phanpy/dist/assets/compose-ZJN5xSb4.js.map +0 -1
  182. package/phanpy/dist/assets/debug.module-YFQgwnIr.js +0 -52
  183. package/phanpy/dist/assets/debug.module-YFQgwnIr.js.map +0 -1
  184. package/phanpy/dist/assets/dom-p1YcJ5Rw.js +0 -2
  185. package/phanpy/dist/assets/dom-p1YcJ5Rw.js.map +0 -1
  186. package/phanpy/dist/assets/home-mobile-dark@2x-Dc-J8-SM.png +0 -0
  187. package/phanpy/dist/assets/home-mobile-light@2x-Bd3fod8m.png +0 -0
  188. package/phanpy/dist/assets/home-tablet-dark@2x-BgcNI8le.png +0 -0
  189. package/phanpy/dist/assets/home-tablet-light@2x-BW2RV9T6.png +0 -0
  190. package/phanpy/dist/assets/icons/add-circle-line-WD0mwORD.js +0 -1
  191. package/phanpy/dist/assets/icons/alert-line-CpFUMf9s.js +0 -1
  192. package/phanpy/dist/assets/icons/android-2-line-Bzxnrd3S.js +0 -1
  193. package/phanpy/dist/assets/icons/announcement-line-5nwaJFJm.js +0 -1
  194. package/phanpy/dist/assets/icons/arrow-down-circle-line-a7Id9-Iv.js +0 -1
  195. package/phanpy/dist/assets/icons/arrow-down-line-B8uzXzq6.js +0 -1
  196. package/phanpy/dist/assets/icons/arrow-left-line-CGrGT9C-.js +0 -1
  197. package/phanpy/dist/assets/icons/arrow-right-line-CE-HERfX.js +0 -1
  198. package/phanpy/dist/assets/icons/arrow-to-up-line-CvdQjmcy.js +0 -1
  199. package/phanpy/dist/assets/icons/arrow-up-circle-line-DEparSNF.js +0 -1
  200. package/phanpy/dist/assets/icons/arrow-up-line-C7yBeugc.js +0 -1
  201. package/phanpy/dist/assets/icons/arrows-right-line-BtbXmJGP.js +0 -1
  202. package/phanpy/dist/assets/icons/at-line-CF66Bznk.js +0 -1
  203. package/phanpy/dist/assets/icons/attachment-line-BY8It-l9.js +0 -1
  204. package/phanpy/dist/assets/icons/blockquote-line-BS6pU_hm.js +0 -1
  205. package/phanpy/dist/assets/icons/board-line-C0UWXyA6.js +0 -1
  206. package/phanpy/dist/assets/icons/bookmark-line-1CtX5JLF.js +0 -1
  207. package/phanpy/dist/assets/icons/building-5-line-Dd59MzbO.js +0 -1
  208. package/phanpy/dist/assets/icons/bus-2-line-6_dvA0GG.js +0 -1
  209. package/phanpy/dist/assets/icons/calendar-day-line-Crpl_fmu.js +0 -1
  210. package/phanpy/dist/assets/icons/calendar-month-line-vommts2C.js +0 -1
  211. package/phanpy/dist/assets/icons/calendar-time-add-line-BU_DTlQk.js +0 -1
  212. package/phanpy/dist/assets/icons/camera-line-Cv69MEei.js +0 -1
  213. package/phanpy/dist/assets/icons/celebrate-line-B8DvIoi0.js +0 -1
  214. package/phanpy/dist/assets/icons/chart-bar-line-FK-QOmtF.js +0 -1
  215. package/phanpy/dist/assets/icons/chart-line-line-BGcJAFWw.js +0 -1
  216. package/phanpy/dist/assets/icons/chat-3-line-YFK2-hwz.js +0 -1
  217. package/phanpy/dist/assets/icons/check-circle-line-DsAxFr5-.js +0 -1
  218. package/phanpy/dist/assets/icons/clipboard-line-BBp364gJ.js +0 -1
  219. package/phanpy/dist/assets/icons/close-circle-line-CICdiuGz.js +0 -1
  220. package/phanpy/dist/assets/icons/close-line-DYrFWcjv.js +0 -1
  221. package/phanpy/dist/assets/icons/cloud-line-tiQAbah8.js +0 -1
  222. package/phanpy/dist/assets/icons/code-line-fAl8iiV3.js +0 -1
  223. package/phanpy/dist/assets/icons/comment-2-line-CR3g7WeB.js +0 -1
  224. package/phanpy/dist/assets/icons/copy-2-line-CLW69yF5.js +0 -1
  225. package/phanpy/dist/assets/icons/delete-2-line-B8xmbr4n.js +0 -1
  226. package/phanpy/dist/assets/icons/document-3-line-DBGNhAg2.js +0 -1
  227. package/phanpy/dist/assets/icons/document-line-C7mb9sb7.js +0 -1
  228. package/phanpy/dist/assets/icons/down-line-BGqSSThd.js +0 -1
  229. package/phanpy/dist/assets/icons/edit-4-line-DcgGaEhx.js +0 -1
  230. package/phanpy/dist/assets/icons/emoji-2-line-D8YgnM-y.js +0 -1
  231. package/phanpy/dist/assets/icons/exit-line-Dc07BS-x.js +0 -1
  232. package/phanpy/dist/assets/icons/external-link-line-BvpSkmjO.js +0 -1
  233. package/phanpy/dist/assets/icons/eye-2-line-CiWXx-f_.js +0 -1
  234. package/phanpy/dist/assets/icons/eye-close-line-BgTaSJ4P.js +0 -1
  235. package/phanpy/dist/assets/icons/filter-2-line-B_mR2usy.js +0 -1
  236. package/phanpy/dist/assets/icons/filter-line-C_nm-3cU.js +0 -1
  237. package/phanpy/dist/assets/icons/flag-1-line-C2HB05I0.js +0 -1
  238. package/phanpy/dist/assets/icons/forbid-circle-line-D3LTT9yd.js +0 -1
  239. package/phanpy/dist/assets/icons/formula-line-DLrt2d6j.js +0 -1
  240. package/phanpy/dist/assets/icons/grid-line-CgUmEikf.js +0 -1
  241. package/phanpy/dist/assets/icons/group-line-C5fnX0wU.js +0 -1
  242. package/phanpy/dist/assets/icons/hand-finger-2-line-BGgxbuL9.js +0 -1
  243. package/phanpy/dist/assets/icons/hashtag-line-CyTEEXBb.js +0 -1
  244. package/phanpy/dist/assets/icons/heart-crack-line-BZddbO2C.js +0 -1
  245. package/phanpy/dist/assets/icons/heart-line-CJ7K47J4.js +0 -1
  246. package/phanpy/dist/assets/icons/history-2-line-kWWvFzqv.js +0 -1
  247. package/phanpy/dist/assets/icons/history-line-bGQiwbTH.js +0 -1
  248. package/phanpy/dist/assets/icons/home-3-line-fRU1zeLG.js +0 -1
  249. package/phanpy/dist/assets/icons/information-line-iNk6-sOY.js +0 -1
  250. package/phanpy/dist/assets/icons/keyboard-line-DsCyuQNz.js +0 -1
  251. package/phanpy/dist/assets/icons/layout-4-line-CZkOX52Z.js +0 -1
  252. package/phanpy/dist/assets/icons/layout-5-line-B_znt5wO.js +0 -1
  253. package/phanpy/dist/assets/icons/left-line-eUw0tya4.js +0 -1
  254. package/phanpy/dist/assets/icons/lightning-line-DaKoDdix.js +0 -1
  255. package/phanpy/dist/assets/icons/link-2-line-DCqLmMA7.js +0 -1
  256. package/phanpy/dist/assets/icons/list-check-line-BAxosBh9.js +0 -1
  257. package/phanpy/dist/assets/icons/lock-line-CPoaXeUW.js +0 -1
  258. package/phanpy/dist/assets/icons/mail-line-B0P8aa1L.js +0 -1
  259. package/phanpy/dist/assets/icons/moon-line-CEqNAToP.js +0 -1
  260. package/phanpy/dist/assets/icons/more-1-fill-Dw2e5xab.js +0 -1
  261. package/phanpy/dist/assets/icons/more-3-line-BIiVjYTz.js +0 -1
  262. package/phanpy/dist/assets/icons/notification-line-BZZq2Gtu.js +0 -1
  263. package/phanpy/dist/assets/icons/pencil-line-CKh8-A1v.js +0 -1
  264. package/phanpy/dist/assets/icons/photo-album-line-Bnfg2u40.js +0 -1
  265. package/phanpy/dist/assets/icons/pin-line-DpTolyhs.js +0 -1
  266. package/phanpy/dist/assets/icons/play-fill-B0-G_8lX.js +0 -1
  267. package/phanpy/dist/assets/icons/qrcode-2-line-B6SPCaHn.js +0 -1
  268. package/phanpy/dist/assets/icons/quill-pen-line-B6LUrnCP.js +0 -1
  269. package/phanpy/dist/assets/icons/quote-left-fill-hQZ1cj_6.js +0 -1
  270. package/phanpy/dist/assets/icons/radar-line-CKyroTth.js +0 -1
  271. package/phanpy/dist/assets/icons/react-line-CoIKhhtK.js +0 -1
  272. package/phanpy/dist/assets/icons/refresh-2-line-D0mTF97S.js +0 -1
  273. package/phanpy/dist/assets/icons/right-line-B3KWJaqc.js +0 -1
  274. package/phanpy/dist/assets/icons/rocket-line-4KZl537D.js +0 -1
  275. package/phanpy/dist/assets/icons/round-fill-C69NTrZ0.js +0 -1
  276. package/phanpy/dist/assets/icons/round-line-B9k_1uo-.js +0 -1
  277. package/phanpy/dist/assets/icons/route-line-B28ReHcE.js +0 -1
  278. package/phanpy/dist/assets/icons/rows-4-line-CrBniagM.js +0 -1
  279. package/phanpy/dist/assets/icons/scan-line-DSf74YdP.js +0 -1
  280. package/phanpy/dist/assets/icons/search-2-line-B6geIU1z.js +0 -1
  281. package/phanpy/dist/assets/icons/settings-3-line-azJwK47w.js +0 -1
  282. package/phanpy/dist/assets/icons/settings-6-line-C_5zc5YR.js +0 -1
  283. package/phanpy/dist/assets/icons/share-2-line-D5MxWjrm.js +0 -1
  284. package/phanpy/dist/assets/icons/share-forward-line-Cp61fZzZ.js +0 -1
  285. package/phanpy/dist/assets/icons/sparkles-2-line-DYYyXTaW.js +0 -1
  286. package/phanpy/dist/assets/icons/sparkles-line-C2hY1s6I.js +0 -1
  287. package/phanpy/dist/assets/icons/time-line-BF3eet1v.js +0 -1
  288. package/phanpy/dist/assets/icons/transfer-4-line-oisfvTBw.js +0 -1
  289. package/phanpy/dist/assets/icons/translate-line-BFWol2Ce.js +0 -1
  290. package/phanpy/dist/assets/icons/unlock-line-X_x5vwv3.js +0 -1
  291. package/phanpy/dist/assets/icons/upload-3-line-DgzwUJeW.js +0 -1
  292. package/phanpy/dist/assets/icons/user-4-line-BVSynZCp.js +0 -1
  293. package/phanpy/dist/assets/icons/user-add-2-line-BlGS5Q8q.js +0 -1
  294. package/phanpy/dist/assets/icons/user-add-line-BbXdHG4z.js +0 -1
  295. package/phanpy/dist/assets/icons/user-edit-line-BFAHOV0X.js +0 -1
  296. package/phanpy/dist/assets/icons/user-follow-line-BXux0wSd.js +0 -1
  297. package/phanpy/dist/assets/icons/user-star-line-DdYlpHLU.js +0 -1
  298. package/phanpy/dist/assets/icons/user-warning-line-Cj43j0_E.js +0 -1
  299. package/phanpy/dist/assets/icons/user-x-line-DIDgNlPH.js +0 -1
  300. package/phanpy/dist/assets/icons/volume-line-Bs390KQt.js +0 -1
  301. package/phanpy/dist/assets/icons/volume-mute-line-DzlzIqFZ.js +0 -1
  302. package/phanpy/dist/assets/icons/walk-line-yNXfB-md.js +0 -1
  303. package/phanpy/dist/assets/icons/world-2-line-CenkGIwj.js +0 -1
  304. package/phanpy/dist/assets/icons/zoom-in-line-CaENUphf.js +0 -1
  305. package/phanpy/dist/assets/icons/zoom-out-line-BDNk0EWo.js +0 -1
  306. package/phanpy/dist/assets/instances-BNPptnn-.json +0 -333
  307. package/phanpy/dist/assets/locales/ar-SA-CfheRbCu.js +0 -1
  308. package/phanpy/dist/assets/locales/ca-ES-DHRW86Tz.js +0 -1
  309. package/phanpy/dist/assets/locales/cs-CZ-CKoqEuA1.js +0 -1
  310. package/phanpy/dist/assets/locales/de-DE-ByRPMRFy.js +0 -1
  311. package/phanpy/dist/assets/locales/eo-UY-CPC7wLCS.js +0 -1
  312. package/phanpy/dist/assets/locales/es-ES-dJa0Fd9t.js +0 -1
  313. package/phanpy/dist/assets/locales/eu-ES-C3djlPR2.js +0 -1
  314. package/phanpy/dist/assets/locales/fa-IR-DTT490Ck.js +0 -1
  315. package/phanpy/dist/assets/locales/fi-FI-B23MCPuz.js +0 -1
  316. package/phanpy/dist/assets/locales/fr-FR-BcaQsO5C.js +0 -1
  317. package/phanpy/dist/assets/locales/gl-ES-BR-CVKBN.js +0 -1
  318. package/phanpy/dist/assets/locales/he-IL-CfheRbCu.js +0 -1
  319. package/phanpy/dist/assets/locales/hu-HU-CfheRbCu.js +0 -1
  320. package/phanpy/dist/assets/locales/it-IT-C1136UFV.js +0 -1
  321. package/phanpy/dist/assets/locales/ja-JP-CRZmRAhD.js +0 -1
  322. package/phanpy/dist/assets/locales/kab-Cz8xH_TT.js +0 -1
  323. package/phanpy/dist/assets/locales/ko-KR-CG9UiY4o.js +0 -1
  324. package/phanpy/dist/assets/locales/lt-LT-CJcI6sHZ.js +0 -1
  325. package/phanpy/dist/assets/locales/nb-NO-CfheRbCu.js +0 -1
  326. package/phanpy/dist/assets/locales/nl-NL-DxN4Yc1t.js +0 -1
  327. package/phanpy/dist/assets/locales/oc-FR-CfheRbCu.js +0 -1
  328. package/phanpy/dist/assets/locales/pl-PL-DkwGXf6P.js +0 -1
  329. package/phanpy/dist/assets/locales/pseudo-LOCALE-CQ4XxkQ0.js +0 -1
  330. package/phanpy/dist/assets/locales/pt-BR-nGL0HdFS.js +0 -1
  331. package/phanpy/dist/assets/locales/pt-PT-Cp17aj2z.js +0 -1
  332. package/phanpy/dist/assets/locales/ru-RU-0Y8cIoaK.js +0 -1
  333. package/phanpy/dist/assets/locales/th-TH-CfheRbCu.js +0 -1
  334. package/phanpy/dist/assets/locales/tok-CfheRbCu.js +0 -1
  335. package/phanpy/dist/assets/locales/tr-TR-CfheRbCu.js +0 -1
  336. package/phanpy/dist/assets/locales/uk-UA-C5E3dFBf.js +0 -1
  337. package/phanpy/dist/assets/locales/zh-CN-BHJi7_et.js +0 -1
  338. package/phanpy/dist/assets/locales/zh-TW-CfheRbCu.js +0 -1
  339. package/phanpy/dist/assets/main-BdqNbG-a.js +0 -26
  340. package/phanpy/dist/assets/main-BdqNbG-a.js.map +0 -1
  341. package/phanpy/dist/assets/mock-home-DGhR__He.js +0 -2
  342. package/phanpy/dist/assets/mock-home-DGhR__He.js.map +0 -1
  343. package/phanpy/dist/assets/multi-column-ROck0NVt.jpg +0 -0
  344. package/phanpy/dist/assets/multi-hashtag-timeline-DH5INVHi.jpg +0 -0
  345. package/phanpy/dist/assets/nested-comments-thread-hv59kZLc.jpg +0 -0
  346. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js +0 -2
  347. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js.map +0 -1
  348. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js +0 -20
  349. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js.map +0 -1
  350. package/phanpy/dist/assets/style-B1iLPTPR.css +0 -2
  351. package/phanpy/dist/assets/temml-DuyIQMei.js +0 -97
  352. package/phanpy/dist/assets/temml-DuyIQMei.js.map +0 -1
  353. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js +0 -2
  354. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js.map +0 -1
  355. package/phanpy/dist/assets/year-in-posts-B2lywqdx.png +0 -0
  356. package/phanpy/dist/assets/year-in-posts-DJv_star.js +0 -3
  357. package/phanpy/dist/assets/year-in-posts-DJv_star.js.map +0 -1
  358. package/phanpy/dist/compose/index.html +0 -20
  359. package/phanpy/dist/favicon.ico +0 -0
  360. package/phanpy/dist/index.html +0 -73
  361. package/phanpy/dist/logo-192.png +0 -0
  362. package/phanpy/dist/logo-512.png +0 -0
  363. package/phanpy/dist/logo-badge-72.png +0 -0
  364. package/phanpy/dist/logo-maskable-512.png +0 -0
  365. package/phanpy/dist/logo-monochrome-512.png +0 -0
  366. package/phanpy/dist/logo-monochrome-maskable-512.png +0 -0
  367. package/phanpy/dist/manifest.webmanifest +0 -1
  368. package/phanpy/dist/og-image-2.jpg +0 -0
  369. package/phanpy/dist/og-image.png +0 -0
  370. package/phanpy/dist/robots.txt +0 -2
  371. package/phanpy/dist/sw.js +0 -2
  372. package/phanpy/dist/sw.js.map +0 -1
  373. package/phanpy/dist/version.json +0 -1
  374. package/run-agent.mjs +0 -899
  375. package/vendor/gate.cjs +0 -138
  376. package/vendor/idp-grant.cjs +0 -394
  377. package/vendor/jfetch.cjs +0 -16
  378. package/web/admin/actors.js +0 -147
  379. package/web/admin/bar.css +0 -126
  380. package/web/admin/bar.js +0 -99
  381. package/web/admin/client/client.js +0 -66
  382. package/web/admin/client/index.html +0 -69
  383. package/web/admin/client-pick.js +0 -79
  384. package/web/admin/common.js +0 -23
  385. package/web/admin/connections.js +0 -112
  386. package/web/admin/gateway.js +0 -133
  387. package/web/admin/group.js +0 -258
  388. package/web/admin/index.html +0 -612
  389. package/web/admin/notices-bar.js +0 -90
  390. package/web/admin/oauth-signin.mjs +0 -37
  391. package/web/admin/record.js +0 -393
  392. package/web/admin/setup/index.html +0 -257
  393. package/web/admin/setup/setup.js +0 -339
  394. package/web/admin/tokens.css +0 -68
  395. package/web/admin/upkeep.js +0 -177
  396. package/web/admin/window.css +0 -55
  397. package/web/admin/window.js +0 -136
  398. package/web/app/README.md +0 -81
  399. package/web/app/admin-facade.mjs +0 -588
  400. package/web/app/agent.mjs +0 -672
  401. package/web/app/atproto-browser.mjs +0 -86
  402. package/web/app/authorize_interaction.html +0 -56
  403. package/web/app/authorize_interaction.js +0 -69
  404. package/web/app/boot.mjs +0 -616
  405. package/web/app/deliver-relay.mjs +0 -129
  406. package/web/app/dist/boot.js +0 -34562
  407. package/web/app/dist/boot.js.map +0 -7
  408. package/web/app/dist/sw.js +0 -73456
  409. package/web/app/dist/sw.js.map +0 -7
  410. package/web/app/fediacct-browser.mjs +0 -146
  411. package/web/app/gateway-move.mjs +0 -60
  412. package/web/app/idb-kv.mjs +0 -35
  413. package/web/app/index.html +0 -258
  414. package/web/app/keys-browser.mjs +0 -71
  415. package/web/app/keystore.mjs +0 -82
  416. package/web/app/oidc-session.mjs +0 -6
  417. package/web/app/pod-auth.mjs +0 -248
  418. package/web/app/pod-remote.mjs +0 -84
  419. package/web/app/shims/_globals.mjs +0 -2
  420. package/web/app/shims/fedify-sig.mjs +0 -77
  421. package/web/app/shims/node-crypto.mjs +0 -113
  422. package/web/app/shims/node-fs.mjs +0 -17
  423. package/web/app/shims/node-path.mjs +0 -19
  424. package/web/app/shims/node-url.mjs +0 -7
  425. package/web/app/shims/prelude.js +0 -58
  426. package/web/app/shims/safefetch.mjs +0 -58
  427. package/web/app/shims/shapes-text.mjs +0 -8
  428. package/web/app/shims/web-push.mjs +0 -14
  429. package/web/app/signup.mjs +0 -357
  430. package/web/app/sw-src.mjs +0 -220
  431. package/web/app/update.js +0 -70
  432. package/web/front/admin.html +0 -55
  433. package/web/front/admin.js +0 -89
  434. package/web/front/install.sh +0 -69
  435. package/web/front/new-account.html +0 -35
  436. package/web/front/new-account.js +0 -13
  437. package/web/front/notices.html +0 -69
  438. package/web/front/notices.js +0 -107
  439. package/web/front/run.html +0 -64
  440. package/web/front/run.js +0 -221
  441. package/web/front/solid-oidc-client.js +0 -6
  442. package/web/icons/forum.svg +0 -11
  443. package/web/icons/gateway.svg +0 -14
  444. 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
- }