fedipod-server 0.9.0 → 0.11.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 (319) hide show
  1. package/dist/claims.js +1 -1
  2. package/dist/handler.d.ts +1 -1
  3. package/dist/handler.js +35 -2
  4. package/dist/handler.jsonld +1 -1
  5. package/lib/admin.mjs +3 -3
  6. package/lib/c2s.mjs +27 -2
  7. package/lib/deliver.mjs +6 -0
  8. package/lib/embed.mjs +1 -0
  9. package/lib/export-collections.mjs +1 -1
  10. package/lib/front-core.mjs +272 -49
  11. package/lib/gateway-core.mjs +3 -7
  12. package/lib/httpsig.mjs +33 -2
  13. package/lib/import.mjs +1 -1
  14. package/lib/intake.mjs +357 -118
  15. package/lib/links.mjs +6 -32
  16. package/lib/mastoapi.mjs +449 -38
  17. package/lib/migrate.mjs +4 -18
  18. package/lib/pod/README.md +61 -0
  19. package/lib/pod/actor.mjs +96 -0
  20. package/lib/pod/collection.mjs +77 -0
  21. package/lib/pod/containers.mjs +136 -0
  22. package/lib/pod/discovery.mjs +46 -0
  23. package/lib/pod/featured.mjs +18 -0
  24. package/lib/pod/followers.mjs +24 -0
  25. package/lib/pod/following.mjs +10 -0
  26. package/lib/pod/http.mjs +74 -0
  27. package/lib/pod/inbox.mjs +144 -0
  28. package/lib/pod/links.mjs +35 -0
  29. package/lib/pod/media.mjs +27 -0
  30. package/lib/pod/notes.mjs +80 -0
  31. package/lib/pod/notifications.mjs +89 -0
  32. package/lib/pod/outbox.mjs +18 -0
  33. package/lib/pod/package.json +19 -0
  34. package/lib/pod/policy.mjs +58 -0
  35. package/lib/pod/private.mjs +19 -0
  36. package/lib/pod/root.mjs +63 -0
  37. package/lib/pod/state.mjs +39 -0
  38. package/lib/pod/transport.mjs +477 -0
  39. package/lib/pod/urls.mjs +71 -0
  40. package/lib/polls.mjs +105 -0
  41. package/lib/publisher.mjs +357 -188
  42. package/lib/remote.mjs +30 -395
  43. package/lib/social.mjs +20 -9
  44. package/lib/storage.mjs +2 -2
  45. package/lib/store.mjs +8 -1
  46. package/lib/tagfeed.mjs +19 -2
  47. package/lib/wire.mjs +87 -67
  48. package/package.json +1 -1
  49. package/run-agent.mjs +20 -39
  50. package/web/admin/admin.js +141 -74
  51. package/web/admin/bar.css +9 -13
  52. package/web/admin/bar.js +2 -2
  53. package/web/admin/client/client.js +1 -1
  54. package/web/admin/client/index.html +5 -6
  55. package/web/admin/index.html +53 -65
  56. package/web/admin/setup/index.html +2 -1
  57. package/web/admin/setup/setup.js +1 -1
  58. package/web/admin/tokens.css +56 -0
  59. package/web/app/README.md +77 -0
  60. package/web/app/admin-facade.mjs +549 -0
  61. package/web/app/agent.mjs +490 -0
  62. package/web/app/atproto-browser.mjs +86 -0
  63. package/web/app/boot.mjs +340 -0
  64. package/web/app/deliver-relay.mjs +72 -0
  65. package/web/app/dist/boot.js +34067 -0
  66. package/web/app/dist/boot.js.map +7 -0
  67. package/web/app/dist/sw.js +53745 -0
  68. package/web/app/dist/sw.js.map +7 -0
  69. package/web/app/fediacct-browser.mjs +146 -0
  70. package/web/app/idb-kv.mjs +35 -0
  71. package/web/app/index.html +203 -0
  72. package/web/app/index.html~ +152 -0
  73. package/web/app/keys-browser.mjs +46 -0
  74. package/web/app/keystore.mjs +99 -0
  75. package/web/app/oidc-session.mjs +189 -0
  76. package/web/app/pod-auth.mjs +248 -0
  77. package/web/app/pod-remote.mjs +84 -0
  78. package/web/app/shims/_globals.mjs +2 -0
  79. package/web/app/shims/fedify-sig.mjs +77 -0
  80. package/web/app/shims/node-crypto.mjs +113 -0
  81. package/web/app/shims/node-fs.mjs +17 -0
  82. package/web/app/shims/node-path.mjs +19 -0
  83. package/web/app/shims/node-url.mjs +7 -0
  84. package/web/app/shims/prelude.js +58 -0
  85. package/web/app/shims/safefetch.mjs +58 -0
  86. package/web/app/shims/web-push.mjs +14 -0
  87. package/web/app/signup.mjs +248 -0
  88. package/web/app/site/_headers +9 -0
  89. package/web/app/site/_redirects +21 -0
  90. package/web/app/site/admin/admin.js +1181 -0
  91. package/web/app/site/admin/bar.css +60 -0
  92. package/web/app/site/admin/bar.js +61 -0
  93. package/web/app/site/admin/client/client.js +66 -0
  94. package/web/app/site/admin/client/index.html +43 -0
  95. package/web/app/site/admin/index.html +556 -0
  96. package/web/app/site/admin/setup/index.html +191 -0
  97. package/web/app/site/admin/setup/setup.js +308 -0
  98. package/web/app/site/admin/tokens.css +56 -0
  99. package/web/app/site/admin/window.css +55 -0
  100. package/web/app/site/admin/window.js +136 -0
  101. package/web/app/site/app/404.html +40 -0
  102. package/web/app/site/app/_headers +2 -0
  103. package/web/app/site/app/apple-touch-icon.png +0 -0
  104. package/web/app/site/app/assets/ICONS-DIPJeU0C.js +2 -0
  105. package/web/app/site/app/assets/ICONS-DIPJeU0C.js.map +1 -0
  106. package/web/app/site/app/assets/ScheduledAtField-D-Abfo4J.js +183 -0
  107. package/web/app/site/app/assets/ScheduledAtField-D-Abfo4J.js.map +1 -0
  108. package/web/app/site/app/assets/Temml-CCjoacWt.woff2 +0 -0
  109. package/web/app/site/app/assets/__vite-browser-external-C7iut881.js +2 -0
  110. package/web/app/site/app/assets/__vite-browser-external-C7iut881.js.map +1 -0
  111. package/web/app/site/app/assets/boosts-carousel-BiOaNdMT.jpg +0 -0
  112. package/web/app/site/app/assets/catch-up-O5q5C75Z.png +0 -0
  113. package/web/app/site/app/assets/chunk-aKtaBQYM.js +1 -0
  114. package/web/app/site/app/assets/compose-CFEx7wb4.js +2 -0
  115. package/web/app/site/app/assets/compose-CFEx7wb4.js.map +1 -0
  116. package/web/app/site/app/assets/compose-ZJN5xSb4.js +35 -0
  117. package/web/app/site/app/assets/compose-ZJN5xSb4.js.map +1 -0
  118. package/web/app/site/app/assets/debug.module-YFQgwnIr.js +52 -0
  119. package/web/app/site/app/assets/debug.module-YFQgwnIr.js.map +1 -0
  120. package/web/app/site/app/assets/dom-p1YcJ5Rw.js +2 -0
  121. package/web/app/site/app/assets/dom-p1YcJ5Rw.js.map +1 -0
  122. package/web/app/site/app/assets/home-mobile-dark@2x-Dc-J8-SM.png +0 -0
  123. package/web/app/site/app/assets/home-mobile-light@2x-Bd3fod8m.png +0 -0
  124. package/web/app/site/app/assets/home-tablet-dark@2x-BgcNI8le.png +0 -0
  125. package/web/app/site/app/assets/home-tablet-light@2x-BW2RV9T6.png +0 -0
  126. package/web/app/site/app/assets/icons/add-circle-line-WD0mwORD.js +1 -0
  127. package/web/app/site/app/assets/icons/alert-line-CpFUMf9s.js +1 -0
  128. package/web/app/site/app/assets/icons/android-2-line-Bzxnrd3S.js +1 -0
  129. package/web/app/site/app/assets/icons/announcement-line-5nwaJFJm.js +1 -0
  130. package/web/app/site/app/assets/icons/arrow-down-circle-line-a7Id9-Iv.js +1 -0
  131. package/web/app/site/app/assets/icons/arrow-down-line-B8uzXzq6.js +1 -0
  132. package/web/app/site/app/assets/icons/arrow-left-line-CGrGT9C-.js +1 -0
  133. package/web/app/site/app/assets/icons/arrow-right-line-CE-HERfX.js +1 -0
  134. package/web/app/site/app/assets/icons/arrow-to-up-line-CvdQjmcy.js +1 -0
  135. package/web/app/site/app/assets/icons/arrow-up-circle-line-DEparSNF.js +1 -0
  136. package/web/app/site/app/assets/icons/arrow-up-line-C7yBeugc.js +1 -0
  137. package/web/app/site/app/assets/icons/arrows-right-line-BtbXmJGP.js +1 -0
  138. package/web/app/site/app/assets/icons/at-line-CF66Bznk.js +1 -0
  139. package/web/app/site/app/assets/icons/attachment-line-BY8It-l9.js +1 -0
  140. package/web/app/site/app/assets/icons/blockquote-line-BS6pU_hm.js +1 -0
  141. package/web/app/site/app/assets/icons/board-line-C0UWXyA6.js +1 -0
  142. package/web/app/site/app/assets/icons/bookmark-line-1CtX5JLF.js +1 -0
  143. package/web/app/site/app/assets/icons/building-5-line-Dd59MzbO.js +1 -0
  144. package/web/app/site/app/assets/icons/bus-2-line-6_dvA0GG.js +1 -0
  145. package/web/app/site/app/assets/icons/calendar-day-line-Crpl_fmu.js +1 -0
  146. package/web/app/site/app/assets/icons/calendar-month-line-vommts2C.js +1 -0
  147. package/web/app/site/app/assets/icons/calendar-time-add-line-BU_DTlQk.js +1 -0
  148. package/web/app/site/app/assets/icons/camera-line-Cv69MEei.js +1 -0
  149. package/web/app/site/app/assets/icons/celebrate-line-B8DvIoi0.js +1 -0
  150. package/web/app/site/app/assets/icons/chart-bar-line-FK-QOmtF.js +1 -0
  151. package/web/app/site/app/assets/icons/chart-line-line-BGcJAFWw.js +1 -0
  152. package/web/app/site/app/assets/icons/chat-3-line-YFK2-hwz.js +1 -0
  153. package/web/app/site/app/assets/icons/check-circle-line-DsAxFr5-.js +1 -0
  154. package/web/app/site/app/assets/icons/clipboard-line-BBp364gJ.js +1 -0
  155. package/web/app/site/app/assets/icons/close-circle-line-CICdiuGz.js +1 -0
  156. package/web/app/site/app/assets/icons/close-line-DYrFWcjv.js +1 -0
  157. package/web/app/site/app/assets/icons/cloud-line-tiQAbah8.js +1 -0
  158. package/web/app/site/app/assets/icons/code-line-fAl8iiV3.js +1 -0
  159. package/web/app/site/app/assets/icons/comment-2-line-CR3g7WeB.js +1 -0
  160. package/web/app/site/app/assets/icons/copy-2-line-CLW69yF5.js +1 -0
  161. package/web/app/site/app/assets/icons/delete-2-line-B8xmbr4n.js +1 -0
  162. package/web/app/site/app/assets/icons/document-3-line-DBGNhAg2.js +1 -0
  163. package/web/app/site/app/assets/icons/document-line-C7mb9sb7.js +1 -0
  164. package/web/app/site/app/assets/icons/down-line-BGqSSThd.js +1 -0
  165. package/web/app/site/app/assets/icons/edit-4-line-DcgGaEhx.js +1 -0
  166. package/web/app/site/app/assets/icons/emoji-2-line-D8YgnM-y.js +1 -0
  167. package/web/app/site/app/assets/icons/exit-line-Dc07BS-x.js +1 -0
  168. package/web/app/site/app/assets/icons/external-link-line-BvpSkmjO.js +1 -0
  169. package/web/app/site/app/assets/icons/eye-2-line-CiWXx-f_.js +1 -0
  170. package/web/app/site/app/assets/icons/eye-close-line-BgTaSJ4P.js +1 -0
  171. package/web/app/site/app/assets/icons/filter-2-line-B_mR2usy.js +1 -0
  172. package/web/app/site/app/assets/icons/filter-line-C_nm-3cU.js +1 -0
  173. package/web/app/site/app/assets/icons/flag-1-line-C2HB05I0.js +1 -0
  174. package/web/app/site/app/assets/icons/forbid-circle-line-D3LTT9yd.js +1 -0
  175. package/web/app/site/app/assets/icons/formula-line-DLrt2d6j.js +1 -0
  176. package/web/app/site/app/assets/icons/grid-line-CgUmEikf.js +1 -0
  177. package/web/app/site/app/assets/icons/group-line-C5fnX0wU.js +1 -0
  178. package/web/app/site/app/assets/icons/hand-finger-2-line-BGgxbuL9.js +1 -0
  179. package/web/app/site/app/assets/icons/hashtag-line-CyTEEXBb.js +1 -0
  180. package/web/app/site/app/assets/icons/heart-crack-line-BZddbO2C.js +1 -0
  181. package/web/app/site/app/assets/icons/heart-line-CJ7K47J4.js +1 -0
  182. package/web/app/site/app/assets/icons/history-2-line-kWWvFzqv.js +1 -0
  183. package/web/app/site/app/assets/icons/history-line-bGQiwbTH.js +1 -0
  184. package/web/app/site/app/assets/icons/home-3-line-fRU1zeLG.js +1 -0
  185. package/web/app/site/app/assets/icons/information-line-iNk6-sOY.js +1 -0
  186. package/web/app/site/app/assets/icons/keyboard-line-DsCyuQNz.js +1 -0
  187. package/web/app/site/app/assets/icons/layout-4-line-CZkOX52Z.js +1 -0
  188. package/web/app/site/app/assets/icons/layout-5-line-B_znt5wO.js +1 -0
  189. package/web/app/site/app/assets/icons/left-line-eUw0tya4.js +1 -0
  190. package/web/app/site/app/assets/icons/lightning-line-DaKoDdix.js +1 -0
  191. package/web/app/site/app/assets/icons/link-2-line-DCqLmMA7.js +1 -0
  192. package/web/app/site/app/assets/icons/list-check-line-BAxosBh9.js +1 -0
  193. package/web/app/site/app/assets/icons/lock-line-CPoaXeUW.js +1 -0
  194. package/web/app/site/app/assets/icons/mail-line-B0P8aa1L.js +1 -0
  195. package/web/app/site/app/assets/icons/moon-line-CEqNAToP.js +1 -0
  196. package/web/app/site/app/assets/icons/more-1-fill-Dw2e5xab.js +1 -0
  197. package/web/app/site/app/assets/icons/more-3-line-BIiVjYTz.js +1 -0
  198. package/web/app/site/app/assets/icons/notification-line-BZZq2Gtu.js +1 -0
  199. package/web/app/site/app/assets/icons/pencil-line-CKh8-A1v.js +1 -0
  200. package/web/app/site/app/assets/icons/photo-album-line-Bnfg2u40.js +1 -0
  201. package/web/app/site/app/assets/icons/pin-line-DpTolyhs.js +1 -0
  202. package/web/app/site/app/assets/icons/play-fill-B0-G_8lX.js +1 -0
  203. package/web/app/site/app/assets/icons/qrcode-2-line-B6SPCaHn.js +1 -0
  204. package/web/app/site/app/assets/icons/quill-pen-line-B6LUrnCP.js +1 -0
  205. package/web/app/site/app/assets/icons/quote-left-fill-hQZ1cj_6.js +1 -0
  206. package/web/app/site/app/assets/icons/radar-line-CKyroTth.js +1 -0
  207. package/web/app/site/app/assets/icons/react-line-CoIKhhtK.js +1 -0
  208. package/web/app/site/app/assets/icons/refresh-2-line-D0mTF97S.js +1 -0
  209. package/web/app/site/app/assets/icons/right-line-B3KWJaqc.js +1 -0
  210. package/web/app/site/app/assets/icons/rocket-line-4KZl537D.js +1 -0
  211. package/web/app/site/app/assets/icons/round-fill-C69NTrZ0.js +1 -0
  212. package/web/app/site/app/assets/icons/round-line-B9k_1uo-.js +1 -0
  213. package/web/app/site/app/assets/icons/route-line-B28ReHcE.js +1 -0
  214. package/web/app/site/app/assets/icons/rows-4-line-CrBniagM.js +1 -0
  215. package/web/app/site/app/assets/icons/scan-line-DSf74YdP.js +1 -0
  216. package/web/app/site/app/assets/icons/search-2-line-B6geIU1z.js +1 -0
  217. package/web/app/site/app/assets/icons/settings-3-line-azJwK47w.js +1 -0
  218. package/web/app/site/app/assets/icons/settings-6-line-C_5zc5YR.js +1 -0
  219. package/web/app/site/app/assets/icons/share-2-line-D5MxWjrm.js +1 -0
  220. package/web/app/site/app/assets/icons/share-forward-line-Cp61fZzZ.js +1 -0
  221. package/web/app/site/app/assets/icons/sparkles-2-line-DYYyXTaW.js +1 -0
  222. package/web/app/site/app/assets/icons/sparkles-line-C2hY1s6I.js +1 -0
  223. package/web/app/site/app/assets/icons/time-line-BF3eet1v.js +1 -0
  224. package/web/app/site/app/assets/icons/transfer-4-line-oisfvTBw.js +1 -0
  225. package/web/app/site/app/assets/icons/translate-line-BFWol2Ce.js +1 -0
  226. package/web/app/site/app/assets/icons/unlock-line-X_x5vwv3.js +1 -0
  227. package/web/app/site/app/assets/icons/upload-3-line-DgzwUJeW.js +1 -0
  228. package/web/app/site/app/assets/icons/user-4-line-BVSynZCp.js +1 -0
  229. package/web/app/site/app/assets/icons/user-add-2-line-BlGS5Q8q.js +1 -0
  230. package/web/app/site/app/assets/icons/user-add-line-BbXdHG4z.js +1 -0
  231. package/web/app/site/app/assets/icons/user-edit-line-BFAHOV0X.js +1 -0
  232. package/web/app/site/app/assets/icons/user-follow-line-BXux0wSd.js +1 -0
  233. package/web/app/site/app/assets/icons/user-star-line-DdYlpHLU.js +1 -0
  234. package/web/app/site/app/assets/icons/user-warning-line-Cj43j0_E.js +1 -0
  235. package/web/app/site/app/assets/icons/user-x-line-DIDgNlPH.js +1 -0
  236. package/web/app/site/app/assets/icons/volume-line-Bs390KQt.js +1 -0
  237. package/web/app/site/app/assets/icons/volume-mute-line-DzlzIqFZ.js +1 -0
  238. package/web/app/site/app/assets/icons/walk-line-yNXfB-md.js +1 -0
  239. package/web/app/site/app/assets/icons/world-2-line-CenkGIwj.js +1 -0
  240. package/web/app/site/app/assets/icons/zoom-in-line-CaENUphf.js +1 -0
  241. package/web/app/site/app/assets/icons/zoom-out-line-BDNk0EWo.js +1 -0
  242. package/web/app/site/app/assets/instances-BNPptnn-.json +333 -0
  243. package/web/app/site/app/assets/locales/ar-SA-CfheRbCu.js +1 -0
  244. package/web/app/site/app/assets/locales/ca-ES-DHRW86Tz.js +1 -0
  245. package/web/app/site/app/assets/locales/cs-CZ-CKoqEuA1.js +1 -0
  246. package/web/app/site/app/assets/locales/de-DE-ByRPMRFy.js +1 -0
  247. package/web/app/site/app/assets/locales/eo-UY-CPC7wLCS.js +1 -0
  248. package/web/app/site/app/assets/locales/es-ES-dJa0Fd9t.js +1 -0
  249. package/web/app/site/app/assets/locales/eu-ES-C3djlPR2.js +1 -0
  250. package/web/app/site/app/assets/locales/fa-IR-DTT490Ck.js +1 -0
  251. package/web/app/site/app/assets/locales/fi-FI-B23MCPuz.js +1 -0
  252. package/web/app/site/app/assets/locales/fr-FR-BcaQsO5C.js +1 -0
  253. package/web/app/site/app/assets/locales/gl-ES-BR-CVKBN.js +1 -0
  254. package/web/app/site/app/assets/locales/he-IL-CfheRbCu.js +1 -0
  255. package/web/app/site/app/assets/locales/hu-HU-CfheRbCu.js +1 -0
  256. package/web/app/site/app/assets/locales/it-IT-C1136UFV.js +1 -0
  257. package/web/app/site/app/assets/locales/ja-JP-CRZmRAhD.js +1 -0
  258. package/web/app/site/app/assets/locales/kab-Cz8xH_TT.js +1 -0
  259. package/web/app/site/app/assets/locales/ko-KR-CG9UiY4o.js +1 -0
  260. package/web/app/site/app/assets/locales/lt-LT-CJcI6sHZ.js +1 -0
  261. package/web/app/site/app/assets/locales/nb-NO-CfheRbCu.js +1 -0
  262. package/web/app/site/app/assets/locales/nl-NL-DxN4Yc1t.js +1 -0
  263. package/web/app/site/app/assets/locales/oc-FR-CfheRbCu.js +1 -0
  264. package/web/app/site/app/assets/locales/pl-PL-DkwGXf6P.js +1 -0
  265. package/web/app/site/app/assets/locales/pseudo-LOCALE-CQ4XxkQ0.js +1 -0
  266. package/web/app/site/app/assets/locales/pt-BR-nGL0HdFS.js +1 -0
  267. package/web/app/site/app/assets/locales/pt-PT-Cp17aj2z.js +1 -0
  268. package/web/app/site/app/assets/locales/ru-RU-0Y8cIoaK.js +1 -0
  269. package/web/app/site/app/assets/locales/th-TH-CfheRbCu.js +1 -0
  270. package/web/app/site/app/assets/locales/tok-CfheRbCu.js +1 -0
  271. package/web/app/site/app/assets/locales/tr-TR-CfheRbCu.js +1 -0
  272. package/web/app/site/app/assets/locales/uk-UA-C5E3dFBf.js +1 -0
  273. package/web/app/site/app/assets/locales/zh-CN-BHJi7_et.js +1 -0
  274. package/web/app/site/app/assets/locales/zh-TW-CfheRbCu.js +1 -0
  275. package/web/app/site/app/assets/main-BdqNbG-a.js +26 -0
  276. package/web/app/site/app/assets/main-BdqNbG-a.js.map +1 -0
  277. package/web/app/site/app/assets/mock-home-DGhR__He.js +2 -0
  278. package/web/app/site/app/assets/mock-home-DGhR__He.js.map +1 -0
  279. package/web/app/site/app/assets/multi-column-ROck0NVt.jpg +0 -0
  280. package/web/app/site/app/assets/multi-hashtag-timeline-DH5INVHi.jpg +0 -0
  281. package/web/app/site/app/assets/nested-comments-thread-hv59kZLc.jpg +0 -0
  282. package/web/app/site/app/assets/polyfill-force-H8sUkLGp.js +2 -0
  283. package/web/app/site/app/assets/polyfill-force-H8sUkLGp.js.map +1 -0
  284. package/web/app/site/app/assets/pwa-viewport-ogKbF51K.js +20 -0
  285. package/web/app/site/app/assets/pwa-viewport-ogKbF51K.js.map +1 -0
  286. package/web/app/site/app/assets/style-B1iLPTPR.css +2 -0
  287. package/web/app/site/app/assets/temml-DuyIQMei.js +97 -0
  288. package/web/app/site/app/assets/temml-DuyIQMei.js.map +1 -0
  289. package/web/app/site/app/assets/tinyld.light.node-DtbBhLYC.js +2 -0
  290. package/web/app/site/app/assets/tinyld.light.node-DtbBhLYC.js.map +1 -0
  291. package/web/app/site/app/assets/year-in-posts-B2lywqdx.png +0 -0
  292. package/web/app/site/app/assets/year-in-posts-DJv_star.js +3 -0
  293. package/web/app/site/app/assets/year-in-posts-DJv_star.js.map +1 -0
  294. package/web/app/site/app/compose/index.html +20 -0
  295. package/web/app/site/app/favicon.ico +0 -0
  296. package/web/app/site/app/index.html +73 -0
  297. package/web/app/site/app/logo-192.png +0 -0
  298. package/web/app/site/app/logo-512.png +0 -0
  299. package/web/app/site/app/logo-badge-72.png +0 -0
  300. package/web/app/site/app/logo-maskable-512.png +0 -0
  301. package/web/app/site/app/logo-monochrome-512.png +0 -0
  302. package/web/app/site/app/logo-monochrome-maskable-512.png +0 -0
  303. package/web/app/site/app/manifest.webmanifest +1 -0
  304. package/web/app/site/app/og-image-2.jpg +0 -0
  305. package/web/app/site/app/og-image.png +0 -0
  306. package/web/app/site/app/robots.txt +2 -0
  307. package/web/app/site/app/version.json +1 -0
  308. package/web/app/site/boot.js +34067 -0
  309. package/web/app/site/index.html +203 -0
  310. package/web/app/site/sw.js +53745 -0
  311. package/web/app/sw-src.mjs +205 -0
  312. package/web/front/#new-account.html# +43 -0
  313. package/web/front/admin.html +1 -81
  314. package/web/front/admin.js +85 -0
  315. package/web/front/new-account.html +1 -9
  316. package/web/front/new-account.js +13 -0
  317. package/web/front/run.html +1 -92
  318. package/web/front/run.js +107 -0
  319. package/lib/podrdf.mjs +0 -132
@@ -0,0 +1,556 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>FediPod — record</title>
7
+ <link rel="stylesheet" href="tokens.css">
8
+ <style>
9
+ /* Colours are the shared tokens (tokens.css, the front's palette), so the
10
+ record, the front and the bar are one visual system; only the layout root —
11
+ the base scale and the bar's column — stays here. Controls share one look: a
12
+ field is a light well with a drawn chevron, a button is the front's filled
13
+ green. */
14
+ :root { color-scheme: light dark; font-size: 125%; --bar-col: 1280px; }
15
+ /* The page itself never scrolls: the body is exactly the window; the content
16
+ column beside the rail is the scroll container. */
17
+ html { height: 100%; }
18
+ body { font: 1rem/1.5 system-ui, sans-serif; margin: 0; height: 100dvh;
19
+ box-sizing: border-box; display: flex; flex-direction: column; overflow: hidden; }
20
+ /* The bar spans the window; the rail and the content column share one centred
21
+ column underneath it — wide enough that the content keeps 960 of its own
22
+ beside the expanded rail. */
23
+ #page { flex: 1 1 auto; min-height: 0; width: 100%; max-width: 1280px; margin: 0 auto;
24
+ padding: 1.25rem 1rem 1rem; box-sizing: border-box;
25
+ display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 1.25rem; }
26
+ #content { min-width: 0; min-height: 0; overflow-y: auto; }
27
+ /* Two cases where the page may grow past the window: the new-account form, and
28
+ a group console, whose lists have no bound. Both scroll on the window. */
29
+ body.adding, body.group { height: auto; min-height: 100dvh; overflow: auto; }
30
+ body.adding #page { display: block; }
31
+ body.adding #content, body.group #content { overflow: visible; min-height: auto; }
32
+ body.group #page { min-height: auto; }
33
+ body.adding #rail { display: none; }
34
+ /* The action rail: a raised card of everything you can DO, so the facts keep
35
+ the page. Collapsed it is a slim strip holding only the toggle arrow. */
36
+ #rail { width: 14.5rem; box-sizing: border-box; padding: .6rem .8rem .9rem;
37
+ align-self: start; max-height: 100%; overflow-y: auto;
38
+ background: var(--raised); border-radius: .5rem; }
39
+ #rail.closed { width: auto; padding: .4rem; }
40
+ #rail.closed .rail-groups { display: none; }
41
+ #rail-toggle { display: flex; align-items: center; justify-content: flex-end;
42
+ width: 100%; margin: 0; padding: .2rem .3rem; border: 0;
43
+ background: none; font: inherit; font-weight: 600; color: var(--heading);
44
+ cursor: pointer; border-radius: .3rem; }
45
+ #rail-toggle:hover, #rail-toggle:active { background: none; }
46
+ .rail-arrow { color: var(--link); }
47
+ .rail-group h2 { display: block; font-size: .9rem; font-weight: 600;
48
+ text-transform: uppercase; letter-spacing: .06em; margin: .9rem 0 .35rem; }
49
+ .rail-group button { display: block; width: 100%; text-align: left;
50
+ margin: .35rem 0; font-size: .95rem; padding: .35rem .7rem; font-weight: 400; }
51
+ .rail-group .apart { margin-top: 1rem; }
52
+ /* One column on a phone: the rail becomes a strip of pills above the facts. */
53
+ @media (max-width: 47rem) {
54
+ #page { display: flex; flex-direction: column; gap: .9rem; }
55
+ #rail { width: auto; max-height: none; overflow: visible; }
56
+ .rail-group { display: flex; flex-wrap: wrap; align-items: baseline; gap: .1rem .45rem; }
57
+ .rail-group h2 { flex: 0 0 100%; margin: .5rem 0 .1rem; }
58
+ .rail-group button { display: inline-block; width: auto; margin: .2rem 0; }
59
+ #content { flex: 1 1 auto; }
60
+ }
61
+ /* `hidden` is a UA rule, so ANY author `display` beats it — `dl { display: grid }`
62
+ left the facts on screen with the attribute set. Everything here toggles with
63
+ `hidden`, so it has to outrank them all. */
64
+ [hidden] { display: none !important; }
65
+ /* The two status regions are never `hidden`: a live region put into the
66
+ accessibility tree in the same task as its text does not reliably announce,
67
+ so they stay in it and disappear by being empty instead. */
68
+ #say:empty, #fatal:empty { display: none; }
69
+ h1, h2, h3 { color: var(--heading); }
70
+ a { color: var(--link); }
71
+ h2, h3 { font-size: 1.15rem; font-weight: 600; display: flex; flex-wrap: wrap;
72
+ align-items: baseline; gap: .6rem; }
73
+ h2 { margin: 1.5rem 0 .5rem; }
74
+ h3 { margin: 1.25rem 0 .35rem; }
75
+ #facts { margin: .75rem 0 0; }
76
+ /* They sit after the kind, on that row, so they need a gap from the word and
77
+ must not stretch the row's line height. */
78
+ #moderation { margin-left: .6rem; word-break: normal; }
79
+ #moderation label { display: inline; margin: 0 .3rem 0 .5rem; font-weight: normal; color: var(--muted); }
80
+ p { margin: .5rem 0; }
81
+ .sub { color: var(--muted); margin-top: 0; }
82
+ fieldset { border: 1px solid var(--line); border-radius: .4rem; margin: 1rem 0; padding: .75rem 1rem 1rem; }
83
+ legend { padding: 0 .3rem; font-weight: 600; color: var(--heading); }
84
+ label { display: block; margin: .75rem 0 .2rem; }
85
+ .hint { color: var(--muted); font-size: 1rem; margin: .15rem 0 0; }
86
+ .choice input[type=text] { width: 9ch; display: inline-block; padding: .15rem .3rem; }
87
+ /* SETTINGS: light wells, unmistakably fields, in both schemes. */
88
+ input[type=text], input[type=email], input[type=url], input[type=password], textarea {
89
+ font: inherit; width: 100%; padding: .5rem; box-sizing: border-box;
90
+ border: 1px solid var(--field-edge); border-radius: .3rem;
91
+ background: var(--field-bg); color: var(--ink); }
92
+ input::placeholder { color: var(--muted); opacity: 1; }
93
+ select { font: inherit; appearance: none; max-width: 100%; min-width: 0;
94
+ padding: .15rem 1.7rem .15rem .55rem;
95
+ border: 1px solid var(--field-edge); border-radius: .3rem;
96
+ color: var(--ink); cursor: pointer;
97
+ background-color: var(--field-bg); background-image: var(--chevron);
98
+ background-repeat: no-repeat; background-position: right .55rem center;
99
+ background-size: .6rem auto; }
100
+ select:hover { background-color: var(--field-bg-hover); }
101
+ /* ACTIONS: the front's filled-green button, one look for the whole page,
102
+ Retire included — the typed-handle confirm, not a colour, is what guards the
103
+ destructive ones. */
104
+ button { font: inherit; padding: .45rem 1rem; border-radius: .3rem; border: 1px solid var(--btn);
105
+ background: var(--btn); color: var(--btn-text); cursor: pointer; }
106
+ button:hover, button:active { background: var(--btn-hover); border-color: var(--btn-hover); }
107
+ button.primary { font-weight: 600; }
108
+ button:disabled { opacity: .55; cursor: default; }
109
+ /* Small buttons that sit in a line of text. */
110
+ button.inline { font-size: .9rem; padding: .15rem .6rem; font-weight: 400; }
111
+ /* One visible ring for everything focusable. */
112
+ :is(button, select, input, textarea, a):focus-visible {
113
+ outline: 2px solid var(--ring); outline-offset: 2px; }
114
+ dl { margin: .5rem 0; } /* grid only above 34rem — see the media query below */
115
+ @media (min-width: 34rem) {
116
+ dl { display: grid; grid-template-columns: max-content minmax(0, 1fr);
117
+ gap: .6rem .9rem; align-items: baseline; }
118
+ }
119
+ dt { color: var(--muted); }
120
+ /* An identity connected under "Other identities" belongs to the row above it,
121
+ and the indent is what says so. */
122
+ dt.under { padding-left: 1.25rem; }
123
+ dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
124
+ .rows { list-style: none; padding: 0; margin: .3rem 0; }
125
+ .rows li { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center;
126
+ padding: .4rem 0; border-top: 1px solid var(--line); }
127
+ .rows li span { flex: 1 1 18rem; overflow-wrap: anywhere; }
128
+ .muted { color: var(--muted); }
129
+ /* The actors dropdown rides the bar, at the bar's own text scale. */
130
+ #bar select { font-size: .95rem; }
131
+ /* The per-account Options disclosure: only where storage is not a real choice
132
+ (the Node agent's Bluesky, cross-post instead) — a summary opening
133
+ Show/Hide in Feed, Cross-post On/Off, Connected/Disconnect. Where storage
134
+ IS a choice, two dropdowns sit in the row directly instead (admin.js
135
+ connectionControls). */
136
+ details.opts { display: inline-block; }
137
+ details.opts > summary { cursor: pointer; color: var(--link); list-style: none; }
138
+ details.opts > summary::-webkit-details-marker { display: none; }
139
+ details.opts > summary::after { content: ' \25be'; }
140
+ details.opts[open] > summary::after { content: ' \25b4'; }
141
+ details.opts > div { margin: .4rem 0 .2rem; padding: .5rem .6rem; display: flex; flex-direction: column;
142
+ gap: .4rem; align-items: stretch; border: 1px solid var(--line); border-radius: .3rem;
143
+ background: var(--raised); min-width: 11rem; }
144
+ details.opts > div select { width: 100%; }
145
+ .opt-hint { color: var(--muted); font-size: .9rem; margin: -.1rem 0 .1rem; }
146
+ /* The connection and storage dropdowns that sit in the row itself (admin.js
147
+ connectionControls) — extra room from the account name before them. */
148
+ .conn-controls { display: inline-flex; align-items: center; gap: .4rem; margin-left: 1rem; }
149
+ /* The alias row inside the Transfer-an-account-here panel. */
150
+ #alias-ctl { display: flex; gap: .5rem; align-items: center; margin-top: .3rem; }
151
+ #alias-ctl input { flex: 1 1 12rem; width: auto; }
152
+ #alias-chips span { display: inline-flex; align-items: center; gap: .35rem;
153
+ border: 1px solid var(--btn-edge); border-radius: 999px;
154
+ padding: .05rem .25rem .05rem .75rem; margin: 0 .3rem .3rem 0; }
155
+ /* Radios read as one line each: label { display: block } alone drops the text
156
+ below the control. */
157
+ .choice { display: block; margin: .35rem 0; font-weight: normal; }
158
+ .choice input { width: auto; margin-right: .4rem; }
159
+ .warn { border-left: .25rem solid var(--warn); padding-left: .75rem; }
160
+ .err { border-left: .25rem solid var(--danger); padding-left: .75rem; color: var(--danger); }
161
+ .ok { border-left: .25rem solid var(--ok); padding-left: .75rem; }
162
+ pre { overflow-x: auto; background: #0001; padding: .6rem; border-radius: .3rem; font-size: .9rem; }
163
+ @media (prefers-color-scheme: dark) {
164
+ fieldset { border-color: #555; } .rows li { border-color: #444; }
165
+ }
166
+ </style>
167
+ <link rel="stylesheet" href="bar.css?v=3">
168
+ <link rel="stylesheet" href="window.css">
169
+ <style>#gw-shape-front,#do-drain,#do-log,#actor-pick{display:none!important}</style>
170
+ </head>
171
+ <body>
172
+
173
+ <!-- The same bar the client view carries: one thing, two views. -->
174
+ <nav id="bar" aria-label="Site">
175
+ <h1 class="name"><a href="/?add">FediPod</a></h1>
176
+ <select id="actor-pick" aria-label="Local actors"
177
+ title=" Every actor on this machine; choosing one goes to its record"></select>
178
+ <a id="bar-fediverse" href="client/" title=" Open the client and read your timeline">visit account</a>
179
+ <a id="bar-manage" href="./" title=" The record: what this actor is, and what you can do to it" aria-current="page">manage account</a>
180
+ <a id="bar-signout" href="/?signout" title=" Sign out of FediPod and clear this browser">sign out</a>
181
+ </nav>
182
+ <main id="page">
183
+
184
+ <!-- Everything you can DO, in one collapsible card; the facts keep the page.
185
+ The buttons are the same ones the two action rows used to hold — same
186
+ ids, same floating panels. -->
187
+ <nav id="rail" hidden aria-label="Actions">
188
+ <button type="button" id="rail-toggle" aria-expanded="true" aria-label="Actions"
189
+ title=" Hide the action panel"><span class="rail-arrow" aria-hidden="true">«</span></button>
190
+ <div class="rail-groups">
191
+ <section class="rail-group" aria-label="Upkeep">
192
+ <h2>Upkeep</h2>
193
+ <button id="do-drain" title=" Fetch and handle whatever is waiting in the inbox now">Drain the inbox</button>
194
+ <button id="do-rebuild" title=" Refresh your feed from what your pod still holds">Refresh Feed</button>
195
+ <button id="do-log" title=" This agent's recent log lines">Show the log</button>
196
+ <button id="do-deadletter" title=" Deliveries that failed for good and were set aside">Show dead letters</button>
197
+ </section>
198
+ <section class="rail-group" aria-label="Lifecycle">
199
+ <h2>Lifecycle</h2>
200
+ <button id="do-rotate-key" title=" Replace the signing key and tell other servers the new one" data-confirm="rotate-key">Rotate signing key</button>
201
+ <button id="do-transfer-in" title=" List an old account as an alias, so its server sends its followers here">Transfer an account here</button>
202
+ <button id="do-move" title=" Your followers go to the account you name; this handle keeps resolving as a redirect" data-confirm="move">Transfer this account away</button>
203
+ <button id="do-retire" title=" End this identity for good — a Delete, then a Tombstone" class="danger apart" data-confirm="retire">Retire identity</button>
204
+ </section>
205
+ </div>
206
+ </nav>
207
+
208
+ <div id="content">
209
+ <p class="err" id="fatal" role="alert"></p>
210
+ <p aria-live="polite" id="say"></p>
211
+
212
+ <!-- Every actor running on this machine. A stopped one is left out: there is
213
+ no page there to open. Plain links — a top-level navigation sends no
214
+ Origin, so each agent's own firewall lets it through. -->
215
+ <section id="pane-others" aria-label="Actors on this machine" hidden>
216
+ <!-- Everything setup cannot work without. The bio, avatar and UI password it
217
+ also offers are all changeable afterwards, so they are not asked here —
218
+ the fuller form is what the new actor opens on. -->
219
+ <form id="new-actor-form" hidden>
220
+ <fieldset>
221
+ <legend>What kind of Actor?</legend>
222
+ <label class="choice"><input type="radio" name="newKind" value="person" checked>
223
+ A <strong>person</strong> — an account you read and post from</label>
224
+ <label class="choice"><input type="radio" name="newKind" value="group">
225
+ A <strong>group</strong> of Fediverse users you manage</label>
226
+ </fieldset>
227
+
228
+ <fieldset>
229
+ <legend>Actor's Handle</legend>
230
+ <label for="new-handle">Handle</label>
231
+ <input type="text" id="new-handle" autocomplete="off"
232
+ placeholder="handle part of Fediverse address: @HANDLE@server"
233
+ aria-describedby="new-handle-hint">
234
+ <p class="hint" id="new-handle-hint">The name in your Fediverse address. This is permanent.
235
+ Letters, digits, hyphens, and underscores only.</p>
236
+ </fieldset>
237
+
238
+ <fieldset>
239
+ <legend>Actor's Pod</legend>
240
+ <label class="choice"><input type="radio" name="newMode" value="new" checked>
241
+ Create a Solid account and pod for the Actor</label>
242
+ <label class="choice"><input type="radio" name="newMode" value="existing">
243
+ Use a pod I already have</label>
244
+
245
+ <label for="new-issuer">Solid identity provider</label>
246
+ <input type="url" id="new-issuer" value="https://solidcommunity.net" autocomplete="url">
247
+
248
+ <label for="new-email">Solid Account email/username</label>
249
+ <input type="email" id="new-email" autocomplete="email" placeholder="you@example.org">
250
+
251
+ <label for="new-password">Solid Account password</label>
252
+ <input type="password" id="new-password" autocomplete="current-password"
253
+ aria-describedby="new-password-hint">
254
+ <p class="hint" id="new-password-hint">Password is sent once in return for a credential which is stored locally.
255
+ The password itself is never stored. You may revoke the credential without changing the
256
+ password.</p>
257
+
258
+ <div id="new-row-podname">
259
+ <label for="new-podname">Pod name</label>
260
+ <input type="text" id="new-podname" autocomplete="off" aria-describedby="new-podname-hint">
261
+ <p class="hint" id="new-podname-hint">The subdomain of your pod address, it will become
262
+ https://YOUR-POD-NAME.your-identity-provider</p>
263
+ </div>
264
+ <div id="new-row-pod" hidden>
265
+ <label for="new-pod">Pod address</label>
266
+ <input type="url" id="new-pod" autocomplete="url" placeholder="https://you.solidcommunity.net/">
267
+ </div>
268
+ </fieldset>
269
+
270
+ <p>
271
+ <button type="submit" id="new-actor-go" title=" Create the account, the pod and the actor" class="primary">Create</button>
272
+ <button type="button" id="new-actor-cancel" title=" Change nothing and close">Cancel</button>
273
+ </p>
274
+ </form>
275
+
276
+ </section>
277
+
278
+ <section id="pane-identity" hidden>
279
+ <dl id="facts"></dl>
280
+ <!-- Declared here, and render() puts these on the kind row — the row they
281
+ belong to is generated, so this is the only place they can be written
282
+ down. Each reads as the setting it would change, so what it shows IS the
283
+ current state: changing the word is the whole action, with no save. -->
284
+ <span id="moderation" hidden>
285
+ <label for="joins-mod">join requests</label>
286
+ <select id="joins-mod" title=" Whether each join request waits for you">
287
+ <option value="unmoderated">unmoderated</option>
288
+ <option value="moderated">moderated</option>
289
+ </select>
290
+ <label for="review-mod">posts</label>
291
+ <select id="review-mod" title=" Whether members’ posts wait for you">
292
+ <option value="unmoderated">unmoderated</option>
293
+ <option value="moderated">moderated</option>
294
+ </select>
295
+ </span>
296
+ <span id="status-ctl" hidden>
297
+ <select id="status-pick" aria-label="Actor status" title=" Whether this actor is receiving mail — parking stops it and keeps the handle; active re-follows the saved graph">
298
+ <option value="active">active</option>
299
+ <option value="parked">parked</option>
300
+ </select>
301
+ </span>
302
+ <span id="update-ctl" hidden>
303
+ <span id="update-word"></span>
304
+ <button id="update-go" hidden title=" Pull the latest FediPod and restart every agent on this machine">Update</button>
305
+ </span>
306
+ <span id="follows-ctl" hidden>
307
+ <select id="follows-pick" aria-label="New followers" title=" Whether each new follower waits for you — switch to accepted automatically before moving an old account here, so the whole wave lands">
308
+ <option value="approve">wait for approval</option>
309
+ <option value="auto">accepted automatically</option>
310
+ </select>
311
+ </span>
312
+ <span id="ident-ctl" hidden>
313
+ <button type="button" id="ident-open" class="inline" title=" Connect an account you hold on another network, so its timeline joins the one you read here">Connect an identity</button>
314
+ </span>
315
+ </section>
316
+
317
+ <span id="gateway-ctl" hidden>
318
+ <span id="gateway-word"></span>
319
+ <button type="button" id="gateway-open-attach" class="inline" hidden
320
+ title=" Attach this account to a mail-filtering gateway">Attach to a gateway</button>
321
+ <button type="button" id="gateway-open-detach" class="inline danger" hidden
322
+ title=" Go back to your pod's own inbox">Detach from gateway</button>
323
+ </span>
324
+
325
+ <section id="pane-group" hidden>
326
+ <!-- Both queues are consequences of a moderation setting: with the setting off
327
+ nothing can ever arrive in them, so the heading would be a standing
328
+ promise of a list that cannot fill. Shown only when the setting is on AND
329
+ something is waiting. -->
330
+ <div id="block-requests" hidden>
331
+ <h3>Follow requests <span class="muted" id="requests-count"></span>
332
+ <button id="admit-all" class="inline" title=" Accept everyone waiting, in one go">Accept all</button></h3>
333
+ <ul class="rows" role="list" id="requests"></ul>
334
+ </div>
335
+
336
+ <div id="block-pending" hidden>
337
+ <h3>Posts to review <span class="muted" id="pending-count"></span></h3>
338
+ <ul class="rows" role="list" id="pending"></ul>
339
+ </div>
340
+
341
+ <!-- Moderation another server asked for. A delivery does not prove who sent
342
+ it, so a moderator's request waits to be vouched for rather than acting
343
+ on arrival. Shown only when something is actually waiting. -->
344
+ <div id="block-modqueue" hidden>
345
+ <h3>Moderation requests <span class="muted" id="modqueue-count"></span></h3>
346
+ <p class="hint">Asked for by a moderator over the Fediverse. A delivery cannot prove who
347
+ sent it, so nothing here has been acted on.</p>
348
+ <ul class="rows" role="list" id="modqueue"></ul>
349
+ </div>
350
+
351
+ <h3>Members <span class="muted" id="members-count"></span></h3>
352
+ <p class="hint">A group cannot force an unfollow. Muting is declining to carry; ejecting also
353
+ tells their server it is no longer a member.</p>
354
+ <ul class="rows" role="list" id="members"></ul>
355
+
356
+ <h3>Carried <span class="muted" id="announced-count"></span></h3>
357
+ <ul class="rows" role="list" id="announced"></ul>
358
+ </section>
359
+
360
+ <section id="pane-inbox" hidden>
361
+ <h2><span class="hlabel">Inbox</span></h2>
362
+ <p id="inbox-summary"></p>
363
+ <p class="hint">Your pod accepts deliveries whether or not this agent is running, so a
364
+ machine that has been off collects them. The agent is working through them oldest first
365
+ and will get there on its own — this is only here if you would rather not wait.</p>
366
+ <p>
367
+ <button id="inbox-keep" title=" Keep everything and let the agent work through it">Keep everything</button>
368
+ <label for="inbox-before">or discard content older than</label>
369
+ <select id="inbox-before">
370
+ <option value="7">7 days</option>
371
+ <option value="30" selected>30 days</option>
372
+ <option value="90">90 days</option>
373
+ </select>
374
+ <button id="inbox-prune" title=" Discard content older than the chosen age; keep the bookkeeping" class="primary">Discard it</button>
375
+ </p>
376
+ <p class="hint">Discarding drops posts, not bookkeeping: follows, unfollows, acceptances
377
+ and deletions in that period are still applied, so your follower list stays right and
378
+ nothing stays up that its author took down. What goes is the timeline you would have
379
+ read that week.</p>
380
+ <p class="err" id="inbox-warn" hidden></p>
381
+ </section>
382
+
383
+ <!-- Every form and panel is DECLARED here, inside the window that shows them.
384
+ Nothing is built in script — window.js only unhides one at a time, moves
385
+ the window and closes it. It floats rather than opening at the foot of the
386
+ page, so it never pushes the line you are reading out from under you. -->
387
+ <div id="win" hidden>
388
+ <div id="win-bar"><span id="win-title"></span><button type="button" id="win-close" title=" Close this panel" aria-label="Close panel">✕</button></div>
389
+ <div id="win-body">
390
+ <pre id="output" tabindex="0" role="region" aria-label="Output" hidden></pre>
391
+ <!-- The inbound half of transferring: the aliases its old server checks before
392
+ it will send the Move. The outbound half is its own panel (confirm-form,
393
+ warn-move) — additive and reversible here, followers handed away there,
394
+ so the two directions never share a door. -->
395
+ <div id="transfer-in-form" hidden>
396
+ <p class="hint">List the old account here first — its server checks this list before it
397
+ will send the move. Then start the transfer from the old account's own settings, and
398
+ set new followers to "accepted automatically" so the whole wave lands.</p>
399
+ <p id="alias-chips"></p>
400
+ <span id="alias-ctl">
401
+ <input type="text" id="alias-input" placeholder="@you@old.server" autocomplete="off"
402
+ title=" The account you are moving here from; its server checks this list before it will send the Move">
403
+ <button type="button" id="alias-add" class="inline"
404
+ title=" Resolve the old account, list it in alsoKnownAs, and republish the actor">Add alias</button>
405
+ </span>
406
+ </div>
407
+ <form id="bsky-form" hidden>
408
+ <ol class="hint">
409
+ <li>Get an account on Bluesky or another ATProto server.</li>
410
+ <li>On Bluesky, make an app password (Settings → Privacy and security → App Passwords)
411
+ and copy it — it is shown only once.</li>
412
+ <li>Fill in this form to connect, pasting that app password into the password
413
+ field.</li>
414
+ </ol>
415
+ <label for="bsky-service">service</label>
416
+ <input type="url" id="bsky-service" value="https://bsky.social" autocomplete="off">
417
+ <label for="bsky-identifier">handle</label>
418
+ <input type="text" id="bsky-identifier" placeholder="you.bsky.social" autocomplete="username">
419
+ <label for="bsky-password">app password</label>
420
+ <input id="bsky-password" type="password" autocomplete="current-password">
421
+ <p>
422
+ <button id="bsky-connect" type="submit" class="primary" title=" Sign in to the Bluesky account with the app password">Connect</button>
423
+ </p>
424
+ </form>
425
+ <form id="ident-form" hidden>
426
+ <p class="hint">Either kind brings that account's timeline and notifications
427
+ into the feed you read here, and acts as that account when you reply to,
428
+ favourite or boost one of its posts.</p>
429
+ <p>
430
+ <button type="button" id="ident-pick-fedi" class="primary" title=" Sign in at a Mastodon-API server: Mastodon, GoToSocial, Pleroma, Akkoma, Pixelfed or Friendica">A Fediverse account</button>
431
+ <button type="button" id="ident-pick-bsky" title=" Sign in to Bluesky or another ATProto server with an app password">A Bluesky account</button>
432
+ </p>
433
+ </form>
434
+ <form id="fediacct-form" hidden>
435
+ <ol class="hint">
436
+ <li>Name the server your other account is on.</li>
437
+ <li>That server asks you to sign in and to allow FediPod. It is the only
438
+ place your password is typed; this agent never sees or stores one.</li>
439
+ <li>Its timeline and notifications then join the ones you already read here,
440
+ and a like or a reply on one of its posts goes out as that account.</li>
441
+ <li>What arrives is held on this machine for reading. None of it is written
442
+ to your pod.</li>
443
+ </ol>
444
+ <label for="fediacct-host">server</label>
445
+ <input type="text" id="fediacct-host" placeholder="mastodon.social" autocomplete="off"
446
+ title=" The server your other account lives on — Mastodon, GoToSocial, Pleroma, Akkoma, Pixelfed and Friendica all speak the API this needs">
447
+ <p>
448
+ <button id="fediacct-connect" type="submit" class="primary" title=" Go to that server to sign in and allow FediPod">Continue to that server</button>
449
+ </p>
450
+ </form>
451
+ <!-- Every consequence is written here rather than assembled in script: the
452
+ page asking "are you sure" has to say what it is sure about, and this is
453
+ the only record of it. Script picks which block to show, nothing else. -->
454
+ <!-- The gateway popups: attach proves the pod with this agent's own credential;
455
+ detach republishes the pod's own inbox. -->
456
+ <form id="gateway-attach-form" hidden>
457
+ <p class="hint">A gateway filters your Fediverse mail before it reaches your pod: each
458
+ delivery is verified at its door, spam is dropped, and the rest lands in your pod as
459
+ before. Attaching proves the pod with this agent's own credential — no password
460
+ leaves this machine.</p>
461
+ <label for="gw-front">gateway</label>
462
+ <input type="url" id="gw-front" placeholder="https://fedipod.net" autocomplete="off">
463
+ <fieldset>
464
+ <legend>Your Fediverse handle</legend>
465
+ <label class="choice"><input type="radio" name="gwShape" value="pod" checked>
466
+ Keep my pod-based handle: <strong id="gw-pod-preview"></strong><br>
467
+ <span class="hint">Your address stays tied to your own pod — you can drop the
468
+ gateway any time and keep everything.</span></label>
469
+ <label class="choice" id="gw-shape-front"><input type="radio" name="gwShape" value="front">
470
+ Create a handle at the gateway:
471
+ @<input type="text" id="gw-name" placeholder="name" autocomplete="off"
472
+ autocapitalize="off" spellcheck="false">@<span id="gw-front-host">fedipod.net</span><br>
473
+ <span class="hint">Your address lives on the gateway's domain, but not your data
474
+ or key; you can change pods later and keep the handle.</span>
475
+ <span id="gw-name-msg" class="hint"></span></label>
476
+ </fieldset>
477
+ <p>
478
+ <button id="gw-attach" type="button" class="primary"
479
+ title=" Create the gateway account and point your mail through its door">Attach</button>
480
+ </p>
481
+ </form>
482
+ <form id="gateway-detach-form" hidden>
483
+ <p class="hint" id="gw-detach-plain">Deliveries go back to your pod's own inbox — the
484
+ actor is republished advertising it. Your name and data never moved.</p>
485
+ <p class="warn" id="gw-detach-fronted" hidden>This identity publishes under the gateway's
486
+ name. Detaching moves every published id back to the pod — a rename other servers
487
+ see, not just a mail change.</p>
488
+ <p>
489
+ <button id="gw-detach" type="button" class="primary"
490
+ title=" Forget the gateway and republish the actor with the pod inbox">Detach</button>
491
+ </p>
492
+ </form>
493
+ <form id="confirm-form" hidden>
494
+ <div id="warn-rotate-key" class="warn" hidden>
495
+ <p>A new keypair replaces the one in this home and the actor is republished so other
496
+ servers learn it. Any other device still holding the old key stops being able to sign.</p>
497
+ <!-- Browser build only: there the key on the pod is locked under the account
498
+ password, so a new one has to be locked too. The Node agent keeps its key
499
+ on disk and needs nothing here — stage-site.mjs reveals this row. -->
500
+ <div id="rotate-pw-row">
501
+ <label for="rotate-password">Your account password</label>
502
+ <input type="password" id="rotate-password" autocomplete="current-password">
503
+ <p class="hint">Your signing key is kept on your pod locked under this, so the
504
+ replacement has to be locked under it too. It is not sent anywhere else.</p>
505
+ </div>
506
+ </div>
507
+ <div id="warn-retire" class="warn" hidden>
508
+ <p><strong>This cannot be undone.</strong> A Delete goes to every follower's inbox telling
509
+ those servers to drop the account and the posts they cached, the actor document is
510
+ replaced with a Tombstone, and this agent will refuse to start again for this pod. Your
511
+ posts and RDF stay on the pod; the identity does not come back.</p>
512
+ <p>Two things that are not this, and can be done from here:
513
+ <button type="button" id="go-park" title=" Park instead: keeps the handle, just stops the mail" class="inline">Park it instead</button>
514
+ keeps the handle resolving and just stops the mail — setting status back to
515
+ active undoes it.
516
+ <button type="button" id="go-move" title=" Transfer instead: hands your followers to another account" class="inline">Transfer it instead</button>
517
+ hands your followers to another account.</p>
518
+ <label for="confirm-handle">Type the handle to confirm</label>
519
+ <input type="text" id="confirm-handle" autocomplete="off">
520
+ </div>
521
+ <!-- "Move private data" (POST /state-move) had a panel here and no way to
522
+ open it: nothing in this page has ever carried data-confirm="move-state",
523
+ so the panel was only ever hidden. Removed 2026-09-09 rather than left as
524
+ markup that looks like a feature. The route is still there for the CLI,
525
+ which is where moving the private half between a directory and the pod
526
+ belongs — it is about filesystem paths and credential.json, neither of
527
+ which a browser has. -->
528
+ <div id="warn-move" class="warn" hidden>
529
+ <p>A <code>Move</code> goes to every follower's inbox and their servers migrate them to the
530
+ account you name, so they end up following that one instead. The actor left behind
531
+ advertises <code>movedTo</code>, so this handle keeps resolving as a redirect rather than
532
+ breaking — nothing here is deleted.</p>
533
+ <p>Then this identity is parked, exactly as Park would: everyone it follows is unfollowed
534
+ and the inbox is closed. Migrating is the far end's decision, so some followers will not
535
+ come across.</p>
536
+ <label for="move-target">Transfer to</label>
537
+ <input type="text" id="move-target" autocomplete="off" placeholder="@you@elsewhere or an actor URL">
538
+ <label for="confirm-handle-move">Type this actor's handle to confirm</label>
539
+ <input type="text" id="confirm-handle-move" autocomplete="off">
540
+ </div>
541
+ <p>
542
+ <button type="submit" id="confirm-go" title=" Do it" class="primary">Confirm</button>
543
+ <button type="button" id="confirm-cancel" title=" Change nothing and close">Cancel</button>
544
+ </p>
545
+ </form>
546
+ </div>
547
+ </div>
548
+
549
+ </div>
550
+ </main>
551
+
552
+ <script src="bar.js"></script>
553
+ <script src="window.js"></script>
554
+ <script src="admin.js"></script>
555
+ </body>
556
+ </html>