fedipod-server 0.29.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (444) hide show
  1. package/README.md +16 -6
  2. package/dist/claims.d.ts +2 -0
  3. package/dist/claims.js +13 -4
  4. package/dist/door.d.ts +4 -0
  5. package/dist/door.js +31 -0
  6. package/dist/fedipod.d.ts +15 -0
  7. package/dist/fedipod.js +13 -0
  8. package/dist/front.d.ts +3 -0
  9. package/dist/front.js +92 -0
  10. package/dist/handler.d.ts +36 -101
  11. package/dist/handler.js +93 -644
  12. package/dist/handler.jsonld +2 -30
  13. package/dist/identities.d.ts +71 -0
  14. package/dist/identities.js +236 -0
  15. package/dist/mounts.d.ts +43 -0
  16. package/dist/mounts.js +123 -0
  17. package/dist/opt-in.d.ts +46 -0
  18. package/dist/opt-in.js +176 -0
  19. package/dist/private-read.d.ts +4 -0
  20. package/dist/private-read.js +34 -0
  21. package/package.json +12 -20
  22. package/lib/client/c2s.mjs +0 -636
  23. package/lib/client/localapi.mjs +0 -87
  24. package/lib/client/masto/accounts.mjs +0 -310
  25. package/lib/client/masto/body.mjs +0 -156
  26. package/lib/client/masto/index.mjs +0 -206
  27. package/lib/client/masto/instance.mjs +0 -112
  28. package/lib/client/masto/media.mjs +0 -79
  29. package/lib/client/masto/oauth.mjs +0 -656
  30. package/lib/client/masto/render.mjs +0 -518
  31. package/lib/client/masto/statuses.mjs +0 -372
  32. package/lib/client/masto/timelines.mjs +0 -438
  33. package/lib/client/oidc-auth.mjs +0 -62
  34. package/lib/client/streaming.mjs +0 -154
  35. package/lib/client/webpush.mjs +0 -98
  36. package/lib/connections/acctfeed.mjs +0 -257
  37. package/lib/connections/atproto.mjs +0 -309
  38. package/lib/connections/bskyfeed.mjs +0 -243
  39. package/lib/connections/bskygroup.mjs +0 -162
  40. package/lib/connections/fediacct.mjs +0 -253
  41. package/lib/connections/import.mjs +0 -357
  42. package/lib/connections/tagfeed.mjs +0 -212
  43. package/lib/connections/vault.mjs +0 -114
  44. package/lib/core/as2.mjs +0 -206
  45. package/lib/core/contexts/activitystreams.json +0 -379
  46. package/lib/core/contexts/anno.json +0 -126
  47. package/lib/core/contexts/did-v1.json +0 -57
  48. package/lib/core/contexts/fep-5711.json +0 -36
  49. package/lib/core/contexts/gotosocial.json +0 -86
  50. package/lib/core/contexts/identity-v1.json +0 -152
  51. package/lib/core/contexts/index.mjs +0 -63
  52. package/lib/core/contexts/join-lemmy.json +0 -33
  53. package/lib/core/contexts/joinmastodon.json +0 -28
  54. package/lib/core/contexts/litepub-0.1.json +0 -60
  55. package/lib/core/contexts/map.json +0 -19
  56. package/lib/core/contexts/miscellany.json +0 -19
  57. package/lib/core/contexts/quotes.json +0 -18
  58. package/lib/core/contexts/schemaorg.json +0 -8845
  59. package/lib/core/contexts/security-data-integrity-v1.json +0 -78
  60. package/lib/core/contexts/security-data-integrity-v2.json +0 -81
  61. package/lib/core/contexts/security-multikey-v1.json +0 -35
  62. package/lib/core/contexts/security-v1.json +0 -74
  63. package/lib/core/contexts/webfinger.json +0 -10
  64. package/lib/core/deliver.mjs +0 -387
  65. package/lib/core/graphview.mjs +0 -327
  66. package/lib/core/intake/activities.mjs +0 -649
  67. package/lib/core/intake/activity.mjs +0 -318
  68. package/lib/core/intake/channel.mjs +0 -144
  69. package/lib/core/intake/group.mjs +0 -258
  70. package/lib/core/intake/index.mjs +0 -732
  71. package/lib/core/intake/notes.mjs +0 -367
  72. package/lib/core/intake/verify.mjs +0 -142
  73. package/lib/core/keys.mjs +0 -153
  74. package/lib/core/lease.mjs +0 -206
  75. package/lib/core/place.mjs +0 -82
  76. package/lib/core/polls.mjs +0 -105
  77. package/lib/core/profile-page.mjs +0 -104
  78. package/lib/core/proof.mjs +0 -79
  79. package/lib/core/publisher/collections.mjs +0 -272
  80. package/lib/core/publisher/index.mjs +0 -522
  81. package/lib/core/publisher/notes.mjs +0 -519
  82. package/lib/core/publisher/own.mjs +0 -143
  83. package/lib/core/publisher/questions.mjs +0 -241
  84. package/lib/core/publisher/restore.mjs +0 -224
  85. package/lib/core/shapes/activitystreams.ttl +0 -157
  86. package/lib/core/shapes/index.mjs +0 -132
  87. package/lib/core/shapes/shapes-text.mjs +0 -13
  88. package/lib/core/social.mjs +0 -561
  89. package/lib/core/storage.mjs +0 -176
  90. package/lib/core/store.mjs +0 -578
  91. package/lib/core/wire-quotes.mjs +0 -71
  92. package/lib/core/wire.mjs +0 -925
  93. package/lib/device/account.mjs +0 -87
  94. package/lib/device/admin/index.mjs +0 -13
  95. package/lib/device/admin/origins.mjs +0 -35
  96. package/lib/device/admin/routes/connections.mjs +0 -144
  97. package/lib/device/admin/routes/gateway.mjs +0 -199
  98. package/lib/device/admin/routes/lifecycle.mjs +0 -200
  99. package/lib/device/admin/routes/owner.mjs +0 -322
  100. package/lib/device/admin/routes/setup.mjs +0 -428
  101. package/lib/device/admin/routes/social.mjs +0 -188
  102. package/lib/device/admin/server.mjs +0 -95
  103. package/lib/device/admin/static.mjs +0 -247
  104. package/lib/device/admin/surface.mjs +0 -315
  105. package/lib/device/certs.mjs +0 -281
  106. package/lib/device/cli/commands/account.mjs +0 -586
  107. package/lib/device/cli/commands/run.mjs +0 -278
  108. package/lib/device/cli/commands/service.mjs +0 -221
  109. package/lib/device/cli/commands/setup.mjs +0 -489
  110. package/lib/device/cli/commands/state.mjs +0 -561
  111. package/lib/device/cli/context.mjs +0 -288
  112. package/lib/device/export-collections.mjs +0 -161
  113. package/lib/device/gateway-move.mjs +0 -58
  114. package/lib/device/home.mjs +0 -161
  115. package/lib/device/migrate.mjs +0 -115
  116. package/lib/device/ports.mjs +0 -27
  117. package/lib/device/remote.mjs +0 -54
  118. package/lib/device/setup.mjs +0 -496
  119. package/lib/device/update.mjs +0 -96
  120. package/lib/gateway/caches.mjs +0 -36
  121. package/lib/gateway/directory.mjs +0 -90
  122. package/lib/gateway/front-core.mjs +0 -966
  123. package/lib/gateway/gateway-core.mjs +0 -244
  124. package/lib/gateway/headers.mjs +0 -49
  125. package/lib/gateway/httpsig.mjs +0 -159
  126. package/lib/gateway/notices.mjs +0 -84
  127. package/lib/gateway/quiet.mjs +0 -189
  128. package/lib/gateway/relay-extras.mjs +0 -89
  129. package/lib/gateway/token-claims.mjs +0 -16
  130. package/lib/pod/README.md +0 -61
  131. package/lib/pod/actor.mjs +0 -96
  132. package/lib/pod/collection.mjs +0 -77
  133. package/lib/pod/containers.mjs +0 -140
  134. package/lib/pod/discovery.mjs +0 -46
  135. package/lib/pod/featured.mjs +0 -18
  136. package/lib/pod/followers.mjs +0 -24
  137. package/lib/pod/following.mjs +0 -10
  138. package/lib/pod/http.mjs +0 -74
  139. package/lib/pod/inbox.mjs +0 -166
  140. package/lib/pod/links.mjs +0 -35
  141. package/lib/pod/location.mjs +0 -52
  142. package/lib/pod/media.mjs +0 -27
  143. package/lib/pod/notes.mjs +0 -78
  144. package/lib/pod/notifications.mjs +0 -89
  145. package/lib/pod/outbox.mjs +0 -18
  146. package/lib/pod/package.json +0 -19
  147. package/lib/pod/policy.mjs +0 -58
  148. package/lib/pod/private.mjs +0 -19
  149. package/lib/pod/root.mjs +0 -104
  150. package/lib/pod/state.mjs +0 -40
  151. package/lib/pod/transport.mjs +0 -674
  152. package/lib/pod/type-index.mjs +0 -101
  153. package/lib/pod/urls.mjs +0 -91
  154. package/lib/server/embed.mjs +0 -424
  155. package/lib/session/README.md +0 -137
  156. package/lib/session/demo.html +0 -94
  157. package/lib/session/fedi-account.mjs +0 -417
  158. package/lib/session/fedi-login.mjs +0 -123
  159. package/lib/session/oidc-session.mjs +0 -233
  160. package/lib/session/package.json +0 -49
  161. package/lib/shared/guard.mjs +0 -213
  162. package/lib/shared/links.mjs +0 -9
  163. package/lib/shared/safefetch.mjs +0 -235
  164. package/lib/shared/ua.mjs +0 -29
  165. package/phanpy/dist/404.html +0 -40
  166. package/phanpy/dist/_headers +0 -2
  167. package/phanpy/dist/apple-touch-icon.png +0 -0
  168. package/phanpy/dist/assets/ICONS-DIPJeU0C.js +0 -2
  169. package/phanpy/dist/assets/ICONS-DIPJeU0C.js.map +0 -1
  170. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js +0 -183
  171. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js.map +0 -1
  172. package/phanpy/dist/assets/Temml-CCjoacWt.woff2 +0 -0
  173. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js +0 -2
  174. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js.map +0 -1
  175. package/phanpy/dist/assets/boosts-carousel-BiOaNdMT.jpg +0 -0
  176. package/phanpy/dist/assets/catch-up-O5q5C75Z.png +0 -0
  177. package/phanpy/dist/assets/chunk-aKtaBQYM.js +0 -1
  178. package/phanpy/dist/assets/compose-CFEx7wb4.js +0 -2
  179. package/phanpy/dist/assets/compose-CFEx7wb4.js.map +0 -1
  180. package/phanpy/dist/assets/compose-ZJN5xSb4.js +0 -35
  181. package/phanpy/dist/assets/compose-ZJN5xSb4.js.map +0 -1
  182. package/phanpy/dist/assets/debug.module-YFQgwnIr.js +0 -52
  183. package/phanpy/dist/assets/debug.module-YFQgwnIr.js.map +0 -1
  184. package/phanpy/dist/assets/dom-p1YcJ5Rw.js +0 -2
  185. package/phanpy/dist/assets/dom-p1YcJ5Rw.js.map +0 -1
  186. package/phanpy/dist/assets/home-mobile-dark@2x-Dc-J8-SM.png +0 -0
  187. package/phanpy/dist/assets/home-mobile-light@2x-Bd3fod8m.png +0 -0
  188. package/phanpy/dist/assets/home-tablet-dark@2x-BgcNI8le.png +0 -0
  189. package/phanpy/dist/assets/home-tablet-light@2x-BW2RV9T6.png +0 -0
  190. package/phanpy/dist/assets/icons/add-circle-line-WD0mwORD.js +0 -1
  191. package/phanpy/dist/assets/icons/alert-line-CpFUMf9s.js +0 -1
  192. package/phanpy/dist/assets/icons/android-2-line-Bzxnrd3S.js +0 -1
  193. package/phanpy/dist/assets/icons/announcement-line-5nwaJFJm.js +0 -1
  194. package/phanpy/dist/assets/icons/arrow-down-circle-line-a7Id9-Iv.js +0 -1
  195. package/phanpy/dist/assets/icons/arrow-down-line-B8uzXzq6.js +0 -1
  196. package/phanpy/dist/assets/icons/arrow-left-line-CGrGT9C-.js +0 -1
  197. package/phanpy/dist/assets/icons/arrow-right-line-CE-HERfX.js +0 -1
  198. package/phanpy/dist/assets/icons/arrow-to-up-line-CvdQjmcy.js +0 -1
  199. package/phanpy/dist/assets/icons/arrow-up-circle-line-DEparSNF.js +0 -1
  200. package/phanpy/dist/assets/icons/arrow-up-line-C7yBeugc.js +0 -1
  201. package/phanpy/dist/assets/icons/arrows-right-line-BtbXmJGP.js +0 -1
  202. package/phanpy/dist/assets/icons/at-line-CF66Bznk.js +0 -1
  203. package/phanpy/dist/assets/icons/attachment-line-BY8It-l9.js +0 -1
  204. package/phanpy/dist/assets/icons/blockquote-line-BS6pU_hm.js +0 -1
  205. package/phanpy/dist/assets/icons/board-line-C0UWXyA6.js +0 -1
  206. package/phanpy/dist/assets/icons/bookmark-line-1CtX5JLF.js +0 -1
  207. package/phanpy/dist/assets/icons/building-5-line-Dd59MzbO.js +0 -1
  208. package/phanpy/dist/assets/icons/bus-2-line-6_dvA0GG.js +0 -1
  209. package/phanpy/dist/assets/icons/calendar-day-line-Crpl_fmu.js +0 -1
  210. package/phanpy/dist/assets/icons/calendar-month-line-vommts2C.js +0 -1
  211. package/phanpy/dist/assets/icons/calendar-time-add-line-BU_DTlQk.js +0 -1
  212. package/phanpy/dist/assets/icons/camera-line-Cv69MEei.js +0 -1
  213. package/phanpy/dist/assets/icons/celebrate-line-B8DvIoi0.js +0 -1
  214. package/phanpy/dist/assets/icons/chart-bar-line-FK-QOmtF.js +0 -1
  215. package/phanpy/dist/assets/icons/chart-line-line-BGcJAFWw.js +0 -1
  216. package/phanpy/dist/assets/icons/chat-3-line-YFK2-hwz.js +0 -1
  217. package/phanpy/dist/assets/icons/check-circle-line-DsAxFr5-.js +0 -1
  218. package/phanpy/dist/assets/icons/clipboard-line-BBp364gJ.js +0 -1
  219. package/phanpy/dist/assets/icons/close-circle-line-CICdiuGz.js +0 -1
  220. package/phanpy/dist/assets/icons/close-line-DYrFWcjv.js +0 -1
  221. package/phanpy/dist/assets/icons/cloud-line-tiQAbah8.js +0 -1
  222. package/phanpy/dist/assets/icons/code-line-fAl8iiV3.js +0 -1
  223. package/phanpy/dist/assets/icons/comment-2-line-CR3g7WeB.js +0 -1
  224. package/phanpy/dist/assets/icons/copy-2-line-CLW69yF5.js +0 -1
  225. package/phanpy/dist/assets/icons/delete-2-line-B8xmbr4n.js +0 -1
  226. package/phanpy/dist/assets/icons/document-3-line-DBGNhAg2.js +0 -1
  227. package/phanpy/dist/assets/icons/document-line-C7mb9sb7.js +0 -1
  228. package/phanpy/dist/assets/icons/down-line-BGqSSThd.js +0 -1
  229. package/phanpy/dist/assets/icons/edit-4-line-DcgGaEhx.js +0 -1
  230. package/phanpy/dist/assets/icons/emoji-2-line-D8YgnM-y.js +0 -1
  231. package/phanpy/dist/assets/icons/exit-line-Dc07BS-x.js +0 -1
  232. package/phanpy/dist/assets/icons/external-link-line-BvpSkmjO.js +0 -1
  233. package/phanpy/dist/assets/icons/eye-2-line-CiWXx-f_.js +0 -1
  234. package/phanpy/dist/assets/icons/eye-close-line-BgTaSJ4P.js +0 -1
  235. package/phanpy/dist/assets/icons/filter-2-line-B_mR2usy.js +0 -1
  236. package/phanpy/dist/assets/icons/filter-line-C_nm-3cU.js +0 -1
  237. package/phanpy/dist/assets/icons/flag-1-line-C2HB05I0.js +0 -1
  238. package/phanpy/dist/assets/icons/forbid-circle-line-D3LTT9yd.js +0 -1
  239. package/phanpy/dist/assets/icons/formula-line-DLrt2d6j.js +0 -1
  240. package/phanpy/dist/assets/icons/grid-line-CgUmEikf.js +0 -1
  241. package/phanpy/dist/assets/icons/group-line-C5fnX0wU.js +0 -1
  242. package/phanpy/dist/assets/icons/hand-finger-2-line-BGgxbuL9.js +0 -1
  243. package/phanpy/dist/assets/icons/hashtag-line-CyTEEXBb.js +0 -1
  244. package/phanpy/dist/assets/icons/heart-crack-line-BZddbO2C.js +0 -1
  245. package/phanpy/dist/assets/icons/heart-line-CJ7K47J4.js +0 -1
  246. package/phanpy/dist/assets/icons/history-2-line-kWWvFzqv.js +0 -1
  247. package/phanpy/dist/assets/icons/history-line-bGQiwbTH.js +0 -1
  248. package/phanpy/dist/assets/icons/home-3-line-fRU1zeLG.js +0 -1
  249. package/phanpy/dist/assets/icons/information-line-iNk6-sOY.js +0 -1
  250. package/phanpy/dist/assets/icons/keyboard-line-DsCyuQNz.js +0 -1
  251. package/phanpy/dist/assets/icons/layout-4-line-CZkOX52Z.js +0 -1
  252. package/phanpy/dist/assets/icons/layout-5-line-B_znt5wO.js +0 -1
  253. package/phanpy/dist/assets/icons/left-line-eUw0tya4.js +0 -1
  254. package/phanpy/dist/assets/icons/lightning-line-DaKoDdix.js +0 -1
  255. package/phanpy/dist/assets/icons/link-2-line-DCqLmMA7.js +0 -1
  256. package/phanpy/dist/assets/icons/list-check-line-BAxosBh9.js +0 -1
  257. package/phanpy/dist/assets/icons/lock-line-CPoaXeUW.js +0 -1
  258. package/phanpy/dist/assets/icons/mail-line-B0P8aa1L.js +0 -1
  259. package/phanpy/dist/assets/icons/moon-line-CEqNAToP.js +0 -1
  260. package/phanpy/dist/assets/icons/more-1-fill-Dw2e5xab.js +0 -1
  261. package/phanpy/dist/assets/icons/more-3-line-BIiVjYTz.js +0 -1
  262. package/phanpy/dist/assets/icons/notification-line-BZZq2Gtu.js +0 -1
  263. package/phanpy/dist/assets/icons/pencil-line-CKh8-A1v.js +0 -1
  264. package/phanpy/dist/assets/icons/photo-album-line-Bnfg2u40.js +0 -1
  265. package/phanpy/dist/assets/icons/pin-line-DpTolyhs.js +0 -1
  266. package/phanpy/dist/assets/icons/play-fill-B0-G_8lX.js +0 -1
  267. package/phanpy/dist/assets/icons/qrcode-2-line-B6SPCaHn.js +0 -1
  268. package/phanpy/dist/assets/icons/quill-pen-line-B6LUrnCP.js +0 -1
  269. package/phanpy/dist/assets/icons/quote-left-fill-hQZ1cj_6.js +0 -1
  270. package/phanpy/dist/assets/icons/radar-line-CKyroTth.js +0 -1
  271. package/phanpy/dist/assets/icons/react-line-CoIKhhtK.js +0 -1
  272. package/phanpy/dist/assets/icons/refresh-2-line-D0mTF97S.js +0 -1
  273. package/phanpy/dist/assets/icons/right-line-B3KWJaqc.js +0 -1
  274. package/phanpy/dist/assets/icons/rocket-line-4KZl537D.js +0 -1
  275. package/phanpy/dist/assets/icons/round-fill-C69NTrZ0.js +0 -1
  276. package/phanpy/dist/assets/icons/round-line-B9k_1uo-.js +0 -1
  277. package/phanpy/dist/assets/icons/route-line-B28ReHcE.js +0 -1
  278. package/phanpy/dist/assets/icons/rows-4-line-CrBniagM.js +0 -1
  279. package/phanpy/dist/assets/icons/scan-line-DSf74YdP.js +0 -1
  280. package/phanpy/dist/assets/icons/search-2-line-B6geIU1z.js +0 -1
  281. package/phanpy/dist/assets/icons/settings-3-line-azJwK47w.js +0 -1
  282. package/phanpy/dist/assets/icons/settings-6-line-C_5zc5YR.js +0 -1
  283. package/phanpy/dist/assets/icons/share-2-line-D5MxWjrm.js +0 -1
  284. package/phanpy/dist/assets/icons/share-forward-line-Cp61fZzZ.js +0 -1
  285. package/phanpy/dist/assets/icons/sparkles-2-line-DYYyXTaW.js +0 -1
  286. package/phanpy/dist/assets/icons/sparkles-line-C2hY1s6I.js +0 -1
  287. package/phanpy/dist/assets/icons/time-line-BF3eet1v.js +0 -1
  288. package/phanpy/dist/assets/icons/transfer-4-line-oisfvTBw.js +0 -1
  289. package/phanpy/dist/assets/icons/translate-line-BFWol2Ce.js +0 -1
  290. package/phanpy/dist/assets/icons/unlock-line-X_x5vwv3.js +0 -1
  291. package/phanpy/dist/assets/icons/upload-3-line-DgzwUJeW.js +0 -1
  292. package/phanpy/dist/assets/icons/user-4-line-BVSynZCp.js +0 -1
  293. package/phanpy/dist/assets/icons/user-add-2-line-BlGS5Q8q.js +0 -1
  294. package/phanpy/dist/assets/icons/user-add-line-BbXdHG4z.js +0 -1
  295. package/phanpy/dist/assets/icons/user-edit-line-BFAHOV0X.js +0 -1
  296. package/phanpy/dist/assets/icons/user-follow-line-BXux0wSd.js +0 -1
  297. package/phanpy/dist/assets/icons/user-star-line-DdYlpHLU.js +0 -1
  298. package/phanpy/dist/assets/icons/user-warning-line-Cj43j0_E.js +0 -1
  299. package/phanpy/dist/assets/icons/user-x-line-DIDgNlPH.js +0 -1
  300. package/phanpy/dist/assets/icons/volume-line-Bs390KQt.js +0 -1
  301. package/phanpy/dist/assets/icons/volume-mute-line-DzlzIqFZ.js +0 -1
  302. package/phanpy/dist/assets/icons/walk-line-yNXfB-md.js +0 -1
  303. package/phanpy/dist/assets/icons/world-2-line-CenkGIwj.js +0 -1
  304. package/phanpy/dist/assets/icons/zoom-in-line-CaENUphf.js +0 -1
  305. package/phanpy/dist/assets/icons/zoom-out-line-BDNk0EWo.js +0 -1
  306. package/phanpy/dist/assets/instances-BNPptnn-.json +0 -333
  307. package/phanpy/dist/assets/locales/ar-SA-CfheRbCu.js +0 -1
  308. package/phanpy/dist/assets/locales/ca-ES-DHRW86Tz.js +0 -1
  309. package/phanpy/dist/assets/locales/cs-CZ-CKoqEuA1.js +0 -1
  310. package/phanpy/dist/assets/locales/de-DE-ByRPMRFy.js +0 -1
  311. package/phanpy/dist/assets/locales/eo-UY-CPC7wLCS.js +0 -1
  312. package/phanpy/dist/assets/locales/es-ES-dJa0Fd9t.js +0 -1
  313. package/phanpy/dist/assets/locales/eu-ES-C3djlPR2.js +0 -1
  314. package/phanpy/dist/assets/locales/fa-IR-DTT490Ck.js +0 -1
  315. package/phanpy/dist/assets/locales/fi-FI-B23MCPuz.js +0 -1
  316. package/phanpy/dist/assets/locales/fr-FR-BcaQsO5C.js +0 -1
  317. package/phanpy/dist/assets/locales/gl-ES-BR-CVKBN.js +0 -1
  318. package/phanpy/dist/assets/locales/he-IL-CfheRbCu.js +0 -1
  319. package/phanpy/dist/assets/locales/hu-HU-CfheRbCu.js +0 -1
  320. package/phanpy/dist/assets/locales/it-IT-C1136UFV.js +0 -1
  321. package/phanpy/dist/assets/locales/ja-JP-CRZmRAhD.js +0 -1
  322. package/phanpy/dist/assets/locales/kab-Cz8xH_TT.js +0 -1
  323. package/phanpy/dist/assets/locales/ko-KR-CG9UiY4o.js +0 -1
  324. package/phanpy/dist/assets/locales/lt-LT-CJcI6sHZ.js +0 -1
  325. package/phanpy/dist/assets/locales/nb-NO-CfheRbCu.js +0 -1
  326. package/phanpy/dist/assets/locales/nl-NL-DxN4Yc1t.js +0 -1
  327. package/phanpy/dist/assets/locales/oc-FR-CfheRbCu.js +0 -1
  328. package/phanpy/dist/assets/locales/pl-PL-DkwGXf6P.js +0 -1
  329. package/phanpy/dist/assets/locales/pseudo-LOCALE-CQ4XxkQ0.js +0 -1
  330. package/phanpy/dist/assets/locales/pt-BR-nGL0HdFS.js +0 -1
  331. package/phanpy/dist/assets/locales/pt-PT-Cp17aj2z.js +0 -1
  332. package/phanpy/dist/assets/locales/ru-RU-0Y8cIoaK.js +0 -1
  333. package/phanpy/dist/assets/locales/th-TH-CfheRbCu.js +0 -1
  334. package/phanpy/dist/assets/locales/tok-CfheRbCu.js +0 -1
  335. package/phanpy/dist/assets/locales/tr-TR-CfheRbCu.js +0 -1
  336. package/phanpy/dist/assets/locales/uk-UA-C5E3dFBf.js +0 -1
  337. package/phanpy/dist/assets/locales/zh-CN-BHJi7_et.js +0 -1
  338. package/phanpy/dist/assets/locales/zh-TW-CfheRbCu.js +0 -1
  339. package/phanpy/dist/assets/main-BdqNbG-a.js +0 -26
  340. package/phanpy/dist/assets/main-BdqNbG-a.js.map +0 -1
  341. package/phanpy/dist/assets/mock-home-DGhR__He.js +0 -2
  342. package/phanpy/dist/assets/mock-home-DGhR__He.js.map +0 -1
  343. package/phanpy/dist/assets/multi-column-ROck0NVt.jpg +0 -0
  344. package/phanpy/dist/assets/multi-hashtag-timeline-DH5INVHi.jpg +0 -0
  345. package/phanpy/dist/assets/nested-comments-thread-hv59kZLc.jpg +0 -0
  346. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js +0 -2
  347. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js.map +0 -1
  348. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js +0 -20
  349. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js.map +0 -1
  350. package/phanpy/dist/assets/style-B1iLPTPR.css +0 -2
  351. package/phanpy/dist/assets/temml-DuyIQMei.js +0 -97
  352. package/phanpy/dist/assets/temml-DuyIQMei.js.map +0 -1
  353. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js +0 -2
  354. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js.map +0 -1
  355. package/phanpy/dist/assets/year-in-posts-B2lywqdx.png +0 -0
  356. package/phanpy/dist/assets/year-in-posts-DJv_star.js +0 -3
  357. package/phanpy/dist/assets/year-in-posts-DJv_star.js.map +0 -1
  358. package/phanpy/dist/compose/index.html +0 -20
  359. package/phanpy/dist/favicon.ico +0 -0
  360. package/phanpy/dist/index.html +0 -73
  361. package/phanpy/dist/logo-192.png +0 -0
  362. package/phanpy/dist/logo-512.png +0 -0
  363. package/phanpy/dist/logo-badge-72.png +0 -0
  364. package/phanpy/dist/logo-maskable-512.png +0 -0
  365. package/phanpy/dist/logo-monochrome-512.png +0 -0
  366. package/phanpy/dist/logo-monochrome-maskable-512.png +0 -0
  367. package/phanpy/dist/manifest.webmanifest +0 -1
  368. package/phanpy/dist/og-image-2.jpg +0 -0
  369. package/phanpy/dist/og-image.png +0 -0
  370. package/phanpy/dist/robots.txt +0 -2
  371. package/phanpy/dist/sw.js +0 -2
  372. package/phanpy/dist/sw.js.map +0 -1
  373. package/phanpy/dist/version.json +0 -1
  374. package/run-agent.mjs +0 -899
  375. package/vendor/gate.cjs +0 -138
  376. package/vendor/idp-grant.cjs +0 -394
  377. package/vendor/jfetch.cjs +0 -16
  378. package/web/admin/actors.js +0 -147
  379. package/web/admin/bar.css +0 -126
  380. package/web/admin/bar.js +0 -99
  381. package/web/admin/client/client.js +0 -66
  382. package/web/admin/client/index.html +0 -69
  383. package/web/admin/client-pick.js +0 -79
  384. package/web/admin/common.js +0 -23
  385. package/web/admin/connections.js +0 -112
  386. package/web/admin/gateway.js +0 -133
  387. package/web/admin/group.js +0 -258
  388. package/web/admin/index.html +0 -612
  389. package/web/admin/notices-bar.js +0 -90
  390. package/web/admin/oauth-signin.mjs +0 -37
  391. package/web/admin/record.js +0 -393
  392. package/web/admin/setup/index.html +0 -257
  393. package/web/admin/setup/setup.js +0 -339
  394. package/web/admin/tokens.css +0 -68
  395. package/web/admin/upkeep.js +0 -177
  396. package/web/admin/window.css +0 -55
  397. package/web/admin/window.js +0 -136
  398. package/web/app/README.md +0 -81
  399. package/web/app/admin-facade.mjs +0 -588
  400. package/web/app/agent.mjs +0 -672
  401. package/web/app/atproto-browser.mjs +0 -86
  402. package/web/app/authorize_interaction.html +0 -56
  403. package/web/app/authorize_interaction.js +0 -69
  404. package/web/app/boot.mjs +0 -616
  405. package/web/app/deliver-relay.mjs +0 -129
  406. package/web/app/dist/boot.js +0 -34562
  407. package/web/app/dist/boot.js.map +0 -7
  408. package/web/app/dist/sw.js +0 -73456
  409. package/web/app/dist/sw.js.map +0 -7
  410. package/web/app/fediacct-browser.mjs +0 -146
  411. package/web/app/gateway-move.mjs +0 -60
  412. package/web/app/idb-kv.mjs +0 -35
  413. package/web/app/index.html +0 -258
  414. package/web/app/keys-browser.mjs +0 -71
  415. package/web/app/keystore.mjs +0 -82
  416. package/web/app/oidc-session.mjs +0 -6
  417. package/web/app/pod-auth.mjs +0 -248
  418. package/web/app/pod-remote.mjs +0 -84
  419. package/web/app/shims/_globals.mjs +0 -2
  420. package/web/app/shims/fedify-sig.mjs +0 -77
  421. package/web/app/shims/node-crypto.mjs +0 -113
  422. package/web/app/shims/node-fs.mjs +0 -17
  423. package/web/app/shims/node-path.mjs +0 -19
  424. package/web/app/shims/node-url.mjs +0 -7
  425. package/web/app/shims/prelude.js +0 -58
  426. package/web/app/shims/safefetch.mjs +0 -58
  427. package/web/app/shims/shapes-text.mjs +0 -8
  428. package/web/app/shims/web-push.mjs +0 -14
  429. package/web/app/signup.mjs +0 -357
  430. package/web/app/sw-src.mjs +0 -220
  431. package/web/app/update.js +0 -70
  432. package/web/front/admin.html +0 -55
  433. package/web/front/admin.js +0 -89
  434. package/web/front/install.sh +0 -69
  435. package/web/front/new-account.html +0 -35
  436. package/web/front/new-account.js +0 -13
  437. package/web/front/notices.html +0 -69
  438. package/web/front/notices.js +0 -107
  439. package/web/front/run.html +0 -64
  440. package/web/front/run.js +0 -221
  441. package/web/front/solid-oidc-client.js +0 -6
  442. package/web/icons/forum.svg +0 -11
  443. package/web/icons/gateway.svg +0 -14
  444. package/web/icons/local.svg +0 -11
@@ -1,522 +0,0 @@
1
- // publisher.mjs — builds/maintains the actor's public face on the remote pod:
2
- // webfinger, actor doc, collections, notes. The /ap/ tree is disposable:
3
- // publishProfile() rebuilds it.
4
- //
5
- // This file is the actor's public face — the actor document, discovery,
6
- // ACLs, the inbox posture, Move and retire. The rest is in the modules
7
- // beside it: collections.mjs (the published collections and the outbox
8
- // record), restore.mjs (catching up with the pod), notes.mjs (a note going
9
- // up), questions.mjs (polls) — each a set of functions taking the Publisher
10
- // as their first argument, reached here through one-line delegations.
11
-
12
- import fs from 'node:fs';
13
- import path from 'node:path';
14
- import { fileURLToPath } from 'node:url';
15
- import crypto from 'node:crypto';
16
- import * as wire from '../wire.mjs';
17
- import { USER_AGENT } from '../../shared/ua.mjs';
18
- import { HTTP_TIMEOUT_MS } from '../../shared/safefetch.mjs';
19
- import * as containers from '../../pod/containers.mjs';
20
- import * as discovery from '../../pod/discovery.mjs';
21
- import * as podActor from '../../pod/actor.mjs';
22
- import * as podInbox from '../../pod/inbox.mjs';
23
- import * as podFeatured from '../../pod/featured.mjs';
24
- import * as podPolicy from '../../pod/policy.mjs';
25
- import * as podNotes from '../../pod/notes.mjs';
26
- import * as collections from './collections.mjs';
27
- import { ALL_COLLECTIONS } from './collections.mjs';
28
- import * as restore from './restore.mjs';
29
- import * as notes from './notes.mjs';
30
- import * as questions from './questions.mjs';
31
- import * as own from './own.mjs';
32
- import { recordPlace } from '../place.mjs';
33
-
34
- const AGENT_VERSION = JSON.parse(fs.readFileSync(
35
- path.join(path.dirname(fileURLToPath(import.meta.url)), '../../../package.json'), 'utf8')).version;
36
-
37
- export class Publisher {
38
- constructor({ config, remote, store, deliverer, publicKeyPem, assertionKey = null, log = console.log,
39
- probeFetch = null, resolveMention = null, resolveActor = null, clientOrigin = null,
40
- }) {
41
- this.config = config;
42
- this.remote = remote;
43
- this.store = store;
44
- this.deliverer = deliverer;
45
- // Everything this actor sends goes on the outbox its owner reads.
46
- if (deliverer) deliverer.onSent = (a) => own.recordOwn(this, a);
47
- this.publicKeyPem = publicKeyPem;
48
- this.assertionKey = assertionKey; // Ed25519 public half, multibase; null = no proofs
49
- // Where this identity's client surface answers, when that is an address a
50
- // stranger can reach. Null on a laptop, where the surface is on loopback
51
- // and advertising it to the world would name somewhere nobody can go.
52
- this.clientOrigin = clientOrigin;
53
- // A fronted identity (config.gateway.frontActor) advertises its ids on a
54
- // shared domain; the map tells RemotePod where each writes on the pod.
55
- const publicBase = config.gateway?.frontActor
56
- ? config.gateway.frontActor.replace(/ap\/actor\/?$/, '') : null;
57
- this.urls = wire.apUrls(config.remotePod, config.root, { publicBase });
58
- if (this.urls.toPod && this.remote?.setUrlMap) this.remote.setUrlMap(this.urls.toPod);
59
- // Credential-free by design — it asks what a stranger sees — but routed
60
- // through the pod's own cooldown and accounting, because it is still a
61
- // socket opened to that pod. Tests inject their own.
62
- this.probeFetch = probeFetch || ((u, i) => this.remote.probe(u, i));
63
- this.resolveMention = resolveMention;
64
- // An actor or object by its address, verified at its origin — how a reply
65
- // finds the inbox of the person it answers.
66
- this.resolveActor = resolveActor;
67
- // Per-poll rewrite windows, keyed by question id. See POLL_REWRITE_MS.
68
- this.pollTimers = new Map();
69
- this.log = log;
70
- }
71
-
72
- // Idempotent: (re)write webfinger + actor + collections + container ACLs.
73
- //
74
- // ~34 pod requests, so it does not run when it would rewrite the same bytes.
75
- // Every document below is derived from the actor doc, the handle, the host,
76
- // whether the actor is quiesced (which decides the inbox ACL) and the agent
77
- // version (which rides in nodeinfo) — so if none of those moved, there is
78
- // nothing to say. Phanpy's editor submits the whole form on every save, so
79
- // "saved without changing anything" is the common case, not a rare one.
80
- //
81
- // `force` is for the callers that publish precisely BECAUSE the pod does not
82
- // have what the digest says it has: the repair path, and the explicit
83
- // republish button. Without it, an actor lost from the pod would match the
84
- // digest, be skipped, and leave the agent reporting success while nobody can
85
- // resolve it.
86
- // The Gateway's outbox door for this account, when a Gateway is attached:
87
- // beside its inbox door, or under the fronted actor.
88
- gatewayOutbox() {
89
- const gw = this.config.gateway;
90
- if (!(gw && gw.url && gw.mode && gw.mode !== 'off')) return null;
91
- if (gw.frontActor) return String(gw.frontActor).replace(/ap\/actor\/?$/u, 'ap/outbox');
92
- return String(gw.url).replace(/ap\/inbox\/?$/u, 'ap/outbox');
93
- }
94
-
95
- // Every actor document this identity publishes, from one place: the
96
- // profile publish and a Move both write it, and a Move that rebuilt it
97
- // by hand dropped the gateway inbox, the outbox door and the collections.
98
- // `clientOrigin` is overridden only by the agent serving a client its own
99
- // local actor: standalone, the published document cannot name a loopback
100
- // address, but a client already talking to that address can be told it.
101
- actorDocFor({ priv = false, moderators = null, inbox = null, movedTo = this.config.movedTo || null,
102
- clientOrigin = this.clientOrigin } = {}) {
103
- const { urls } = this;
104
- return wire.actorDoc({
105
- urls, handle: wire.publicHandle(this.config), name: this.config.name, publicKeyPem: this.publicKeyPem,
106
- movedTo, kind: this.config.kind,
107
- approveJoins: wire.followsNeedApproval(this.config),
108
- assertionKey: this.assertionKey,
109
- summary: this.config.summary || null, icon: this.config.icon || null,
110
- image: this.config.image || null, fields: this.config.fields || [],
111
- webId: this.remote.webId || null,
112
- aliases: this.config.aliases || [],
113
- // A group says whether only its moderators may open posts (Lemmy's
114
- // term); a person's actor carries nothing of the kind.
115
- postingRestrictedToMods: this.config.kind === 'group' ? !!this.config.postingRestrictedToMods : null,
116
- moderators,
117
- pendingFollowers: priv ? urls.pendingFollowers : null,
118
- // Named only where the private folder is proved to keep it private.
119
- liked: priv ? urls.liked : null,
120
- ownerOutbox: priv ? urls.ownOutbox : null,
121
- pendingFollowing: priv ? urls.pendingFollowing : null,
122
- blocked: priv ? urls.blocked : null,
123
- inbox,
124
- // The agent's own outbox endpoint, where it is reachable: a client
125
- // following the actor must arrive somewhere that will take a write.
126
- // Otherwise the Gateway's outbox door, when one is attached.
127
- outbox: clientOrigin ? `${clientOrigin}ap/outbox` : this.gatewayOutbox(),
128
- // How a client-to-server client finds the way in with nothing configured
129
- // by hand. Advertised only where the surface is publicly reachable.
130
- oauthAuthorize: clientOrigin ? `${clientOrigin}oauth/authorize` : null,
131
- oauthToken: clientOrigin ? `${clientOrigin}oauth/token` : null,
132
- });
133
- }
134
-
135
- // The human half: a page a browser can open and follow from. The actor
136
- // document is for servers; this is the address you hand to a person. It
137
- // shows who the account is, its fields, when it joined and what it pinned;
138
- // the counts and the posts live in the collections. Written only when its
139
- // content changed.
140
- async publishProfilePage({ force = false } = {}) {
141
- const { urls } = this;
142
- const host = new URL(urls.base).host;
143
- // When the account was made. Accounts from before this was recorded take
144
- // the date of their oldest post, or today.
145
- if (!this.config.createdAt) {
146
- const oldest = this.store.getStatuses().filter(s => s.kind === 'post' && s.published)
147
- .map(s => s.published).sort()[0];
148
- this.config.createdAt = oldest || new Date().toISOString();
149
- this.store.setConfig?.({ ...this.store.getConfig?.(), createdAt: this.config.createdAt });
150
- }
151
- const pinned = this.store.getStatuses()
152
- .filter(s => s.kind === 'post' && s.pinned && s.visibility !== 'private' && s.visibility !== 'direct')
153
- .sort((a, b) => String(b.published).localeCompare(String(a.published)))
154
- .slice(0, 5)
155
- .map(s => ({ content: s.content, published: s.published, url: s.noteId }));
156
- // The address as the world knows it: at the Gateway for a fronted
157
- // identity, on the pod's host otherwise, the actor id where no host can
158
- // answer for a handle.
159
- const frontActor = this.config.gateway?.frontActor;
160
- const address = frontActor ? `@${wire.publicHandle(this.config)}@${new URL(frontActor).host}`
161
- : (wire.webfingerHost(urls.base) ? `@${this.config.handle}@${host}` : urls.actor);
162
- const html = wire.profilePageHtml({
163
- name: this.config.name || this.config.handle,
164
- address,
165
- summary: this.config.summary ? wire.contentHtml(this.config.summary) : null,
166
- icon: this.config.icon || null,
167
- image: this.config.image || null,
168
- fields: this.config.fields || [],
169
- joined: this.config.createdAt,
170
- pinned,
171
- kind: this.config.kind,
172
- });
173
- const digest = crypto.createHash('sha256').update(html).digest('hex').slice(0, 32);
174
- const seen = this.store.read('published.json', {});
175
- if (!force && seen.pageDigest === digest) return false;
176
- await podActor.writeProfilePage(this.remote, urls, html);
177
- this.store.write('published.json', { ...this.store.read('published.json', {}), pageDigest: digest });
178
- return true;
179
- }
180
-
181
- async publishProfile({ force = false } = {}) {
182
- const { urls } = this;
183
- const host = new URL(urls.base).host;
184
-
185
- // The owner-only collections (FEP-4ccd, FEP-c648) are advertised only
186
- // where "owner-only" is real — the pod must provably enforce the private
187
- // container's ACL, the same bar private posts clear.
188
- const priv = await this.privateReady() === true;
189
- const moderators = (this.config.moderators || []).length ? urls.moderators : null;
190
- // An advertised inbox gateway (config.gateway.mode past 'off') becomes the
191
- // actor's inbox; deliveries reach the pod inbox through it. Absent → today.
192
- const gw = this.config.gateway;
193
- const gwActive = gw && gw.url && gw.mode && gw.mode !== 'off';
194
- // A forum's category advertises the forum's one inbox (config.inboxUrl):
195
- // deliveries to any category land there, and the forum routes them.
196
- const actorDoc = this.actorDocFor({ priv, moderators, inbox: gwActive ? gw.url : (this.config.inboxUrl || null) });
197
- const surface = crypto.createHash('sha256').update(JSON.stringify({
198
- actor: actorDoc, handle: this.config.handle, host,
199
- quiesced: !!this.config.quiescedAt, version: AGENT_VERSION,
200
- moderators: this.config.moderators || [],
201
- })).digest('hex').slice(0, 32);
202
- // The human page has its own gate: it changes with pins and the joined
203
- // date as well as with the profile, and costs one write when it does.
204
- await this.publishProfilePage({ force });
205
- if (!force && this.store.read('published.json', {}).surfaceDigest === surface) {
206
- this.log('profile unchanged — nothing republished');
207
- return { unreachable: [], updated: 0, skipped: true };
208
- }
209
-
210
- // Discovery is the pod's, and a pod has one WebFinger document: a forum's
211
- // category (config.forum names the forum) is not the pod's identity, so it
212
- // writes none — the forum's own actor, or a Gateway, answers for it.
213
- if (!this.config.forum) {
214
- await discovery.writeWebfinger(this.remote, urls,
215
- wire.jrd({ handle: this.config.handle, host, actor: urls.actor, page: urls.profileHtml }));
216
- await discovery.writeHostMeta(this.remote, urls, wire.hostMeta(urls.base));
217
-
218
- const nodeinfoDocUrl = urls.home + 'ap/nodeinfo-2.0';
219
- const localPosts = this.store.getStatuses().filter(s => s.kind === 'post').length;
220
- await discovery.writeNodeinfo(this.remote, urls, {
221
- pointer: wire.nodeinfoPointer(nodeinfoDocUrl),
222
- doc: wire.nodeinfoDoc({ version: AGENT_VERSION, localPosts }),
223
- });
224
- }
225
-
226
- const actor = actorDoc; // built above, for the digest
227
- await podActor.write(this.remote, urls, actor);
228
-
229
- // FEP-1b12: the moderator roster, public — it is what a recipient
230
- // validates a group's announced moderation against.
231
- if (moderators) {
232
- await podFeatured.writeModerators(this.remote, urls,
233
- wire.orderedCollection(urls.moderators, this.config.moderators));
234
- }
235
- // The gateway policy doc: the PUBLIC data a keyless gateway reads to decide
236
- // what concerns this identity. Written only while a gateway is advertised.
237
- if (gwActive) await this.publishGatewayPolicy();
238
-
239
- // WebID → actor: the profile card lists the actor as a foaf:account.
240
- // Best-effort — a profile that cannot be read or edited does not stop the
241
- // publish, it is logged and the rest of the surface still goes up.
242
- if (this.config.forum) { /* a category is not the pod owner's account */ } else try {
243
- const wrote = await podActor.linkInWebIdProfile(this.remote, {
244
- actorUrl: urls.actor,
245
- accountName: `@${this.config.handle}@${host}`,
246
- kind: this.config.kind,
247
- // Where a Solid client posts: dokieli reads `as:outbox` off the WebID.
248
- outbox: this.clientOrigin ? `${this.clientOrigin}ap/outbox` : this.gatewayOutbox(),
249
- });
250
- if (wrote) this.log('WebID profile now lists the actor as a foaf:account');
251
- } catch (e) {
252
- this.log(`WebID profile not updated with the actor link: ${e.message}`);
253
- }
254
- // Where the account lives, in the owner's public type index — only where
255
- // they already have one; an index is made only on their yes, at sign-up.
256
- if (!this.config.forum) {
257
- await recordPlace(this.remote, urls.base, urls.home + 'ap/actor')
258
- .then((r) => { if (r === 'registered') this.log('the public type index now records where the account lives'); })
259
- .catch((e) => this.log(`type index not updated with the account's place: ${e.message}`));
260
- }
261
-
262
- // inbox: public may only Append; owner (the agent) reads + drains. A
263
- // quiesced actor keeps its name resolving but takes no more mail, so a
264
- // republish must not re-open the door.
265
- await podInbox.writeKeep(this.remote, urls);
266
- await podInbox.setPosture(this.remote, urls, this.config.quiescedAt ? 'closed' : 'open');
267
- if (this.config.quiescedAt) this.log('inbox left closed — this actor is quiesced');
268
-
269
- // notes live under a public-Read container (acl:default covers new notes).
270
- await podNotes.provisionContainer(this.remote, urls);
271
-
272
- await this.publishCollections({ ...ALL_COLLECTIONS, force });
273
- const updated = await this.announceProfileChange(actor, { force });
274
- await this.ensurePrivateAcls();
275
- const unreachable = await this.verifyPublicSurface();
276
- // Last, and merged: announceProfileChange writes this document too.
277
- //
278
- // Only when the surface came back readable. Recording it regardless meant a
279
- // publish that half-landed still matched the digest, so the NEXT save — the
280
- // one the operator makes because the first did not work — was skipped as a
281
- // no-op and reported success. The digest is a record of what is up there,
282
- // and an unreachable document is not up there.
283
- if (!unreachable.length) {
284
- this.store.write('published.json',
285
- { ...this.store.read('published.json', {}), surfaceDigest: surface });
286
- }
287
- // Named as the fediverse sees it: a fronted actor's name and host are the
288
- // front's, not the pod's.
289
- const pubName = wire.publicHandle(this.config);
290
- const pubHost = this.config.gateway?.frontActor ? new URL(this.config.gateway.frontActor).host : host;
291
- this.log(this.config.gateway?.frontActor || wire.webfingerHost(urls.base)
292
- ? `profile published: @${pubName}@${pubHost} → ${urls.actor}`
293
- : `profile published → ${urls.actor} — NOT discoverable as @${pubName}@${pubHost}: `
294
- + 'this pod is suffixed, and WebFinger is only answered for a subdomained pod');
295
- return { unreachable, updated };
296
- }
297
-
298
- // Fires when the document differs from the one last published — including
299
- // the first time, when there is nothing to differ from.
300
- //
301
- // Every call to publishProfile is already a DELIBERATE republish: setup, a
302
- // rename, an edit through the client or /config, `describe`, a key rotation,
303
- // or an actor document found missing from the pod. Starting the agent does not
304
- // call it. So the digest is not there to survive restarts — it is there for
305
- // the republish that changes nothing, which /config does whenever you save a
306
- // field the actor document does not carry.
307
- //
308
- // A silent first publish was considered and is WRONG here: it would spend a
309
- // real edit doing nothing but recording a digest, and that edit is exactly the
310
- // one whose invisibility this fixes.
311
- async announceProfileChange(actor, { force = false } = {}) {
312
- const digest = crypto.createHash('sha256').update(JSON.stringify(actor)).digest('hex').slice(0, 32);
313
- const seen = this.store.read('published.json', {});
314
- // A forced republish is the operator saying TELL THE WORLD — the digest
315
- // gate is for silent no-op saves, not for that.
316
- if (seen.actorDigest === digest && !force) return 0;
317
- this.store.write('published.json', { ...seen, actorDigest: digest, at: new Date().toISOString() });
318
- const inboxes = [...new Set(this.store.getContacts().followers
319
- .map(f => f.sharedInbox || f.inbox).filter(Boolean))];
320
- if (!inboxes.length) return 0;
321
- await this.deliverer.deliverToAll(inboxes,
322
- wire.updateActorActivity({ urls: this.urls, actor, serial: Date.now() }));
323
- this.log(`profile changed — Update delivered to ${inboxes.length} inbox(es)`);
324
- return inboxes.length;
325
- }
326
-
327
- // The mirror of ensurePrivateAcls, and the check this project lacked: these
328
- // documents MUST be readable by strangers or no server can see the actor.
329
- // A publish that dies half-way, or an ACL write that is accepted without
330
- // taking effect, is otherwise indistinguishable from success — the agent
331
- // reports itself configured and federating while nobody can find it.
332
- async verifyPublicSurface() {
333
- const { urls } = this;
334
- const targets = [
335
- // Discovery documents are the pod's, not a forum category's (see publishProfile).
336
- ...(this.config.forum ? [] : [['webfinger', urls.webfinger], ['host-meta', urls.base + '.well-known/host-meta']]),
337
- ['actor', urls.actor],
338
- ['notes', urls.notes],
339
- ['followers', urls.followers],
340
- ['following', urls.following],
341
- ['featured', urls.featured],
342
- ['outbox', urls.outbox],
343
- ];
344
- const unreachable = [];
345
- for (const [name, url] of targets) {
346
- if (!await this.publiclyReadable(url)) unreachable.push(name);
347
- }
348
- if (unreachable.length) {
349
- this.log(`FEDERATION: ${unreachable.join(', ')} not readable without credentials — `
350
- + 'other servers cannot resolve or fetch this actor');
351
- }
352
- return unreachable;
353
- }
354
-
355
- // An ACL write that silently failed — or was changed afterwards by anything
356
- // else touching the pod — leaves the private trees, signing keys included,
357
- // world-readable. bootstrap writes them once at setup and never returns, so
358
- // this runs on every connect: probe UNauthenticated, rewrite whatever
359
- // answers, and say so loudly if the rewrite does not take.
360
- async ensurePrivateAcls() {
361
- const findings = await containers.repairPrivateAcls(this.remote,
362
- [this.urls.home, this.urls.state],
363
- { isPublic: (u) => this.publiclyReadable(u) });
364
- // What a finding MEANS is ours to say; the library just reports.
365
- for (const f of findings) {
366
- this.log(`${f.url} was readable without credentials — rewriting its ACL`);
367
- if (f.error) { this.log(`SECURITY: ${f.url} is public and its ACL could not be rewritten: ${f.error}`); continue; }
368
- if (f.stillPublic) this.log(`SECURITY: ${f.url} is STILL readable without credentials — check the pod's ACLs`);
369
- }
370
- }
371
-
372
- // Deliberately credential-free: this asks what a stranger would see.
373
- // accept: */* matters — asking for turtle makes the server answer 501 on the
374
- // JSON documents (webfinger, actor), which reads as "unreachable" when the
375
- // world can in fact see them perfectly well.
376
- publiclyReadable(url) {
377
- return containers.probePublicReadability(this.probeFetch, url,
378
- { headers: { 'user-agent': USER_AGENT }, timeoutMs: HTTP_TIMEOUT_MS });
379
- }
380
-
381
- // Retire this identity for good: tell everyone who follows us to drop the
382
- // account, then leave a Tombstone where the actor was. The inbox stays
383
- // publicly Append-able on purpose — closing it would make deliveries 401,
384
- // which Mastodon treats as failure and retries, the opposite of the point.
385
- // A Delete stops well-behaved servers; anything that keeps delivering gets a
386
- // cheap 201 into a container we no longer read.
387
- async retireActor() {
388
- const { urls } = this;
389
- const contacts = this.store.getContacts();
390
- const inboxes = [...new Set(contacts.followers.map(f => f.sharedInbox || f.inbox).filter(Boolean))];
391
- const deletedAt = new Date().toISOString();
392
- await this.deliverer.deliverToAll(inboxes, wire.deleteActorActivity(urls, Date.parse(deletedAt)));
393
- await podActor.writeTombstone(this.remote, urls, wire.tombstoneDoc(urls, deletedAt, this.config.kind));
394
- this.store.setConfig({ ...this.store.getConfig(), retiredAt: deletedAt });
395
- await this.store.flush();
396
- this.log(`retired: Delete sent to ${inboxes.length} inbox(es), actor replaced with a Tombstone`);
397
- return { inboxes: inboxes.length, deletedAt };
398
- }
399
-
400
- // Stop accepting mail without giving up the name: deliveries get an immediate
401
- // 401 rather than a 201 into storage nobody will ever drain. WebFinger,
402
- // host-meta and the actor stay published, so the handle still resolves.
403
- async closeInbox() {
404
- await podInbox.setPosture(this.remote, this.urls, 'closed');
405
- const at = new Date().toISOString();
406
- this.store.setConfig({ ...this.store.getConfig(), quiescedAt: at });
407
- await this.store.flush();
408
- this.log(`inbox closed — @${this.config.handle} still resolves but accepts nothing`);
409
- return at;
410
- }
411
-
412
- // Undo closeInbox: mail flows again and the actor is no longer quiesced.
413
- async openInbox() {
414
- await podInbox.setPosture(this.remote, this.urls, 'open');
415
- const { quiescedAt, ...rest } = this.store.getConfig() || {};
416
- this.store.setConfig(rest);
417
- this.config.quiescedAt = undefined;
418
- await this.store.flush();
419
- this.log(`inbox re-opened — @${this.config.handle} is taking mail again`);
420
- }
421
-
422
- // Lock the inbox to a gateway: the public loses Append, so nothing reaches
423
- // the pod except through the gateway's verify-at-the-door. Reversible with
424
- // openInbox (public-Append) — the one-call rollback.
425
- async lockInboxToGateway(gatewayWebId) {
426
- await podInbox.setPosture(this.remote, this.urls, { gatewayWebId });
427
- this.log(`inbox locked to gateway ${gatewayWebId} — public delivery is refused`);
428
- }
429
-
430
- // Tell the fediverse the account lives somewhere else now. Well-behaved
431
- // servers migrate their followers to the target and stop delivering here.
432
- async publishMove(target) {
433
- const { urls } = this;
434
- const contacts = this.store.getContacts();
435
- const inboxes = [...new Set(contacts.followers.map(f => f.sharedInbox || f.inbox).filter(Boolean))];
436
- const at = new Date().toISOString();
437
- await this.deliverer.deliverToAll(inboxes, wire.moveActivity(urls, target, Date.parse(at)));
438
- this.config.movedTo = target; // so the republish below carries it
439
- this.store.setConfig({ ...this.store.getConfig(), movedTo: target, movedAt: at });
440
- const gw = this.config.gateway;
441
- const gwActive = gw && gw.url && gw.mode && gw.mode !== 'off';
442
- const priv = await this.privateReady() === true;
443
- const moderators = (this.config.moderators || []).length ? urls.moderators : null;
444
- await podActor.writeMoved(this.remote, urls, this.actorDocFor({
445
- priv, moderators, inbox: gwActive ? gw.url : null, movedTo: target,
446
- }));
447
- await this.store.flush();
448
- this.log(`moved to ${target}: Move sent to ${inboxes.length} inbox(es), actor now advertises movedTo`);
449
- return { inboxes: inboxes.length, target, movedAt: at };
450
- }
451
-
452
- // The gateway policy: a small PUBLIC document a keyless inbox gateway reads
453
- // to decide, at the edge, what to forward and what to drop. It carries only
454
- // public facts — the actor/followers URLs, the REAL pod inbox to forward to,
455
- // the accepted-following list (already public) and a mirror of the blocklist.
456
- // Publishing the blocklist here makes it public; that is a deliberate part of
457
- // running a gateway, surfaced to the operator in the admin UI.
458
- async publishGatewayPolicy() {
459
- const { urls } = this;
460
- const contacts = this.store.getContacts();
461
- const bl = this.store.getBlocklist();
462
- await podPolicy.write(this.remote, urls, {
463
- v: 1,
464
- actorUrl: urls.actor,
465
- followersUrl: urls.followers,
466
- followingUrl: urls.following,
467
- inboxUrl: urls.inbox, // the pod inbox the gateway forwards to
468
- notesPrefix: urls.notes,
469
- kind: this.config.kind || 'person',
470
- following: contacts.following.filter(f => f.accepted && !f.bsky).map(f => f.actor),
471
- blocklist: { domains: bl.domains || [], actors: bl.actors || [] },
472
- });
473
- }
474
-
475
- // collections.mjs
476
- publishOutbox(...a) { return collections.publishOutbox(this, ...a); }
477
- readPublishedOutbox(...a) { return collections.readPublishedOutbox(this, ...a); }
478
- publishFollowers(...a) { return collections.publishFollowers(this, ...a); }
479
- readPublishedFollowers(...a) { return collections.readPublishedFollowers(this, ...a); }
480
- publishCollections(...a) { return collections.publishCollections(this, ...a); }
481
- publishPending(...a) { return collections.publishPending(this, ...a); }
482
- publishBlocked(...a) { return collections.publishBlocked(this, ...a); }
483
- recordOutbox(...a) { return collections.recordOutbox(this, ...a); }
484
- unrecordOutbox(...a) { return collections.unrecordOutbox(this, ...a); }
485
- recordOwn(...a) { return own.recordOwn(this, ...a); }
486
- backfillLiked() { return own.backfillLiked(this); }
487
- inboxesFor(...a) { return notes.inboxesFor(this, ...a); }
488
- noteToSelf(...a) { return notes.noteToSelf(this, ...a); }
489
- updateObject(...a) { return notes.updateObject(this, ...a); }
490
- unrecordOwn(...a) { return own.unrecordOwn(this, ...a); }
491
- publishOwn(...a) { return own.publishOwn(this, ...a); }
492
- ownSettled() { return own.ownSettled(this); }
493
- publishFeatured(...a) { return collections.publishFeatured(this, ...a); }
494
-
495
- // restore.mjs
496
- reconcileFollowers(...a) { return restore.reconcileFollowers(this, ...a); }
497
- reconcileOutbox(...a) { return restore.reconcileOutbox(this, ...a); }
498
- rebuildStatuses(...a) { return restore.rebuildStatuses(this, ...a); }
499
- healStatuses(...a) { return restore.healStatuses(this, ...a); }
500
-
501
- // notes.mjs
502
- ensureMediaContainer(...a) { return notes.ensureMediaContainer(this, ...a); }
503
- _containerExists(...a) { return notes.containerExists(this, ...a); }
504
- ensurePrivateContainer(...a) { return notes.ensurePrivateContainer(this, ...a); }
505
- privateReady(...a) { return notes.privateReady(this, ...a); }
506
- _mentionsFor(...a) { return notes.mentionsFor(this, ...a); }
507
- publishNote(...a) { return notes.publishNote(this, ...a); }
508
- authorizeQuote(...a) { return notes.authorizeQuote(this, ...a); }
509
- withdrawQuote(...a) { return notes.withdrawQuote(this, ...a); }
510
- grantQuote(...a) { return notes.grantQuote(this, ...a); }
511
- publishObject(...a) { return notes.publishObject(this, ...a); }
512
- updateNote(...a) { return notes.updateNote(this, ...a); }
513
-
514
- // questions.mjs
515
- publishQuestion(...a) { return questions.publishQuestion(this, ...a); }
516
- _pollActivity(...a) { return questions.pollActivity(this, ...a); }
517
- recordVote(...a) { return questions.recordVote(this, ...a); }
518
- _pollDirty(...a) { return questions.pollDirty(this, ...a); }
519
- republishPoll(...a) { return questions.republishPoll(this, ...a); }
520
- closeDuePolls(...a) { return questions.closeDuePolls(this, ...a); }
521
- stopPolls(...a) { return questions.stopPolls(this, ...a); }
522
- }