fedipod 0.18.0 → 1.0.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 (324) hide show
  1. package/README.md +105 -115
  2. package/architecture.md +41 -0
  3. package/bin/fedipod.mjs +3 -5
  4. package/browser.svg +72 -0
  5. package/cli.md +9 -0
  6. package/gateway.md +160 -0
  7. package/groups.md +7 -2
  8. package/gui.md +11 -1
  9. package/installed-agent.md +97 -0
  10. package/lib/admin.mjs +3 -3
  11. package/lib/deliver.mjs +6 -0
  12. package/lib/export-collections.mjs +1 -1
  13. package/lib/front-core.mjs +272 -49
  14. package/lib/gateway-core.mjs +3 -7
  15. package/lib/httpsig.mjs +33 -2
  16. package/lib/import.mjs +1 -1
  17. package/lib/intake.mjs +335 -118
  18. package/lib/links.mjs +6 -32
  19. package/lib/mastoapi.mjs +372 -35
  20. package/lib/migrate.mjs +4 -18
  21. package/lib/pod/README.md +61 -0
  22. package/lib/pod/actor.mjs +96 -0
  23. package/lib/pod/collection.mjs +77 -0
  24. package/lib/pod/containers.mjs +136 -0
  25. package/lib/pod/discovery.mjs +46 -0
  26. package/lib/pod/featured.mjs +18 -0
  27. package/lib/pod/followers.mjs +24 -0
  28. package/lib/pod/following.mjs +10 -0
  29. package/lib/pod/http.mjs +74 -0
  30. package/lib/pod/inbox.mjs +144 -0
  31. package/lib/pod/links.mjs +35 -0
  32. package/lib/pod/media.mjs +27 -0
  33. package/lib/pod/notes.mjs +80 -0
  34. package/lib/pod/notifications.mjs +89 -0
  35. package/lib/pod/outbox.mjs +18 -0
  36. package/lib/pod/package.json +19 -0
  37. package/lib/pod/policy.mjs +58 -0
  38. package/lib/pod/private.mjs +19 -0
  39. package/lib/pod/root.mjs +63 -0
  40. package/lib/pod/state.mjs +39 -0
  41. package/lib/pod/transport.mjs +477 -0
  42. package/lib/pod/urls.mjs +71 -0
  43. package/lib/publisher.mjs +112 -183
  44. package/lib/remote.mjs +30 -395
  45. package/lib/social.mjs +18 -9
  46. package/lib/storage.mjs +2 -2
  47. package/lib/store.mjs +8 -1
  48. package/lib/tagfeed.mjs +19 -2
  49. package/lib/wire.mjs +48 -67
  50. package/package.json +14 -3
  51. package/run-agent.mjs +14 -39
  52. package/scripts/build-app.mjs +64 -0
  53. package/scripts/check-pod-calls.mjs +177 -0
  54. package/scripts/stage-site.mjs +144 -0
  55. package/web/admin/admin.js +141 -74
  56. package/web/admin/bar.css +9 -13
  57. package/web/admin/bar.js +2 -2
  58. package/web/admin/client/client.js +1 -1
  59. package/web/admin/client/index.html +5 -6
  60. package/web/admin/index.html +53 -65
  61. package/web/admin/setup/index.html +2 -1
  62. package/web/admin/setup/setup.js +1 -1
  63. package/web/admin/tokens.css +56 -0
  64. package/web/app/README.md +77 -0
  65. package/web/app/admin-facade.mjs +549 -0
  66. package/web/app/agent.mjs +490 -0
  67. package/web/app/atproto-browser.mjs +86 -0
  68. package/web/app/boot.mjs +340 -0
  69. package/web/app/deliver-relay.mjs +72 -0
  70. package/web/app/dist/boot.js +34067 -0
  71. package/web/app/dist/boot.js.map +7 -0
  72. package/web/app/dist/sw.js +53745 -0
  73. package/web/app/dist/sw.js.map +7 -0
  74. package/web/app/fediacct-browser.mjs +146 -0
  75. package/web/app/idb-kv.mjs +35 -0
  76. package/web/app/index.html +203 -0
  77. package/web/app/index.html~ +152 -0
  78. package/web/app/keys-browser.mjs +46 -0
  79. package/web/app/keystore.mjs +99 -0
  80. package/web/app/oidc-session.mjs +189 -0
  81. package/web/app/pod-auth.mjs +248 -0
  82. package/web/app/pod-remote.mjs +84 -0
  83. package/web/app/shims/_globals.mjs +2 -0
  84. package/web/app/shims/fedify-sig.mjs +77 -0
  85. package/web/app/shims/node-crypto.mjs +113 -0
  86. package/web/app/shims/node-fs.mjs +17 -0
  87. package/web/app/shims/node-path.mjs +19 -0
  88. package/web/app/shims/node-url.mjs +7 -0
  89. package/web/app/shims/prelude.js +58 -0
  90. package/web/app/shims/safefetch.mjs +58 -0
  91. package/web/app/shims/web-push.mjs +14 -0
  92. package/web/app/signup.mjs +248 -0
  93. package/web/app/site/_headers +9 -0
  94. package/web/app/site/_redirects +21 -0
  95. package/web/app/site/admin/admin.js +1181 -0
  96. package/web/app/site/admin/bar.css +60 -0
  97. package/web/app/site/admin/bar.js +61 -0
  98. package/web/app/site/admin/client/client.js +66 -0
  99. package/web/app/site/admin/client/index.html +43 -0
  100. package/web/app/site/admin/index.html +556 -0
  101. package/web/app/site/admin/setup/index.html +191 -0
  102. package/web/app/site/admin/setup/setup.js +308 -0
  103. package/web/app/site/admin/tokens.css +56 -0
  104. package/web/app/site/admin/window.css +55 -0
  105. package/web/app/site/admin/window.js +136 -0
  106. package/web/app/site/app/404.html +40 -0
  107. package/web/app/site/app/_headers +2 -0
  108. package/web/app/site/app/apple-touch-icon.png +0 -0
  109. package/web/app/site/app/assets/ICONS-DIPJeU0C.js +2 -0
  110. package/web/app/site/app/assets/ICONS-DIPJeU0C.js.map +1 -0
  111. package/web/app/site/app/assets/ScheduledAtField-D-Abfo4J.js +183 -0
  112. package/web/app/site/app/assets/ScheduledAtField-D-Abfo4J.js.map +1 -0
  113. package/web/app/site/app/assets/Temml-CCjoacWt.woff2 +0 -0
  114. package/web/app/site/app/assets/__vite-browser-external-C7iut881.js +2 -0
  115. package/web/app/site/app/assets/__vite-browser-external-C7iut881.js.map +1 -0
  116. package/web/app/site/app/assets/boosts-carousel-BiOaNdMT.jpg +0 -0
  117. package/web/app/site/app/assets/catch-up-O5q5C75Z.png +0 -0
  118. package/web/app/site/app/assets/chunk-aKtaBQYM.js +1 -0
  119. package/web/app/site/app/assets/compose-CFEx7wb4.js +2 -0
  120. package/web/app/site/app/assets/compose-CFEx7wb4.js.map +1 -0
  121. package/web/app/site/app/assets/compose-ZJN5xSb4.js +35 -0
  122. package/web/app/site/app/assets/compose-ZJN5xSb4.js.map +1 -0
  123. package/web/app/site/app/assets/debug.module-YFQgwnIr.js +52 -0
  124. package/web/app/site/app/assets/debug.module-YFQgwnIr.js.map +1 -0
  125. package/web/app/site/app/assets/dom-p1YcJ5Rw.js +2 -0
  126. package/web/app/site/app/assets/dom-p1YcJ5Rw.js.map +1 -0
  127. package/web/app/site/app/assets/home-mobile-dark@2x-Dc-J8-SM.png +0 -0
  128. package/web/app/site/app/assets/home-mobile-light@2x-Bd3fod8m.png +0 -0
  129. package/web/app/site/app/assets/home-tablet-dark@2x-BgcNI8le.png +0 -0
  130. package/web/app/site/app/assets/home-tablet-light@2x-BW2RV9T6.png +0 -0
  131. package/web/app/site/app/assets/icons/add-circle-line-WD0mwORD.js +1 -0
  132. package/web/app/site/app/assets/icons/alert-line-CpFUMf9s.js +1 -0
  133. package/web/app/site/app/assets/icons/android-2-line-Bzxnrd3S.js +1 -0
  134. package/web/app/site/app/assets/icons/announcement-line-5nwaJFJm.js +1 -0
  135. package/web/app/site/app/assets/icons/arrow-down-circle-line-a7Id9-Iv.js +1 -0
  136. package/web/app/site/app/assets/icons/arrow-down-line-B8uzXzq6.js +1 -0
  137. package/web/app/site/app/assets/icons/arrow-left-line-CGrGT9C-.js +1 -0
  138. package/web/app/site/app/assets/icons/arrow-right-line-CE-HERfX.js +1 -0
  139. package/web/app/site/app/assets/icons/arrow-to-up-line-CvdQjmcy.js +1 -0
  140. package/web/app/site/app/assets/icons/arrow-up-circle-line-DEparSNF.js +1 -0
  141. package/web/app/site/app/assets/icons/arrow-up-line-C7yBeugc.js +1 -0
  142. package/web/app/site/app/assets/icons/arrows-right-line-BtbXmJGP.js +1 -0
  143. package/web/app/site/app/assets/icons/at-line-CF66Bznk.js +1 -0
  144. package/web/app/site/app/assets/icons/attachment-line-BY8It-l9.js +1 -0
  145. package/web/app/site/app/assets/icons/blockquote-line-BS6pU_hm.js +1 -0
  146. package/web/app/site/app/assets/icons/board-line-C0UWXyA6.js +1 -0
  147. package/web/app/site/app/assets/icons/bookmark-line-1CtX5JLF.js +1 -0
  148. package/web/app/site/app/assets/icons/building-5-line-Dd59MzbO.js +1 -0
  149. package/web/app/site/app/assets/icons/bus-2-line-6_dvA0GG.js +1 -0
  150. package/web/app/site/app/assets/icons/calendar-day-line-Crpl_fmu.js +1 -0
  151. package/web/app/site/app/assets/icons/calendar-month-line-vommts2C.js +1 -0
  152. package/web/app/site/app/assets/icons/calendar-time-add-line-BU_DTlQk.js +1 -0
  153. package/web/app/site/app/assets/icons/camera-line-Cv69MEei.js +1 -0
  154. package/web/app/site/app/assets/icons/celebrate-line-B8DvIoi0.js +1 -0
  155. package/web/app/site/app/assets/icons/chart-bar-line-FK-QOmtF.js +1 -0
  156. package/web/app/site/app/assets/icons/chart-line-line-BGcJAFWw.js +1 -0
  157. package/web/app/site/app/assets/icons/chat-3-line-YFK2-hwz.js +1 -0
  158. package/web/app/site/app/assets/icons/check-circle-line-DsAxFr5-.js +1 -0
  159. package/web/app/site/app/assets/icons/clipboard-line-BBp364gJ.js +1 -0
  160. package/web/app/site/app/assets/icons/close-circle-line-CICdiuGz.js +1 -0
  161. package/web/app/site/app/assets/icons/close-line-DYrFWcjv.js +1 -0
  162. package/web/app/site/app/assets/icons/cloud-line-tiQAbah8.js +1 -0
  163. package/web/app/site/app/assets/icons/code-line-fAl8iiV3.js +1 -0
  164. package/web/app/site/app/assets/icons/comment-2-line-CR3g7WeB.js +1 -0
  165. package/web/app/site/app/assets/icons/copy-2-line-CLW69yF5.js +1 -0
  166. package/web/app/site/app/assets/icons/delete-2-line-B8xmbr4n.js +1 -0
  167. package/web/app/site/app/assets/icons/document-3-line-DBGNhAg2.js +1 -0
  168. package/web/app/site/app/assets/icons/document-line-C7mb9sb7.js +1 -0
  169. package/web/app/site/app/assets/icons/down-line-BGqSSThd.js +1 -0
  170. package/web/app/site/app/assets/icons/edit-4-line-DcgGaEhx.js +1 -0
  171. package/web/app/site/app/assets/icons/emoji-2-line-D8YgnM-y.js +1 -0
  172. package/web/app/site/app/assets/icons/exit-line-Dc07BS-x.js +1 -0
  173. package/web/app/site/app/assets/icons/external-link-line-BvpSkmjO.js +1 -0
  174. package/web/app/site/app/assets/icons/eye-2-line-CiWXx-f_.js +1 -0
  175. package/web/app/site/app/assets/icons/eye-close-line-BgTaSJ4P.js +1 -0
  176. package/web/app/site/app/assets/icons/filter-2-line-B_mR2usy.js +1 -0
  177. package/web/app/site/app/assets/icons/filter-line-C_nm-3cU.js +1 -0
  178. package/web/app/site/app/assets/icons/flag-1-line-C2HB05I0.js +1 -0
  179. package/web/app/site/app/assets/icons/forbid-circle-line-D3LTT9yd.js +1 -0
  180. package/web/app/site/app/assets/icons/formula-line-DLrt2d6j.js +1 -0
  181. package/web/app/site/app/assets/icons/grid-line-CgUmEikf.js +1 -0
  182. package/web/app/site/app/assets/icons/group-line-C5fnX0wU.js +1 -0
  183. package/web/app/site/app/assets/icons/hand-finger-2-line-BGgxbuL9.js +1 -0
  184. package/web/app/site/app/assets/icons/hashtag-line-CyTEEXBb.js +1 -0
  185. package/web/app/site/app/assets/icons/heart-crack-line-BZddbO2C.js +1 -0
  186. package/web/app/site/app/assets/icons/heart-line-CJ7K47J4.js +1 -0
  187. package/web/app/site/app/assets/icons/history-2-line-kWWvFzqv.js +1 -0
  188. package/web/app/site/app/assets/icons/history-line-bGQiwbTH.js +1 -0
  189. package/web/app/site/app/assets/icons/home-3-line-fRU1zeLG.js +1 -0
  190. package/web/app/site/app/assets/icons/information-line-iNk6-sOY.js +1 -0
  191. package/web/app/site/app/assets/icons/keyboard-line-DsCyuQNz.js +1 -0
  192. package/web/app/site/app/assets/icons/layout-4-line-CZkOX52Z.js +1 -0
  193. package/web/app/site/app/assets/icons/layout-5-line-B_znt5wO.js +1 -0
  194. package/web/app/site/app/assets/icons/left-line-eUw0tya4.js +1 -0
  195. package/web/app/site/app/assets/icons/lightning-line-DaKoDdix.js +1 -0
  196. package/web/app/site/app/assets/icons/link-2-line-DCqLmMA7.js +1 -0
  197. package/web/app/site/app/assets/icons/list-check-line-BAxosBh9.js +1 -0
  198. package/web/app/site/app/assets/icons/lock-line-CPoaXeUW.js +1 -0
  199. package/web/app/site/app/assets/icons/mail-line-B0P8aa1L.js +1 -0
  200. package/web/app/site/app/assets/icons/moon-line-CEqNAToP.js +1 -0
  201. package/web/app/site/app/assets/icons/more-1-fill-Dw2e5xab.js +1 -0
  202. package/web/app/site/app/assets/icons/more-3-line-BIiVjYTz.js +1 -0
  203. package/web/app/site/app/assets/icons/notification-line-BZZq2Gtu.js +1 -0
  204. package/web/app/site/app/assets/icons/pencil-line-CKh8-A1v.js +1 -0
  205. package/web/app/site/app/assets/icons/photo-album-line-Bnfg2u40.js +1 -0
  206. package/web/app/site/app/assets/icons/pin-line-DpTolyhs.js +1 -0
  207. package/web/app/site/app/assets/icons/play-fill-B0-G_8lX.js +1 -0
  208. package/web/app/site/app/assets/icons/qrcode-2-line-B6SPCaHn.js +1 -0
  209. package/web/app/site/app/assets/icons/quill-pen-line-B6LUrnCP.js +1 -0
  210. package/web/app/site/app/assets/icons/quote-left-fill-hQZ1cj_6.js +1 -0
  211. package/web/app/site/app/assets/icons/radar-line-CKyroTth.js +1 -0
  212. package/web/app/site/app/assets/icons/react-line-CoIKhhtK.js +1 -0
  213. package/web/app/site/app/assets/icons/refresh-2-line-D0mTF97S.js +1 -0
  214. package/web/app/site/app/assets/icons/right-line-B3KWJaqc.js +1 -0
  215. package/web/app/site/app/assets/icons/rocket-line-4KZl537D.js +1 -0
  216. package/web/app/site/app/assets/icons/round-fill-C69NTrZ0.js +1 -0
  217. package/web/app/site/app/assets/icons/round-line-B9k_1uo-.js +1 -0
  218. package/web/app/site/app/assets/icons/route-line-B28ReHcE.js +1 -0
  219. package/web/app/site/app/assets/icons/rows-4-line-CrBniagM.js +1 -0
  220. package/web/app/site/app/assets/icons/scan-line-DSf74YdP.js +1 -0
  221. package/web/app/site/app/assets/icons/search-2-line-B6geIU1z.js +1 -0
  222. package/web/app/site/app/assets/icons/settings-3-line-azJwK47w.js +1 -0
  223. package/web/app/site/app/assets/icons/settings-6-line-C_5zc5YR.js +1 -0
  224. package/web/app/site/app/assets/icons/share-2-line-D5MxWjrm.js +1 -0
  225. package/web/app/site/app/assets/icons/share-forward-line-Cp61fZzZ.js +1 -0
  226. package/web/app/site/app/assets/icons/sparkles-2-line-DYYyXTaW.js +1 -0
  227. package/web/app/site/app/assets/icons/sparkles-line-C2hY1s6I.js +1 -0
  228. package/web/app/site/app/assets/icons/time-line-BF3eet1v.js +1 -0
  229. package/web/app/site/app/assets/icons/transfer-4-line-oisfvTBw.js +1 -0
  230. package/web/app/site/app/assets/icons/translate-line-BFWol2Ce.js +1 -0
  231. package/web/app/site/app/assets/icons/unlock-line-X_x5vwv3.js +1 -0
  232. package/web/app/site/app/assets/icons/upload-3-line-DgzwUJeW.js +1 -0
  233. package/web/app/site/app/assets/icons/user-4-line-BVSynZCp.js +1 -0
  234. package/web/app/site/app/assets/icons/user-add-2-line-BlGS5Q8q.js +1 -0
  235. package/web/app/site/app/assets/icons/user-add-line-BbXdHG4z.js +1 -0
  236. package/web/app/site/app/assets/icons/user-edit-line-BFAHOV0X.js +1 -0
  237. package/web/app/site/app/assets/icons/user-follow-line-BXux0wSd.js +1 -0
  238. package/web/app/site/app/assets/icons/user-star-line-DdYlpHLU.js +1 -0
  239. package/web/app/site/app/assets/icons/user-warning-line-Cj43j0_E.js +1 -0
  240. package/web/app/site/app/assets/icons/user-x-line-DIDgNlPH.js +1 -0
  241. package/web/app/site/app/assets/icons/volume-line-Bs390KQt.js +1 -0
  242. package/web/app/site/app/assets/icons/volume-mute-line-DzlzIqFZ.js +1 -0
  243. package/web/app/site/app/assets/icons/walk-line-yNXfB-md.js +1 -0
  244. package/web/app/site/app/assets/icons/world-2-line-CenkGIwj.js +1 -0
  245. package/web/app/site/app/assets/icons/zoom-in-line-CaENUphf.js +1 -0
  246. package/web/app/site/app/assets/icons/zoom-out-line-BDNk0EWo.js +1 -0
  247. package/web/app/site/app/assets/instances-BNPptnn-.json +333 -0
  248. package/web/app/site/app/assets/locales/ar-SA-CfheRbCu.js +1 -0
  249. package/web/app/site/app/assets/locales/ca-ES-DHRW86Tz.js +1 -0
  250. package/web/app/site/app/assets/locales/cs-CZ-CKoqEuA1.js +1 -0
  251. package/web/app/site/app/assets/locales/de-DE-ByRPMRFy.js +1 -0
  252. package/web/app/site/app/assets/locales/eo-UY-CPC7wLCS.js +1 -0
  253. package/web/app/site/app/assets/locales/es-ES-dJa0Fd9t.js +1 -0
  254. package/web/app/site/app/assets/locales/eu-ES-C3djlPR2.js +1 -0
  255. package/web/app/site/app/assets/locales/fa-IR-DTT490Ck.js +1 -0
  256. package/web/app/site/app/assets/locales/fi-FI-B23MCPuz.js +1 -0
  257. package/web/app/site/app/assets/locales/fr-FR-BcaQsO5C.js +1 -0
  258. package/web/app/site/app/assets/locales/gl-ES-BR-CVKBN.js +1 -0
  259. package/web/app/site/app/assets/locales/he-IL-CfheRbCu.js +1 -0
  260. package/web/app/site/app/assets/locales/hu-HU-CfheRbCu.js +1 -0
  261. package/web/app/site/app/assets/locales/it-IT-C1136UFV.js +1 -0
  262. package/web/app/site/app/assets/locales/ja-JP-CRZmRAhD.js +1 -0
  263. package/web/app/site/app/assets/locales/kab-Cz8xH_TT.js +1 -0
  264. package/web/app/site/app/assets/locales/ko-KR-CG9UiY4o.js +1 -0
  265. package/web/app/site/app/assets/locales/lt-LT-CJcI6sHZ.js +1 -0
  266. package/web/app/site/app/assets/locales/nb-NO-CfheRbCu.js +1 -0
  267. package/web/app/site/app/assets/locales/nl-NL-DxN4Yc1t.js +1 -0
  268. package/web/app/site/app/assets/locales/oc-FR-CfheRbCu.js +1 -0
  269. package/web/app/site/app/assets/locales/pl-PL-DkwGXf6P.js +1 -0
  270. package/web/app/site/app/assets/locales/pseudo-LOCALE-CQ4XxkQ0.js +1 -0
  271. package/web/app/site/app/assets/locales/pt-BR-nGL0HdFS.js +1 -0
  272. package/web/app/site/app/assets/locales/pt-PT-Cp17aj2z.js +1 -0
  273. package/web/app/site/app/assets/locales/ru-RU-0Y8cIoaK.js +1 -0
  274. package/web/app/site/app/assets/locales/th-TH-CfheRbCu.js +1 -0
  275. package/web/app/site/app/assets/locales/tok-CfheRbCu.js +1 -0
  276. package/web/app/site/app/assets/locales/tr-TR-CfheRbCu.js +1 -0
  277. package/web/app/site/app/assets/locales/uk-UA-C5E3dFBf.js +1 -0
  278. package/web/app/site/app/assets/locales/zh-CN-BHJi7_et.js +1 -0
  279. package/web/app/site/app/assets/locales/zh-TW-CfheRbCu.js +1 -0
  280. package/web/app/site/app/assets/main-BdqNbG-a.js +26 -0
  281. package/web/app/site/app/assets/main-BdqNbG-a.js.map +1 -0
  282. package/web/app/site/app/assets/mock-home-DGhR__He.js +2 -0
  283. package/web/app/site/app/assets/mock-home-DGhR__He.js.map +1 -0
  284. package/web/app/site/app/assets/multi-column-ROck0NVt.jpg +0 -0
  285. package/web/app/site/app/assets/multi-hashtag-timeline-DH5INVHi.jpg +0 -0
  286. package/web/app/site/app/assets/nested-comments-thread-hv59kZLc.jpg +0 -0
  287. package/web/app/site/app/assets/polyfill-force-H8sUkLGp.js +2 -0
  288. package/web/app/site/app/assets/polyfill-force-H8sUkLGp.js.map +1 -0
  289. package/web/app/site/app/assets/pwa-viewport-ogKbF51K.js +20 -0
  290. package/web/app/site/app/assets/pwa-viewport-ogKbF51K.js.map +1 -0
  291. package/web/app/site/app/assets/style-B1iLPTPR.css +2 -0
  292. package/web/app/site/app/assets/temml-DuyIQMei.js +97 -0
  293. package/web/app/site/app/assets/temml-DuyIQMei.js.map +1 -0
  294. package/web/app/site/app/assets/tinyld.light.node-DtbBhLYC.js +2 -0
  295. package/web/app/site/app/assets/tinyld.light.node-DtbBhLYC.js.map +1 -0
  296. package/web/app/site/app/assets/year-in-posts-B2lywqdx.png +0 -0
  297. package/web/app/site/app/assets/year-in-posts-DJv_star.js +3 -0
  298. package/web/app/site/app/assets/year-in-posts-DJv_star.js.map +1 -0
  299. package/web/app/site/app/compose/index.html +20 -0
  300. package/web/app/site/app/favicon.ico +0 -0
  301. package/web/app/site/app/index.html +73 -0
  302. package/web/app/site/app/logo-192.png +0 -0
  303. package/web/app/site/app/logo-512.png +0 -0
  304. package/web/app/site/app/logo-badge-72.png +0 -0
  305. package/web/app/site/app/logo-maskable-512.png +0 -0
  306. package/web/app/site/app/logo-monochrome-512.png +0 -0
  307. package/web/app/site/app/logo-monochrome-maskable-512.png +0 -0
  308. package/web/app/site/app/manifest.webmanifest +1 -0
  309. package/web/app/site/app/og-image-2.jpg +0 -0
  310. package/web/app/site/app/og-image.png +0 -0
  311. package/web/app/site/app/robots.txt +2 -0
  312. package/web/app/site/app/version.json +1 -0
  313. package/web/app/site/boot.js +34067 -0
  314. package/web/app/site/index.html +203 -0
  315. package/web/app/site/sw.js +53745 -0
  316. package/web/app/sw-src.mjs +205 -0
  317. package/web/front/#new-account.html# +43 -0
  318. package/web/front/admin.html +1 -81
  319. package/web/front/admin.js +85 -0
  320. package/web/front/new-account.html +1 -9
  321. package/web/front/new-account.js +13 -0
  322. package/web/front/run.html +1 -92
  323. package/web/front/run.js +107 -0
  324. package/lib/podrdf.mjs +0 -132
package/README.md CHANGED
@@ -2,121 +2,110 @@
2
2
 
3
3
  - access the Fediverse from a Solid pod
4
4
 
5
- `FediPod` is a merger of three federating protocols - feeds from Mastodon and other Fediverse servers and from Bluesky and other ATProto servers, with all user data stored on a Solid pod. There are four different kinds of FediPod accounts :
6
-
7
- | Kind of Account | Description | User requirements | Host requirements |
8
- |---|---|---|---|
9
- | FediPod Solo | Browse & interact with the Fediverse and ATProto from a Solid pod | an always-on pod, a usually on local agent | — |
10
- | FediPod Group | Host a discussion group of Fediverse/ATProto users from a Solid pod | an always-on pod, a usually on local agent | — |
11
- | FediPod Gateway | Solo or Group with spam filtering & optional community identity | same + gateway pass-through account | any always-on host, Netlify will do |
12
- | FediPod Server | Full ActivityPub server as a CSS component | a pod on a CSS server implementing the FediPod component | a CSS server implementing the FediPod component |
13
-
14
- ## Installation & Setup
15
-
16
- You may sign up for free for a solo, group, or gateway account at https://fedipod.net/ . Wizards will walk you through install and setup. If you want to host a community, instructions are available for [Fediverse User Group](https://github.com/jeff-zucker/FediPod/blob/main/groups.md), the lightweight [FediPod Gateway](https://github.com/jeff-zucker/FediPod/blob/main/gateway.md) and for the full CSS component [FediPod Server](https://github.com/jeff-zucker/FediPod/blob/main/packages/fedipod-server/README.md).
17
-
18
- ### Installing
19
-
20
- ```
21
- npm install -g fedipod
22
- ```
23
-
24
- Needs Node 20 or newer.
25
-
26
- ### Running the agent -
27
-
28
- Run `fedipod start`. You may optionally add a port number (`fedipod start --port 8081`) to change your local agent's port (default is 8030).
29
-
30
- Now point your browser (any) at `https://localhost:8030` — or your own port if you set one — and there you go!
31
-
32
- ### Running the agent as a service (recommended)
33
-
34
- If you don't want to run the agent each time, you can install it as a system service. This is recommended as leaving the agent off causes your mail to pile up on the pod host. To create a system service :
35
- ```
36
- fedipod install-service
37
- ```
38
- It registers every identity on this machine, one service each, so all of your actors start at boot. An identity running in a terminal is stopped and taken over by its service.
39
-
40
- `fedipod uninstall-service` reverses it.
41
-
42
- ## Managing your FediPod install
43
-
44
- You can manage your posts, see logs, park, move, transfer your account and perform other actions. See the [GUI admin](https://github.com/jeff-zucker/FediPod/blob/main/gui.md) and [CLI admin](https://github.com/jeff-zucker/FediPod/blob/main/cli.md) pages.
45
-
46
- You can also use the admin tools to create other actors, either groups or persons. You may have as many as you want on the local machine, but each one needs a separate pod.
47
-
48
- Every agent checks once a day whether a newer FediPod is published. When one
49
- exists, the record page offers **Update**, and `fedipod update`
50
- does the same from the terminal. `AP_UPDATE_CHECK=0` turns the check off.
51
-
52
- ## A FediPod.net Gateway account (reccommended)
53
-
54
- Most of what a Fediverse inbox receives is broadcast noise. A gateway is a
55
- shared, always-on door that verifies each delivery, drops the junk, and
56
- passes the rest to your pod — while your key and data stay on your own
57
- pod. There is a free gateway at [fedipod.net](https://fedipod.net/). Attaching to it or detaching from it is a few wizard-guided clicks.
58
-
59
- Users are recommended to associate with a gateway as it reduces the mail load on your pod host.
60
-
61
- ## Fediverse Clients
62
-
63
- The UI is the bundled [Phanpy](https://github.com/cheeaun/phanpy)
64
- client (MIT, by Chee Aun). It is served same-origin over the agent's Mastodon client-API facade, and logging in is one click — the instance is filled in for you. If you ever enter it by hand, use the address on the record's **local host** row.
65
-
66
- The agent federates for real: follow/unfollow, post, reply, favourite,
67
- boost, media, delete; incoming boosts from people you follow and a
68
- configurable public-hashtag feed (`POST /tagfeed`) fill the timeline.
69
- Also: editing posts, content warnings, voting in polls, all four visibility
70
- levels (followers-only and direct posts work only on a pod that enforces
71
- WAC access control — on one that doesn't, the composer refuses and says why),
72
- a conversations view for direct messages, bookmarks, favourites, lists,
73
- keyword filters, scheduled posts, pinned posts (visible from other servers),
74
- blocking and muting from the client, custom emojis, and web-push
75
- notifications that reach you while the client is closed.
76
-
77
- Polls: up to four options, one answer or several, running from five minutes to
78
- a month.
79
-
80
- ### Other clients
81
-
82
- - **Web clients**: drop any static Mastodon client dist into `ui/<name>/`
83
- and it is served at `/<name>/`, same-origin — see `ui/README.md`.
84
- - **Desktop clients** (Tuba, Whalebird, …): add `https://localhost:8030` (or other port for other agent) as a
85
- custom instance.
86
- - **Streaming**: the agent serves the Mastodon streaming API
87
- (`/api/v1/streaming`, WebSocket) so clients update live instead of polling.
88
-
89
- ## Bluesky and ATProto
90
-
91
- `FediPod` includes experimental support for ATProto. A Bluesky connection lets your `FediPod` agent drive an existing Bluesky (or other ATProto) account alongside your Fediverse identity. When you post a public post from `FediPod`, it will be cross-posted to Bluesky as a mirror (a toggle you can turn off). Private DMs from `FediPod` to Bluesky are not currently supported. Bluesky replies and activity flow into your timeline so you see, for example, a combined Bluesky and Mastodon feed. You can like, boost, and reply to Bluesky posts from within `FediPod`. None of these features require `Bridgy Fed`, however, fully joining a `FediPod` group from a Bluesky client other than `FediPod` does require a bridge.
92
-
93
- ## Your other Fediverse accounts
94
-
95
- If you also hold an account on Mastodon — or on any other server speaking the Mastodon API, such as GoToSocial, Pleroma, Akkoma, Pixelfed or Friendica — you can connect it and read it here. Its home timeline and notifications join the feed you already read, interleaved by time, and a post both accounts see appears once rather than twice. Favouriting, boosting and replying act as the account the post came through, on its own server. Connect one from the **Other identities** row of the admin page: you sign in at that server, and the token it hands back stays on this machine.
96
-
97
-
98
- ## Architecture
99
-
100
- `Activitypods` requires a server which provides both an ActivityPub server and a Solid server and thus requires a specific server setup. `FediPod Solo & FediPod Group`, can be installed on any subdomained https-served pod without any modification to the server. It does this by splitting the ActivityPub server into two parts. The pod part provides discovery (webfinger) and stores mostly public data while the local agent provides the ActivityPub actions and storage for most private data. The exception is private direct messages which are stored on the pod protected by ACL resources. The same protected area also holds followers-only posts, and the pending-follow
101
- and blocked collections. [`FediPod Gateway`](https://github.com/jeff-zucker/FediPod/blob/main/gateway.md) can be supported from any lightweight Internet-facing box including Netlify, it does not require a full server and can work with any FediPod-capable pod. [`FediPod Server`](https://github.com/jeff-zucker/FediPod/blob/main/packages/fedipod-server/README.md) works as a CSS server component. If the pod host installs it, anyone with a pod on that server can opt-in to using their pod as a FediPod account fed by the server itself.
102
-
103
- ![Fedipod Gateway flow](https://raw.githubusercontent.com/jeff-zucker/FediPod/main/architecture.svg)
104
-
105
- ### Protocol conformance
106
-
107
- FediPod is a full ActivityPub server, on both of the spec's profiles:
108
- server-to-server (§7) and client-to-server (§6) — `POST /ap/outbox` on the
109
- agent takes an activity (or a bare Note) and does the id-minting,
110
- side-effects and delivery, authenticated by a Solid-OIDC token whose WebID is
111
- the owner's. The Mastodon REST API is the everyday client interface; C2S is
112
- the spec's own.
113
-
114
- Group actors follow FEP-1b12: a carried post names the group as its
115
- `audience`, the moderator roster is published as the actor's `attributedTo`,
116
- a followed group's announced `Delete` of a post it carried is honoured, and
117
- the group's own moderation is announced to the membership. The FEP-4ccd
118
- pending-follow collections and the FEP-c648 blocked collection are published
119
- as owner-only documents. See [Groups](https://github.com/jeff-zucker/FediPod/blob/main/groups.md).
5
+ FediPod gives you a Fediverse account whose data lives on a Solid pod. You
6
+ follow people on Mastodon, Bluesky, and other Fediverse or ATProto servers in
7
+ one timeline. Your posts, followers and settings stay on your pod.
8
+
9
+ The easiest way to run FediPod is to use it in any browser at https://fedipod.net. Nothing to install. A wizard will walk you through getting a pod (you can also bring your own) and creating a Fediverse identity attached to the pod. There are also a number of [other ways to run FediPod](#other-ways-to-run-fedipod) which offer a variety of scenarios.
10
+
11
+ ## Requirements
12
+
13
+ - A current browser, on a desktop or a phone.
14
+ - A Solid pod with a host name of its own, such as
15
+ `https://alice.solidcommunity.net/`. Sign-up can create one for you at
16
+ solidcommunity.net or another provider, or use a pod you already have. A
17
+ pod that lives on a path of a shared host, like `https://server.example/alice/`,
18
+ cannot be a Fediverse address.
19
+ - Followers-only and direct posts need a pod that enforces WAC access control.
20
+ On one that does not, the composer refuses those two and says why. Public
21
+ and unlisted posts work on any pod.
22
+
23
+ ## Getting an account
24
+
25
+ 1. Open https://fedipod.net and choose **create an account**.
26
+ 2. Choose a pod: a new one at the provider you name, or a pod you already have.
27
+ 3. Choose your handle. Your address is `@handle@yourpod`. Both parts are
28
+ permanent; display name, bio and pictures are set later in the client.
29
+ 4. Enter your pod password once. It creates the account and locks your
30
+ signing key. The password is not stored.
31
+
32
+ Your account then opens in the client. To use it from another browser, go to
33
+ https://fedipod.net, enter your address, sign in at your pod, and unlock your
34
+ key with your password once on that browser.
35
+
36
+ ## What you can do
37
+
38
+ The client is [Phanpy](https://github.com/cheeaun/phanpy) (MIT, by Chee Aun),
39
+ served by fedipod.net. Through it you follow and unfollow, post, reply,
40
+ favourite, boost, attach media, edit and delete. Content warnings, polls with
41
+ up to four options and one or several answers, all four visibility levels, a
42
+ conversations view for direct messages, bookmarks, lists, keyword filters,
43
+ pinned posts that other servers can see, blocking and muting, and the custom
44
+ emojis other servers send.
45
+
46
+ **Bluesky.** Connect a Bluesky account, or any other ATProto account, from the
47
+ manage page. Your public posts are mirrored to it, Bluesky replies and
48
+ activity flow into your timeline, and you can like, repost and reply to
49
+ Bluesky posts. Direct messages to Bluesky are not supported. None of this
50
+ needs Bridgy Fed.
51
+
52
+ **Your other Fediverse accounts.** If you also hold an account on Mastodon,
53
+ or on any other server speaking the Mastodon API such as GoToSocial, Pleroma,
54
+ Akkoma, Pixelfed or Friendica, connect it from the manage page and read it
55
+ here. Its home timeline and notifications join the feed you already read,
56
+ interleaved by time, and a post both accounts see appears once. Favouriting,
57
+ boosting and replying act as the account the post came through. The token it
58
+ hands back stays in your browser unless you choose to keep it on your pod.
59
+
60
+ **Moving in.** Mastodon-format exports of follows, blocks, mutes, lists and
61
+ domain blocks import from the manage page. Your old account can be listed as
62
+ an alias, so a Move from it lands here.
63
+
64
+ **The manage page.** `manage account` in the bar opens it: your profile,
65
+ aliases, the gateway, key rotation, recovering posts, parking, moving to
66
+ another server, retiring, and clearing a backlog. It is the same interface
67
+ the installed agent has, described in [the admin interface](gui.md).
68
+
69
+ **More than one browser.** One browser runs your account at a time. Opening
70
+ it in a second browser shows your timeline read-only, and the moment you act
71
+ there it takes over; the first drops back to reading.
72
+
73
+ ## What the browser version does not do
74
+
75
+ - **Scheduled posts.** Nothing runs between now and the time you picked, so
76
+ the composer refuses one rather than dropping it later.
77
+ - **Notifications while the client is closed.** There is no push service.
78
+ Open the tab and they are there.
79
+ - **Live updates.** The client refreshes by polling.
80
+ - **Hosting a group.** Joining one works.
81
+ - **Other clients.** A phone app or desktop client has nothing on the network
82
+ to connect to.
83
+
84
+ For these, see [Other ways to run FediPod](#other-ways-to-run-fedipod).
85
+
86
+ ## Your data and your keys
87
+
88
+ Everything you publish and everything you read is stored on your pod. Your
89
+ signing key is stored there too, encrypted under your password, so nobody who
90
+ can read your pod, its host included, can post as you. fedipod.net holds no
91
+ key: it verifies incoming mail, drops the junk, forwards the rest to your pod,
92
+ and hands your browser the app. You can detach from it at any time and attach
93
+ to a gateway of your own. Your address and your data do not change.
94
+
95
+ ## Other ways to run FediPod
96
+
97
+ - [The installed agent](installed-agent.md) runs on your own machine and
98
+ adds scheduled posts, push notifications, live updates, group hosting and
99
+ the use of any Mastodon client.
100
+ - [Groups](groups.md): hosting a discussion group of Fediverse and Bluesky
101
+ users from a pod.
102
+ - [The gateway](gateway.md): running an always-on door of your own, on
103
+ Netlify or any small host.
104
+ - [FediPod Server](packages/fedipod-server/README.md): a full ActivityPub
105
+ server as a Community Solid Server component, giving every pod on the server
106
+ the option of a Fediverse account.
107
+ - [Architecture](architecture.md): how the pieces fit, and which protocols
108
+ FediPod speaks.
120
109
 
121
110
  ## Acknowledgements
122
111
 
@@ -129,3 +118,4 @@ This package was created using a heavily hectored claude.
129
118
  ## License
130
119
 
131
120
  (c) Jeff Zucker, 2026; may be freely used with an MIT license.
121
+ p
@@ -0,0 +1,41 @@
1
+ # Architecture
2
+
3
+ FediPod splits an ActivityPub server into two parts. The pod provides
4
+ discovery and stores the public record: the actor, its outbox, followers and
5
+ posts, and the inbox that receives deliveries. The agent provides the
6
+ ActivityPub actions: it drains the inbox, builds the timeline, signs and
7
+ delivers, and answers the Mastodon client. The agent runs either in your
8
+ browser, served by fedipod.net, or as [the installed agent](installed-agent.md)
9
+ on your own machine. Private direct messages, followers-only posts and the
10
+ pending-follow and blocked collections live on the pod in an area protected by
11
+ access control.
12
+
13
+ A [gateway](gateway.md) can stand in front of the pod: an always-on door that
14
+ verifies each delivery where the signature can still be checked, drops spam,
15
+ and forwards the rest to the pod inbox with a receipt. It holds no key. The
16
+ browser version always has one; the installed agent may use one. Any
17
+ lightweight host will do, Netlify included.
18
+
19
+ [FediPod Server](packages/fedipod-server/README.md) puts the agent inside a
20
+ Community Solid Server, so anyone with a pod on that server can opt in to a
21
+ Fediverse account fed by the server itself.
22
+
23
+ ![The browser version](https://raw.githubusercontent.com/jeff-zucker/FediPod/main/browser.svg)
24
+
25
+ ![The installed agent, with a gateway](https://raw.githubusercontent.com/jeff-zucker/FediPod/main/architecture.svg)
26
+
27
+ ## Protocol conformance
28
+
29
+ FediPod is a full ActivityPub server, on both of the spec's profiles:
30
+ server-to-server (§7) and client-to-server (§6). `POST /ap/outbox` on the
31
+ installed agent takes an activity, or a bare Note, and does the id-minting,
32
+ side-effects and delivery, authenticated by a Solid-OIDC token whose WebID is
33
+ the owner's. The Mastodon REST API is the everyday client interface; C2S is
34
+ the spec's own.
35
+
36
+ Group actors follow FEP-1b12: a carried post names the group as its
37
+ `audience`, the moderator roster is published as the actor's `attributedTo`,
38
+ a followed group's announced `Delete` of a post it carried is honoured, and
39
+ the group's own moderation is announced to the membership. The FEP-4ccd
40
+ pending-follow collections and the FEP-c648 blocked collection are published
41
+ as owner-only documents. See [Groups](groups.md).
package/bin/fedipod.mjs CHANGED
@@ -964,13 +964,12 @@ if (cmd === 'up') {
964
964
  let copied;
965
965
  try {
966
966
  copied = await copyPrivateHalf({
967
- from: { state: agent.privateStorage(cred, 'state'), fediverse: agent.privateStorage(cred, 'fediverse') },
968
- to: { state: agent.privateStorage(destCred, 'state'), fediverse: agent.privateStorage(destCred, 'fediverse') },
967
+ from: { state: agent.privateStorage(cred, 'state') },
968
+ to: { state: agent.privateStorage(destCred, 'state') },
969
969
  log: (...a) => console.log('[state]', ...a),
970
970
  });
971
971
  } catch (e) { console.error(e.message); process.exit(1); }
972
972
  console.log(`copied ${copied.docs} state document(s)`);
973
- console.log(`copied ${copied.notes} note(s)`);
974
973
 
975
974
  // An empty source produces an empty destination, and every check above
976
975
  // passes: nothing failed to land because nothing was sent. The command then
@@ -2071,8 +2070,7 @@ WantedBy=default.target
2071
2070
  if (res.status >= 400) { console.error(body.error || `HTTP ${res.status}`); process.exit(1); }
2072
2071
  if (body.why) { console.error(body.why); process.exit(1); }
2073
2072
  console.log(`the pod indexed ${body.indexed} post(s); recovered ${body.recovered}`
2074
- + `${body.reblogs ? `, and marked ${body.reblogs} of them boosted` : ''}`
2075
- + `${body.rdf ? ` (${body.rdf} written back to the RDF)` : ''}`);
2073
+ + `${body.reblogs ? `, and marked ${body.reblogs} of them boosted` : ''}`);
2076
2074
  if (body.dropped) console.log(`${body.dropped} fell past the 1000-status cap`);
2077
2075
  if (!body.landed) { console.error('the state write did NOT land — nothing is saved'); process.exit(1); }
2078
2076
  if (!body.recovered && !has('from-notes')) {
package/browser.svg ADDED
@@ -0,0 +1,72 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 860 486" font-family="Helvetica, Arial, sans-serif">
2
+ <defs>
3
+ <marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
4
+ <path d="M0,0 L10,5 L0,10 z" fill="#333"/>
5
+ </marker>
6
+ </defs>
7
+ <rect x="0" y="0" width="860" height="486" fill="#ffffff"/>
8
+
9
+ <!-- boxes (draw.io palette) -->
10
+ <g stroke-width="1.5">
11
+ <rect x="315" y="24" width="230" height="72" rx="6" fill="#dae8fc" stroke="#6c8ebf"/>
12
+ <rect x="315" y="190" width="230" height="68" rx="6" fill="#e1d5e7" stroke="#9673a6"/>
13
+ <rect x="40" y="372" width="210" height="70" rx="6" fill="#f8cecc" stroke="#b85450"/>
14
+ <rect x="580" y="360" width="250" height="88" rx="6" fill="#d5e8d4" stroke="#82b366"/>
15
+ </g>
16
+
17
+ <!-- box labels -->
18
+ <g fill="#111" text-anchor="middle">
19
+ <text x="430" y="56" font-size="17" font-weight="bold">Open Social Web</text>
20
+ <text x="430" y="80" font-size="13">Mastodon · Pixelfed · Bluesky …</text>
21
+
22
+ <text x="430" y="220" font-size="17" font-weight="bold">FediPod Gateway</text>
23
+ <text x="430" y="242" font-size="13">the mail door &amp; the relay</text>
24
+
25
+ <text x="145" y="391" font-size="17" font-weight="bold">Your Pod</text>
26
+ <text x="145" y="409" font-size="13">AP S2S formatted data</text>
27
+ <text x="145" y="426" font-size="13">in addition to other pod data</text>
28
+
29
+ <text x="705" y="392" font-size="17" font-weight="bold">Any Browser</text>
30
+ <text x="705" y="414" font-size="13">runs your FediPod Agent,</text>
31
+ <text x="705" y="431" font-size="13">a Mastodon API client</text>
32
+ </g>
33
+
34
+ <!-- arrows -->
35
+ <g stroke="#333" stroke-width="1.6" fill="none">
36
+ <!-- 1: Open Social Web <-> Gateway (AP S2S mail) -->
37
+ <line x1="430" y1="96" x2="430" y2="190" marker-start="url(#arrow)" marker-end="url(#arrow)"/>
38
+ <!-- 2: Your Pod -> Open Social Web (UNCHANGED, pod answers lookups) -->
39
+ <path d="M110,372 C46,300 46,150 322,92" marker-end="url(#arrow)"/>
40
+ <!-- 3: Gateway -> Your Pod (one way now) -->
41
+ <path d="M338,258 C300,300 250,330 205,372" marker-end="url(#arrow)"/>
42
+ <!-- 4: Gateway <-> Any Browser (agent loaded; signed posts sent) -->
43
+ <path d="M632,360 C560,320 522,300 472,258" marker-start="url(#arrow)" marker-end="url(#arrow)"/>
44
+ <!-- 5: Your Pod <-> Any Browser (Solid) -->
45
+ <line x1="250" y1="408" x2="580" y2="408" marker-start="url(#arrow)" marker-end="url(#arrow)"/>
46
+ <!-- 6: Any Browser <-> Open Social Web (ATProto client — Bluesky) -->
47
+ <path d="M760,360 C824,300 824,150 538,92" marker-start="url(#arrow)" marker-end="url(#arrow)"/>
48
+ </g>
49
+
50
+ <!-- arrow labels -->
51
+ <g fill="#333" font-size="13">
52
+ <text x="418" y="134" text-anchor="end">raw mail in</text>
53
+ <text x="418" y="150" text-anchor="end">relayed posts out</text>
54
+ <text x="442" y="142" text-anchor="start">AP S2S Protocol</text>
55
+
56
+ <text x="96" y="250" text-anchor="start">Pod responds to requests for</text>
57
+ <text x="96" y="266" text-anchor="start">webfinger, actor, public posts</text>
58
+
59
+ <text x="300" y="322" text-anchor="start">verified mail in</text>
60
+
61
+ <text x="588" y="302" text-anchor="middle">FediPod Agent loaded in browser;</text>
62
+ <text x="588" y="318" text-anchor="middle">signed posts sent to gateway</text>
63
+
64
+ <text x="430" y="400" text-anchor="middle" font-weight="bold" fill="#111">Solid Protocol</text>
65
+ <text x="430" y="428" text-anchor="middle">reads &amp; writes your pod</text>
66
+
67
+ <text x="780" y="238" text-anchor="end">ATProto</text>
68
+ <text x="780" y="254" text-anchor="end">client protocol</text>
69
+ </g>
70
+
71
+ <text x="830" y="474" text-anchor="end" font-size="11" fill="#888">© 2026 Jeff Zucker · CC BY-SA 4.0</text>
72
+ </svg>
package/cli.md CHANGED
@@ -70,6 +70,15 @@ fedipod revoke-credential --email EMAIL # cut this machine off from the pod acc
70
70
  ```
71
71
  A new password takes effect when a running agent restarts.
72
72
 
73
+ **A client hosted somewhere else now needs one.** A client running on its own
74
+ site (Elk, Phanpy on someone's own domain) asks the agent to send the sign-in
75
+ result back to that site. Without a password there is nothing to approve that
76
+ with — and the agent used to do it anyway, which meant any page you happened
77
+ to have open could ask for the same thing and be given a key to your account.
78
+ So: no password, no sending credentials off this machine. Clients that live on
79
+ the agent itself (the bundled one, a dist in `ui/`, anything on
80
+ `https://localhost:<port>`) are unaffected and need no password.
81
+
73
82
  ## Bluesky
74
83
 
75
84
  ```
package/gateway.md ADDED
@@ -0,0 +1,160 @@
1
+ # The gateway
2
+
3
+ Most of what a Fediverse inbox receives is broadcast noise. A gateway is an
4
+ always-on, internet-facing door that stands in front of your pod: it checks
5
+ each delivery's signature where the headers still exist, drops forgeries and
6
+ junk before they ever touch your pod, and passes the rest on with a receipt
7
+ saying it checked.
8
+
9
+ Your name, your signing key and your data stay on your own pod. The gateway is
10
+ **keyless** — it never holds the key you sign with, so it cannot post as you,
11
+ read your private things, or be you anywhere. The worst a broken one can do is
12
+ push items into your inbox, and those still face your agent's own checks.
13
+
14
+ A FediPod install works without any gateway at all. Deliveries go straight to
15
+ your pod inbox, which holds them whether your agent is running or not.
16
+
17
+ ## Attaching your pod to one
18
+
19
+ There is a gateway at [fedipod.net](https://fedipod.net/). Attaching happens
20
+ from your own agent, which proves the pod with its own credential — no
21
+ password is typed anywhere:
22
+
23
+ 1. Open your agent's admin page and, in the **Gateway** panel, give the
24
+ gateway's address and the name you want there. The panel checks the name
25
+ is free as you type.
26
+ 2. Choose a pod-based name (`@you@your.pod`) or a gateway-based name
27
+ (`@you@the-gateway`). The gateway account is created automatically either
28
+ way. A pod-based attach applies immediately; taking a gateway-based name
29
+ restarts the agent itself to publish under it.
30
+
31
+ The same attach from the command line, against the running agent:
32
+
33
+ ```
34
+ fedipod gateway --attach https://fedipod.net --name yourname
35
+ ```
36
+
37
+ `--name` defaults to your handle; add `--fronted` for a gateway-based name.
38
+
39
+ To undo it:
40
+
41
+ ```
42
+ fedipod gateway --detach
43
+ ```
44
+
45
+ That republishes your actor with your pod's own inbox. Nothing else moves.
46
+ Detach talks to the running agent, so start it first. For a fronted identity,
47
+ detaching also moves every published id back to the pod — a rename other
48
+ servers see, not just a mail change.
49
+
50
+ ## Easing into it
51
+
52
+ Attaching does not have to change how deliveries are treated on day one. The
53
+ mode says how far you trust the door, and every step is reversible:
54
+
55
+ - **off** — configured but not advertised; nothing changes on the wire. This
56
+ is where a by-hand configure starts, and the step back short of forgetting
57
+ the gateway entirely.
58
+ - **shadow** — your actor advertises the gateway and the agent measures how
59
+ much real traffic verifies.
60
+ - **trust** — verified follows are accepted without review.
61
+ - **locked** — your inbox accepts writes only from the gateway.
62
+
63
+ In every mode past **off**, the door itself is already filtering: blocked
64
+ actors, content that does not concern you, and forged signatures are dropped
65
+ at the door and never reach the pod. The mode says only how far the agent
66
+ believes the door's receipts.
67
+
68
+ The shadow numbers come from the agent:
69
+
70
+ ```
71
+ curl -k https://localhost:8030/gateway
72
+ ```
73
+
74
+ which reports the mode and the verified and unverified counts.
75
+
76
+ Set it from the agent's own API:
77
+
78
+ ```
79
+ curl -k -X POST https://localhost:8030/gateway -H 'content-type: application/json' \
80
+ -d '{"action":"mode","mode":"shadow"}'
81
+ ```
82
+
83
+ 8030 is the default identity's port; `fedipod status`
84
+ prints the right one for each identity.
85
+
86
+ ## The receipt secret
87
+
88
+ The gateway stamps each verification receipt with a secret shared between it
89
+ and your agent, and your agent believes a receipt only when the stamp checks
90
+ out. That is what stops somebody dropping a forged "verified" receipt beside a
91
+ forged delivery.
92
+
93
+ You never fetch this secret from anywhere. When you run your own gateway,
94
+ your agent mints it and shows it to you once; you carry it to the gateway
95
+ yourself. When you attach to a multi-user gateway, the direction is reversed:
96
+ the gateway mints the secret and answers the attach with it, and your agent
97
+ records it.
98
+
99
+ ## What the gateway can see
100
+
101
+ It reads only public data to decide what concerns you: your published
102
+ followers and following, and a small public policy document your agent writes
103
+ with a mirror of your blocklist. Nothing private leaves your pod. Publishing
104
+ that mirror does make your blocklist public, which is part of the bargain of
105
+ running behind a door.
106
+
107
+ ## Running a gateway
108
+
109
+ Any always-on box will do — a VPS, a home server behind a tunnel, a serverless
110
+ host. The logic is plain Node in `lib/gateway-core.mjs`, and a host needs only
111
+ a thin adapter that calls `handleDelivery`.
112
+
113
+ Two ways are ready to use:
114
+
115
+ - **On Netlify**, with the adapter in `netlify/functions/inbox.mjs`. See
116
+ [netlify/README.md](netlify/README.md) for the deployment specifics.
117
+ - **On any box of your own**, with your own adapter around the same core.
118
+ - **Inside a Community Solid Server**, as the same door run in-process by the
119
+ CSS component — see [packages/fedipod-server](packages/fedipod-server/README.md).
120
+
121
+ ### Offering accounts to other people
122
+
123
+ A gateway can also be a front for many people, so a host can offer
124
+ `@name@their-host` addresses. Each user keeps their own pod, their own agent
125
+ and their own signing key; the front answers WebFinger for all of them, serves
126
+ each public face by rewriting that user's pod ids onto the shared domain, and
127
+ routes every verified delivery into the right pod.
128
+
129
+ A fronted identity is the gateway-based name choice in the admin page's
130
+ Gateway panel, or:
131
+
132
+ ```
133
+ fedipod gateway --attach <front-origin> --name <name> --fronted
134
+ ```
135
+
136
+ Choose at attach time: changing an existing identity's front later renames
137
+ every published id, and the attach refuses it.
138
+
139
+ **A front is only a doorway.** It never hosts pods and never dictates where
140
+ they live. A host who also wants to offer pods to people who have none runs a
141
+ pod server separately, with the duties that carries — and users may always
142
+ bring a pod of their own instead.
143
+
144
+ ## Setting one up by hand
145
+
146
+ If you are not using a signup page:
147
+
148
+ 1. Deploy the door to your box.
149
+ 2. Give it Append on your inbox, using a dedicated low-privilege pod account —
150
+ never your owner credential. FediPod's default inbox is public-Append, so
151
+ this is optional: with no credential the door writes with a plain PUT.
152
+ 3. Point your agent at it, which mints the shared secret and returns it once:
153
+
154
+ ```
155
+ curl -k -X POST https://localhost:8030/gateway -H 'content-type: application/json' \
156
+ -d '{"action":"configure","url":"<door-inbox-url>","webId":"<door-webid>"}'
157
+ ```
158
+
159
+ Copy that secret into the door's environment.
160
+ 4. Walk the modes above, starting at shadow.
package/groups.md CHANGED
@@ -14,6 +14,13 @@ and pick group rather than person, or take the group path on a signup page.
14
14
  You can turn on join review as you create it. The group's pod must be the root
15
15
  of its own host, so its handle resolves.
16
16
 
17
+ **Running a group needs the installed agent.** The in-browser build makes
18
+ personal identities only — the sign-up wizard has no group option, and the
19
+ moderation surface (join review, members, muting, the moderation queue) is not
20
+ part of that build. You can *join* a group from the browser exactly as from
21
+ anywhere else: joining is following, and that works everywhere. It is hosting
22
+ one that needs an install.
23
+
17
24
  Being in a group also connects you to the people in it: posts from fellow
18
25
  members reach your timeline even when you do not follow them individually,
19
26
  so a reply in the room is something you see rather than something filed
@@ -62,8 +69,6 @@ boosting the author.
62
69
 
63
70
  A group can be handed on rather than abandoned using the `Transfer this account away` button. This tells every follower to migrate, so the membership survives a change of host.
64
71
 
65
-
66
-
67
72
  ## Bluesky members
68
73
 
69
74
  A group with a connected Bluesky account is joinable from Bluesky: following
package/gui.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # The Admin interface
2
2
 
3
+ In the browser version at fedipod.net, `manage account` in the bar opens this
4
+ same page for your account. The rest of this page describes it as the
5
+ installed agent serves it; the controls are the same, minus the manual inbox
6
+ drain and the local log, which a browser does not have.
7
+
3
8
  Open `https://localhost:8030/` while any agent is running — it forwards you to the agent — then choose `manage account` and select the actor you want from the local actors dropdown.
4
9
  Picking an actor marked "(stopped)" starts its agent, then opens its page.
5
10
 
@@ -91,7 +96,10 @@ is marked **sign in again** rather than quietly dropped.
91
96
  ## Handling follow requests
92
97
 
93
98
  New followers appear under **Follow requests** with **Accept** and **Refuse**
94
- beside them; nothing is accepted without you. Groups are different — joining
99
+ beside them; nothing is accepted without you.
100
+ They show in any Mastodon client as well, now that the client API serves the
101
+ queue and takes both answers.
102
+ Groups are different — joining
95
103
  follows the group's own moderation settings; see [Groups](groups.md).
96
104
 
97
105
  **Accept all** answers the whole queue at once, and the identity pane's
@@ -123,6 +131,8 @@ account*); your followers arrive by themselves. Removing an alias asks
123
131
  twice — servers still processing the move check it while they retry. The CSV
124
132
  files from the old server's export are imported with the CLI; see
125
133
  [CLI admin](cli.md).
134
+ The in-browser build runs the same importer, so a CSV can be handed to it
135
+ there too.
126
136
 
127
137
  ## Protecting & recovering your data
128
138