fedipod-server 0.29.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (440) hide show
  1. package/README.md +11 -6
  2. package/dist/door.d.ts +4 -0
  3. package/dist/door.js +31 -0
  4. package/dist/fedipod.d.ts +16 -0
  5. package/dist/fedipod.js +13 -0
  6. package/dist/front.d.ts +3 -0
  7. package/dist/front.js +94 -0
  8. package/dist/handler.d.ts +36 -101
  9. package/dist/handler.js +85 -645
  10. package/dist/handler.jsonld +2 -30
  11. package/dist/identities.d.ts +62 -0
  12. package/dist/identities.js +236 -0
  13. package/dist/mounts.d.ts +43 -0
  14. package/dist/mounts.js +123 -0
  15. package/dist/opt-in.d.ts +46 -0
  16. package/dist/opt-in.js +176 -0
  17. package/package.json +10 -18
  18. package/lib/client/c2s.mjs +0 -636
  19. package/lib/client/localapi.mjs +0 -87
  20. package/lib/client/masto/accounts.mjs +0 -310
  21. package/lib/client/masto/body.mjs +0 -156
  22. package/lib/client/masto/index.mjs +0 -206
  23. package/lib/client/masto/instance.mjs +0 -112
  24. package/lib/client/masto/media.mjs +0 -79
  25. package/lib/client/masto/oauth.mjs +0 -656
  26. package/lib/client/masto/render.mjs +0 -518
  27. package/lib/client/masto/statuses.mjs +0 -372
  28. package/lib/client/masto/timelines.mjs +0 -438
  29. package/lib/client/oidc-auth.mjs +0 -62
  30. package/lib/client/streaming.mjs +0 -154
  31. package/lib/client/webpush.mjs +0 -98
  32. package/lib/connections/acctfeed.mjs +0 -257
  33. package/lib/connections/atproto.mjs +0 -309
  34. package/lib/connections/bskyfeed.mjs +0 -243
  35. package/lib/connections/bskygroup.mjs +0 -162
  36. package/lib/connections/fediacct.mjs +0 -253
  37. package/lib/connections/import.mjs +0 -357
  38. package/lib/connections/tagfeed.mjs +0 -212
  39. package/lib/connections/vault.mjs +0 -114
  40. package/lib/core/as2.mjs +0 -206
  41. package/lib/core/contexts/activitystreams.json +0 -379
  42. package/lib/core/contexts/anno.json +0 -126
  43. package/lib/core/contexts/did-v1.json +0 -57
  44. package/lib/core/contexts/fep-5711.json +0 -36
  45. package/lib/core/contexts/gotosocial.json +0 -86
  46. package/lib/core/contexts/identity-v1.json +0 -152
  47. package/lib/core/contexts/index.mjs +0 -63
  48. package/lib/core/contexts/join-lemmy.json +0 -33
  49. package/lib/core/contexts/joinmastodon.json +0 -28
  50. package/lib/core/contexts/litepub-0.1.json +0 -60
  51. package/lib/core/contexts/map.json +0 -19
  52. package/lib/core/contexts/miscellany.json +0 -19
  53. package/lib/core/contexts/quotes.json +0 -18
  54. package/lib/core/contexts/schemaorg.json +0 -8845
  55. package/lib/core/contexts/security-data-integrity-v1.json +0 -78
  56. package/lib/core/contexts/security-data-integrity-v2.json +0 -81
  57. package/lib/core/contexts/security-multikey-v1.json +0 -35
  58. package/lib/core/contexts/security-v1.json +0 -74
  59. package/lib/core/contexts/webfinger.json +0 -10
  60. package/lib/core/deliver.mjs +0 -387
  61. package/lib/core/graphview.mjs +0 -327
  62. package/lib/core/intake/activities.mjs +0 -649
  63. package/lib/core/intake/activity.mjs +0 -318
  64. package/lib/core/intake/channel.mjs +0 -144
  65. package/lib/core/intake/group.mjs +0 -258
  66. package/lib/core/intake/index.mjs +0 -732
  67. package/lib/core/intake/notes.mjs +0 -367
  68. package/lib/core/intake/verify.mjs +0 -142
  69. package/lib/core/keys.mjs +0 -153
  70. package/lib/core/lease.mjs +0 -206
  71. package/lib/core/place.mjs +0 -82
  72. package/lib/core/polls.mjs +0 -105
  73. package/lib/core/profile-page.mjs +0 -104
  74. package/lib/core/proof.mjs +0 -79
  75. package/lib/core/publisher/collections.mjs +0 -272
  76. package/lib/core/publisher/index.mjs +0 -522
  77. package/lib/core/publisher/notes.mjs +0 -519
  78. package/lib/core/publisher/own.mjs +0 -143
  79. package/lib/core/publisher/questions.mjs +0 -241
  80. package/lib/core/publisher/restore.mjs +0 -224
  81. package/lib/core/shapes/activitystreams.ttl +0 -157
  82. package/lib/core/shapes/index.mjs +0 -132
  83. package/lib/core/shapes/shapes-text.mjs +0 -13
  84. package/lib/core/social.mjs +0 -561
  85. package/lib/core/storage.mjs +0 -176
  86. package/lib/core/store.mjs +0 -578
  87. package/lib/core/wire-quotes.mjs +0 -71
  88. package/lib/core/wire.mjs +0 -925
  89. package/lib/device/account.mjs +0 -87
  90. package/lib/device/admin/index.mjs +0 -13
  91. package/lib/device/admin/origins.mjs +0 -35
  92. package/lib/device/admin/routes/connections.mjs +0 -144
  93. package/lib/device/admin/routes/gateway.mjs +0 -199
  94. package/lib/device/admin/routes/lifecycle.mjs +0 -200
  95. package/lib/device/admin/routes/owner.mjs +0 -322
  96. package/lib/device/admin/routes/setup.mjs +0 -428
  97. package/lib/device/admin/routes/social.mjs +0 -188
  98. package/lib/device/admin/server.mjs +0 -95
  99. package/lib/device/admin/static.mjs +0 -247
  100. package/lib/device/admin/surface.mjs +0 -315
  101. package/lib/device/certs.mjs +0 -281
  102. package/lib/device/cli/commands/account.mjs +0 -586
  103. package/lib/device/cli/commands/run.mjs +0 -278
  104. package/lib/device/cli/commands/service.mjs +0 -221
  105. package/lib/device/cli/commands/setup.mjs +0 -489
  106. package/lib/device/cli/commands/state.mjs +0 -561
  107. package/lib/device/cli/context.mjs +0 -288
  108. package/lib/device/export-collections.mjs +0 -161
  109. package/lib/device/gateway-move.mjs +0 -58
  110. package/lib/device/home.mjs +0 -161
  111. package/lib/device/migrate.mjs +0 -115
  112. package/lib/device/ports.mjs +0 -27
  113. package/lib/device/remote.mjs +0 -54
  114. package/lib/device/setup.mjs +0 -496
  115. package/lib/device/update.mjs +0 -96
  116. package/lib/gateway/caches.mjs +0 -36
  117. package/lib/gateway/directory.mjs +0 -90
  118. package/lib/gateway/front-core.mjs +0 -966
  119. package/lib/gateway/gateway-core.mjs +0 -244
  120. package/lib/gateway/headers.mjs +0 -49
  121. package/lib/gateway/httpsig.mjs +0 -159
  122. package/lib/gateway/notices.mjs +0 -84
  123. package/lib/gateway/quiet.mjs +0 -189
  124. package/lib/gateway/relay-extras.mjs +0 -89
  125. package/lib/gateway/token-claims.mjs +0 -16
  126. package/lib/pod/README.md +0 -61
  127. package/lib/pod/actor.mjs +0 -96
  128. package/lib/pod/collection.mjs +0 -77
  129. package/lib/pod/containers.mjs +0 -140
  130. package/lib/pod/discovery.mjs +0 -46
  131. package/lib/pod/featured.mjs +0 -18
  132. package/lib/pod/followers.mjs +0 -24
  133. package/lib/pod/following.mjs +0 -10
  134. package/lib/pod/http.mjs +0 -74
  135. package/lib/pod/inbox.mjs +0 -166
  136. package/lib/pod/links.mjs +0 -35
  137. package/lib/pod/location.mjs +0 -52
  138. package/lib/pod/media.mjs +0 -27
  139. package/lib/pod/notes.mjs +0 -78
  140. package/lib/pod/notifications.mjs +0 -89
  141. package/lib/pod/outbox.mjs +0 -18
  142. package/lib/pod/package.json +0 -19
  143. package/lib/pod/policy.mjs +0 -58
  144. package/lib/pod/private.mjs +0 -19
  145. package/lib/pod/root.mjs +0 -104
  146. package/lib/pod/state.mjs +0 -40
  147. package/lib/pod/transport.mjs +0 -674
  148. package/lib/pod/type-index.mjs +0 -101
  149. package/lib/pod/urls.mjs +0 -91
  150. package/lib/server/embed.mjs +0 -424
  151. package/lib/session/README.md +0 -137
  152. package/lib/session/demo.html +0 -94
  153. package/lib/session/fedi-account.mjs +0 -417
  154. package/lib/session/fedi-login.mjs +0 -123
  155. package/lib/session/oidc-session.mjs +0 -233
  156. package/lib/session/package.json +0 -49
  157. package/lib/shared/guard.mjs +0 -213
  158. package/lib/shared/links.mjs +0 -9
  159. package/lib/shared/safefetch.mjs +0 -235
  160. package/lib/shared/ua.mjs +0 -29
  161. package/phanpy/dist/404.html +0 -40
  162. package/phanpy/dist/_headers +0 -2
  163. package/phanpy/dist/apple-touch-icon.png +0 -0
  164. package/phanpy/dist/assets/ICONS-DIPJeU0C.js +0 -2
  165. package/phanpy/dist/assets/ICONS-DIPJeU0C.js.map +0 -1
  166. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js +0 -183
  167. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js.map +0 -1
  168. package/phanpy/dist/assets/Temml-CCjoacWt.woff2 +0 -0
  169. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js +0 -2
  170. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js.map +0 -1
  171. package/phanpy/dist/assets/boosts-carousel-BiOaNdMT.jpg +0 -0
  172. package/phanpy/dist/assets/catch-up-O5q5C75Z.png +0 -0
  173. package/phanpy/dist/assets/chunk-aKtaBQYM.js +0 -1
  174. package/phanpy/dist/assets/compose-CFEx7wb4.js +0 -2
  175. package/phanpy/dist/assets/compose-CFEx7wb4.js.map +0 -1
  176. package/phanpy/dist/assets/compose-ZJN5xSb4.js +0 -35
  177. package/phanpy/dist/assets/compose-ZJN5xSb4.js.map +0 -1
  178. package/phanpy/dist/assets/debug.module-YFQgwnIr.js +0 -52
  179. package/phanpy/dist/assets/debug.module-YFQgwnIr.js.map +0 -1
  180. package/phanpy/dist/assets/dom-p1YcJ5Rw.js +0 -2
  181. package/phanpy/dist/assets/dom-p1YcJ5Rw.js.map +0 -1
  182. package/phanpy/dist/assets/home-mobile-dark@2x-Dc-J8-SM.png +0 -0
  183. package/phanpy/dist/assets/home-mobile-light@2x-Bd3fod8m.png +0 -0
  184. package/phanpy/dist/assets/home-tablet-dark@2x-BgcNI8le.png +0 -0
  185. package/phanpy/dist/assets/home-tablet-light@2x-BW2RV9T6.png +0 -0
  186. package/phanpy/dist/assets/icons/add-circle-line-WD0mwORD.js +0 -1
  187. package/phanpy/dist/assets/icons/alert-line-CpFUMf9s.js +0 -1
  188. package/phanpy/dist/assets/icons/android-2-line-Bzxnrd3S.js +0 -1
  189. package/phanpy/dist/assets/icons/announcement-line-5nwaJFJm.js +0 -1
  190. package/phanpy/dist/assets/icons/arrow-down-circle-line-a7Id9-Iv.js +0 -1
  191. package/phanpy/dist/assets/icons/arrow-down-line-B8uzXzq6.js +0 -1
  192. package/phanpy/dist/assets/icons/arrow-left-line-CGrGT9C-.js +0 -1
  193. package/phanpy/dist/assets/icons/arrow-right-line-CE-HERfX.js +0 -1
  194. package/phanpy/dist/assets/icons/arrow-to-up-line-CvdQjmcy.js +0 -1
  195. package/phanpy/dist/assets/icons/arrow-up-circle-line-DEparSNF.js +0 -1
  196. package/phanpy/dist/assets/icons/arrow-up-line-C7yBeugc.js +0 -1
  197. package/phanpy/dist/assets/icons/arrows-right-line-BtbXmJGP.js +0 -1
  198. package/phanpy/dist/assets/icons/at-line-CF66Bznk.js +0 -1
  199. package/phanpy/dist/assets/icons/attachment-line-BY8It-l9.js +0 -1
  200. package/phanpy/dist/assets/icons/blockquote-line-BS6pU_hm.js +0 -1
  201. package/phanpy/dist/assets/icons/board-line-C0UWXyA6.js +0 -1
  202. package/phanpy/dist/assets/icons/bookmark-line-1CtX5JLF.js +0 -1
  203. package/phanpy/dist/assets/icons/building-5-line-Dd59MzbO.js +0 -1
  204. package/phanpy/dist/assets/icons/bus-2-line-6_dvA0GG.js +0 -1
  205. package/phanpy/dist/assets/icons/calendar-day-line-Crpl_fmu.js +0 -1
  206. package/phanpy/dist/assets/icons/calendar-month-line-vommts2C.js +0 -1
  207. package/phanpy/dist/assets/icons/calendar-time-add-line-BU_DTlQk.js +0 -1
  208. package/phanpy/dist/assets/icons/camera-line-Cv69MEei.js +0 -1
  209. package/phanpy/dist/assets/icons/celebrate-line-B8DvIoi0.js +0 -1
  210. package/phanpy/dist/assets/icons/chart-bar-line-FK-QOmtF.js +0 -1
  211. package/phanpy/dist/assets/icons/chart-line-line-BGcJAFWw.js +0 -1
  212. package/phanpy/dist/assets/icons/chat-3-line-YFK2-hwz.js +0 -1
  213. package/phanpy/dist/assets/icons/check-circle-line-DsAxFr5-.js +0 -1
  214. package/phanpy/dist/assets/icons/clipboard-line-BBp364gJ.js +0 -1
  215. package/phanpy/dist/assets/icons/close-circle-line-CICdiuGz.js +0 -1
  216. package/phanpy/dist/assets/icons/close-line-DYrFWcjv.js +0 -1
  217. package/phanpy/dist/assets/icons/cloud-line-tiQAbah8.js +0 -1
  218. package/phanpy/dist/assets/icons/code-line-fAl8iiV3.js +0 -1
  219. package/phanpy/dist/assets/icons/comment-2-line-CR3g7WeB.js +0 -1
  220. package/phanpy/dist/assets/icons/copy-2-line-CLW69yF5.js +0 -1
  221. package/phanpy/dist/assets/icons/delete-2-line-B8xmbr4n.js +0 -1
  222. package/phanpy/dist/assets/icons/document-3-line-DBGNhAg2.js +0 -1
  223. package/phanpy/dist/assets/icons/document-line-C7mb9sb7.js +0 -1
  224. package/phanpy/dist/assets/icons/down-line-BGqSSThd.js +0 -1
  225. package/phanpy/dist/assets/icons/edit-4-line-DcgGaEhx.js +0 -1
  226. package/phanpy/dist/assets/icons/emoji-2-line-D8YgnM-y.js +0 -1
  227. package/phanpy/dist/assets/icons/exit-line-Dc07BS-x.js +0 -1
  228. package/phanpy/dist/assets/icons/external-link-line-BvpSkmjO.js +0 -1
  229. package/phanpy/dist/assets/icons/eye-2-line-CiWXx-f_.js +0 -1
  230. package/phanpy/dist/assets/icons/eye-close-line-BgTaSJ4P.js +0 -1
  231. package/phanpy/dist/assets/icons/filter-2-line-B_mR2usy.js +0 -1
  232. package/phanpy/dist/assets/icons/filter-line-C_nm-3cU.js +0 -1
  233. package/phanpy/dist/assets/icons/flag-1-line-C2HB05I0.js +0 -1
  234. package/phanpy/dist/assets/icons/forbid-circle-line-D3LTT9yd.js +0 -1
  235. package/phanpy/dist/assets/icons/formula-line-DLrt2d6j.js +0 -1
  236. package/phanpy/dist/assets/icons/grid-line-CgUmEikf.js +0 -1
  237. package/phanpy/dist/assets/icons/group-line-C5fnX0wU.js +0 -1
  238. package/phanpy/dist/assets/icons/hand-finger-2-line-BGgxbuL9.js +0 -1
  239. package/phanpy/dist/assets/icons/hashtag-line-CyTEEXBb.js +0 -1
  240. package/phanpy/dist/assets/icons/heart-crack-line-BZddbO2C.js +0 -1
  241. package/phanpy/dist/assets/icons/heart-line-CJ7K47J4.js +0 -1
  242. package/phanpy/dist/assets/icons/history-2-line-kWWvFzqv.js +0 -1
  243. package/phanpy/dist/assets/icons/history-line-bGQiwbTH.js +0 -1
  244. package/phanpy/dist/assets/icons/home-3-line-fRU1zeLG.js +0 -1
  245. package/phanpy/dist/assets/icons/information-line-iNk6-sOY.js +0 -1
  246. package/phanpy/dist/assets/icons/keyboard-line-DsCyuQNz.js +0 -1
  247. package/phanpy/dist/assets/icons/layout-4-line-CZkOX52Z.js +0 -1
  248. package/phanpy/dist/assets/icons/layout-5-line-B_znt5wO.js +0 -1
  249. package/phanpy/dist/assets/icons/left-line-eUw0tya4.js +0 -1
  250. package/phanpy/dist/assets/icons/lightning-line-DaKoDdix.js +0 -1
  251. package/phanpy/dist/assets/icons/link-2-line-DCqLmMA7.js +0 -1
  252. package/phanpy/dist/assets/icons/list-check-line-BAxosBh9.js +0 -1
  253. package/phanpy/dist/assets/icons/lock-line-CPoaXeUW.js +0 -1
  254. package/phanpy/dist/assets/icons/mail-line-B0P8aa1L.js +0 -1
  255. package/phanpy/dist/assets/icons/moon-line-CEqNAToP.js +0 -1
  256. package/phanpy/dist/assets/icons/more-1-fill-Dw2e5xab.js +0 -1
  257. package/phanpy/dist/assets/icons/more-3-line-BIiVjYTz.js +0 -1
  258. package/phanpy/dist/assets/icons/notification-line-BZZq2Gtu.js +0 -1
  259. package/phanpy/dist/assets/icons/pencil-line-CKh8-A1v.js +0 -1
  260. package/phanpy/dist/assets/icons/photo-album-line-Bnfg2u40.js +0 -1
  261. package/phanpy/dist/assets/icons/pin-line-DpTolyhs.js +0 -1
  262. package/phanpy/dist/assets/icons/play-fill-B0-G_8lX.js +0 -1
  263. package/phanpy/dist/assets/icons/qrcode-2-line-B6SPCaHn.js +0 -1
  264. package/phanpy/dist/assets/icons/quill-pen-line-B6LUrnCP.js +0 -1
  265. package/phanpy/dist/assets/icons/quote-left-fill-hQZ1cj_6.js +0 -1
  266. package/phanpy/dist/assets/icons/radar-line-CKyroTth.js +0 -1
  267. package/phanpy/dist/assets/icons/react-line-CoIKhhtK.js +0 -1
  268. package/phanpy/dist/assets/icons/refresh-2-line-D0mTF97S.js +0 -1
  269. package/phanpy/dist/assets/icons/right-line-B3KWJaqc.js +0 -1
  270. package/phanpy/dist/assets/icons/rocket-line-4KZl537D.js +0 -1
  271. package/phanpy/dist/assets/icons/round-fill-C69NTrZ0.js +0 -1
  272. package/phanpy/dist/assets/icons/round-line-B9k_1uo-.js +0 -1
  273. package/phanpy/dist/assets/icons/route-line-B28ReHcE.js +0 -1
  274. package/phanpy/dist/assets/icons/rows-4-line-CrBniagM.js +0 -1
  275. package/phanpy/dist/assets/icons/scan-line-DSf74YdP.js +0 -1
  276. package/phanpy/dist/assets/icons/search-2-line-B6geIU1z.js +0 -1
  277. package/phanpy/dist/assets/icons/settings-3-line-azJwK47w.js +0 -1
  278. package/phanpy/dist/assets/icons/settings-6-line-C_5zc5YR.js +0 -1
  279. package/phanpy/dist/assets/icons/share-2-line-D5MxWjrm.js +0 -1
  280. package/phanpy/dist/assets/icons/share-forward-line-Cp61fZzZ.js +0 -1
  281. package/phanpy/dist/assets/icons/sparkles-2-line-DYYyXTaW.js +0 -1
  282. package/phanpy/dist/assets/icons/sparkles-line-C2hY1s6I.js +0 -1
  283. package/phanpy/dist/assets/icons/time-line-BF3eet1v.js +0 -1
  284. package/phanpy/dist/assets/icons/transfer-4-line-oisfvTBw.js +0 -1
  285. package/phanpy/dist/assets/icons/translate-line-BFWol2Ce.js +0 -1
  286. package/phanpy/dist/assets/icons/unlock-line-X_x5vwv3.js +0 -1
  287. package/phanpy/dist/assets/icons/upload-3-line-DgzwUJeW.js +0 -1
  288. package/phanpy/dist/assets/icons/user-4-line-BVSynZCp.js +0 -1
  289. package/phanpy/dist/assets/icons/user-add-2-line-BlGS5Q8q.js +0 -1
  290. package/phanpy/dist/assets/icons/user-add-line-BbXdHG4z.js +0 -1
  291. package/phanpy/dist/assets/icons/user-edit-line-BFAHOV0X.js +0 -1
  292. package/phanpy/dist/assets/icons/user-follow-line-BXux0wSd.js +0 -1
  293. package/phanpy/dist/assets/icons/user-star-line-DdYlpHLU.js +0 -1
  294. package/phanpy/dist/assets/icons/user-warning-line-Cj43j0_E.js +0 -1
  295. package/phanpy/dist/assets/icons/user-x-line-DIDgNlPH.js +0 -1
  296. package/phanpy/dist/assets/icons/volume-line-Bs390KQt.js +0 -1
  297. package/phanpy/dist/assets/icons/volume-mute-line-DzlzIqFZ.js +0 -1
  298. package/phanpy/dist/assets/icons/walk-line-yNXfB-md.js +0 -1
  299. package/phanpy/dist/assets/icons/world-2-line-CenkGIwj.js +0 -1
  300. package/phanpy/dist/assets/icons/zoom-in-line-CaENUphf.js +0 -1
  301. package/phanpy/dist/assets/icons/zoom-out-line-BDNk0EWo.js +0 -1
  302. package/phanpy/dist/assets/instances-BNPptnn-.json +0 -333
  303. package/phanpy/dist/assets/locales/ar-SA-CfheRbCu.js +0 -1
  304. package/phanpy/dist/assets/locales/ca-ES-DHRW86Tz.js +0 -1
  305. package/phanpy/dist/assets/locales/cs-CZ-CKoqEuA1.js +0 -1
  306. package/phanpy/dist/assets/locales/de-DE-ByRPMRFy.js +0 -1
  307. package/phanpy/dist/assets/locales/eo-UY-CPC7wLCS.js +0 -1
  308. package/phanpy/dist/assets/locales/es-ES-dJa0Fd9t.js +0 -1
  309. package/phanpy/dist/assets/locales/eu-ES-C3djlPR2.js +0 -1
  310. package/phanpy/dist/assets/locales/fa-IR-DTT490Ck.js +0 -1
  311. package/phanpy/dist/assets/locales/fi-FI-B23MCPuz.js +0 -1
  312. package/phanpy/dist/assets/locales/fr-FR-BcaQsO5C.js +0 -1
  313. package/phanpy/dist/assets/locales/gl-ES-BR-CVKBN.js +0 -1
  314. package/phanpy/dist/assets/locales/he-IL-CfheRbCu.js +0 -1
  315. package/phanpy/dist/assets/locales/hu-HU-CfheRbCu.js +0 -1
  316. package/phanpy/dist/assets/locales/it-IT-C1136UFV.js +0 -1
  317. package/phanpy/dist/assets/locales/ja-JP-CRZmRAhD.js +0 -1
  318. package/phanpy/dist/assets/locales/kab-Cz8xH_TT.js +0 -1
  319. package/phanpy/dist/assets/locales/ko-KR-CG9UiY4o.js +0 -1
  320. package/phanpy/dist/assets/locales/lt-LT-CJcI6sHZ.js +0 -1
  321. package/phanpy/dist/assets/locales/nb-NO-CfheRbCu.js +0 -1
  322. package/phanpy/dist/assets/locales/nl-NL-DxN4Yc1t.js +0 -1
  323. package/phanpy/dist/assets/locales/oc-FR-CfheRbCu.js +0 -1
  324. package/phanpy/dist/assets/locales/pl-PL-DkwGXf6P.js +0 -1
  325. package/phanpy/dist/assets/locales/pseudo-LOCALE-CQ4XxkQ0.js +0 -1
  326. package/phanpy/dist/assets/locales/pt-BR-nGL0HdFS.js +0 -1
  327. package/phanpy/dist/assets/locales/pt-PT-Cp17aj2z.js +0 -1
  328. package/phanpy/dist/assets/locales/ru-RU-0Y8cIoaK.js +0 -1
  329. package/phanpy/dist/assets/locales/th-TH-CfheRbCu.js +0 -1
  330. package/phanpy/dist/assets/locales/tok-CfheRbCu.js +0 -1
  331. package/phanpy/dist/assets/locales/tr-TR-CfheRbCu.js +0 -1
  332. package/phanpy/dist/assets/locales/uk-UA-C5E3dFBf.js +0 -1
  333. package/phanpy/dist/assets/locales/zh-CN-BHJi7_et.js +0 -1
  334. package/phanpy/dist/assets/locales/zh-TW-CfheRbCu.js +0 -1
  335. package/phanpy/dist/assets/main-BdqNbG-a.js +0 -26
  336. package/phanpy/dist/assets/main-BdqNbG-a.js.map +0 -1
  337. package/phanpy/dist/assets/mock-home-DGhR__He.js +0 -2
  338. package/phanpy/dist/assets/mock-home-DGhR__He.js.map +0 -1
  339. package/phanpy/dist/assets/multi-column-ROck0NVt.jpg +0 -0
  340. package/phanpy/dist/assets/multi-hashtag-timeline-DH5INVHi.jpg +0 -0
  341. package/phanpy/dist/assets/nested-comments-thread-hv59kZLc.jpg +0 -0
  342. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js +0 -2
  343. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js.map +0 -1
  344. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js +0 -20
  345. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js.map +0 -1
  346. package/phanpy/dist/assets/style-B1iLPTPR.css +0 -2
  347. package/phanpy/dist/assets/temml-DuyIQMei.js +0 -97
  348. package/phanpy/dist/assets/temml-DuyIQMei.js.map +0 -1
  349. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js +0 -2
  350. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js.map +0 -1
  351. package/phanpy/dist/assets/year-in-posts-B2lywqdx.png +0 -0
  352. package/phanpy/dist/assets/year-in-posts-DJv_star.js +0 -3
  353. package/phanpy/dist/assets/year-in-posts-DJv_star.js.map +0 -1
  354. package/phanpy/dist/compose/index.html +0 -20
  355. package/phanpy/dist/favicon.ico +0 -0
  356. package/phanpy/dist/index.html +0 -73
  357. package/phanpy/dist/logo-192.png +0 -0
  358. package/phanpy/dist/logo-512.png +0 -0
  359. package/phanpy/dist/logo-badge-72.png +0 -0
  360. package/phanpy/dist/logo-maskable-512.png +0 -0
  361. package/phanpy/dist/logo-monochrome-512.png +0 -0
  362. package/phanpy/dist/logo-monochrome-maskable-512.png +0 -0
  363. package/phanpy/dist/manifest.webmanifest +0 -1
  364. package/phanpy/dist/og-image-2.jpg +0 -0
  365. package/phanpy/dist/og-image.png +0 -0
  366. package/phanpy/dist/robots.txt +0 -2
  367. package/phanpy/dist/sw.js +0 -2
  368. package/phanpy/dist/sw.js.map +0 -1
  369. package/phanpy/dist/version.json +0 -1
  370. package/run-agent.mjs +0 -899
  371. package/vendor/gate.cjs +0 -138
  372. package/vendor/idp-grant.cjs +0 -394
  373. package/vendor/jfetch.cjs +0 -16
  374. package/web/admin/actors.js +0 -147
  375. package/web/admin/bar.css +0 -126
  376. package/web/admin/bar.js +0 -99
  377. package/web/admin/client/client.js +0 -66
  378. package/web/admin/client/index.html +0 -69
  379. package/web/admin/client-pick.js +0 -79
  380. package/web/admin/common.js +0 -23
  381. package/web/admin/connections.js +0 -112
  382. package/web/admin/gateway.js +0 -133
  383. package/web/admin/group.js +0 -258
  384. package/web/admin/index.html +0 -612
  385. package/web/admin/notices-bar.js +0 -90
  386. package/web/admin/oauth-signin.mjs +0 -37
  387. package/web/admin/record.js +0 -393
  388. package/web/admin/setup/index.html +0 -257
  389. package/web/admin/setup/setup.js +0 -339
  390. package/web/admin/tokens.css +0 -68
  391. package/web/admin/upkeep.js +0 -177
  392. package/web/admin/window.css +0 -55
  393. package/web/admin/window.js +0 -136
  394. package/web/app/README.md +0 -81
  395. package/web/app/admin-facade.mjs +0 -588
  396. package/web/app/agent.mjs +0 -672
  397. package/web/app/atproto-browser.mjs +0 -86
  398. package/web/app/authorize_interaction.html +0 -56
  399. package/web/app/authorize_interaction.js +0 -69
  400. package/web/app/boot.mjs +0 -616
  401. package/web/app/deliver-relay.mjs +0 -129
  402. package/web/app/dist/boot.js +0 -34562
  403. package/web/app/dist/boot.js.map +0 -7
  404. package/web/app/dist/sw.js +0 -73456
  405. package/web/app/dist/sw.js.map +0 -7
  406. package/web/app/fediacct-browser.mjs +0 -146
  407. package/web/app/gateway-move.mjs +0 -60
  408. package/web/app/idb-kv.mjs +0 -35
  409. package/web/app/index.html +0 -258
  410. package/web/app/keys-browser.mjs +0 -71
  411. package/web/app/keystore.mjs +0 -82
  412. package/web/app/oidc-session.mjs +0 -6
  413. package/web/app/pod-auth.mjs +0 -248
  414. package/web/app/pod-remote.mjs +0 -84
  415. package/web/app/shims/_globals.mjs +0 -2
  416. package/web/app/shims/fedify-sig.mjs +0 -77
  417. package/web/app/shims/node-crypto.mjs +0 -113
  418. package/web/app/shims/node-fs.mjs +0 -17
  419. package/web/app/shims/node-path.mjs +0 -19
  420. package/web/app/shims/node-url.mjs +0 -7
  421. package/web/app/shims/prelude.js +0 -58
  422. package/web/app/shims/safefetch.mjs +0 -58
  423. package/web/app/shims/shapes-text.mjs +0 -8
  424. package/web/app/shims/web-push.mjs +0 -14
  425. package/web/app/signup.mjs +0 -357
  426. package/web/app/sw-src.mjs +0 -220
  427. package/web/app/update.js +0 -70
  428. package/web/front/admin.html +0 -55
  429. package/web/front/admin.js +0 -89
  430. package/web/front/install.sh +0 -69
  431. package/web/front/new-account.html +0 -35
  432. package/web/front/new-account.js +0 -13
  433. package/web/front/notices.html +0 -69
  434. package/web/front/notices.js +0 -107
  435. package/web/front/run.html +0 -64
  436. package/web/front/run.js +0 -221
  437. package/web/front/solid-oidc-client.js +0 -6
  438. package/web/icons/forum.svg +0 -11
  439. package/web/icons/gateway.svg +0 -14
  440. package/web/icons/local.svg +0 -11
@@ -1,78 +0,0 @@
1
- {
2
- "@context": {
3
- "id": "@id",
4
- "type": "@type",
5
- "@protected": true,
6
- "digestMultibase": {
7
- "@id": "https://w3id.org/security#digestMultibase",
8
- "@type": "https://w3id.org/security#multibase"
9
- },
10
- "proof": {
11
- "@id": "https://w3id.org/security#proof",
12
- "@type": "@id",
13
- "@container": "@graph"
14
- },
15
- "DataIntegrityProof": {
16
- "@id": "https://w3id.org/security#DataIntegrityProof",
17
- "@context": {
18
- "@protected": true,
19
- "id": "@id",
20
- "type": "@type",
21
- "challenge": "https://w3id.org/security#challenge",
22
- "created": {
23
- "@id": "http://purl.org/dc/terms/created",
24
- "@type": "http://www.w3.org/2001/XMLSchema#dateTime"
25
- },
26
- "domain": "https://w3id.org/security#domain",
27
- "expires": {
28
- "@id": "https://w3id.org/security#expiration",
29
- "@type": "http://www.w3.org/2001/XMLSchema#dateTime"
30
- },
31
- "nonce": "https://w3id.org/security#nonce",
32
- "proofPurpose": {
33
- "@id": "https://w3id.org/security#proofPurpose",
34
- "@type": "@vocab",
35
- "@context": {
36
- "@protected": true,
37
- "id": "@id",
38
- "type": "@type",
39
- "assertionMethod": {
40
- "@id": "https://w3id.org/security#assertionMethod",
41
- "@type": "@id",
42
- "@container": "@set"
43
- },
44
- "authentication": {
45
- "@id": "https://w3id.org/security#authenticationMethod",
46
- "@type": "@id",
47
- "@container": "@set"
48
- },
49
- "capabilityInvocation": {
50
- "@id": "https://w3id.org/security#capabilityInvocationMethod",
51
- "@type": "@id",
52
- "@container": "@set"
53
- },
54
- "capabilityDelegation": {
55
- "@id": "https://w3id.org/security#capabilityDelegationMethod",
56
- "@type": "@id",
57
- "@container": "@set"
58
- },
59
- "keyAgreement": {
60
- "@id": "https://w3id.org/security#keyAgreementMethod",
61
- "@type": "@id",
62
- "@container": "@set"
63
- }
64
- }
65
- },
66
- "cryptosuite": "https://w3id.org/security#cryptosuite",
67
- "proofValue": {
68
- "@id": "https://w3id.org/security#proofValue",
69
- "@type": "https://w3id.org/security#multibase"
70
- },
71
- "verificationMethod": {
72
- "@id": "https://w3id.org/security#verificationMethod",
73
- "@type": "@id"
74
- }
75
- }
76
- }
77
- }
78
- }
@@ -1,81 +0,0 @@
1
- {
2
- "@context": {
3
- "id": "@id",
4
- "type": "@type",
5
- "@protected": true,
6
- "proof": {
7
- "@id": "https://w3id.org/security#proof",
8
- "@type": "@id",
9
- "@container": "@graph"
10
- },
11
- "DataIntegrityProof": {
12
- "@id": "https://w3id.org/security#DataIntegrityProof",
13
- "@context": {
14
- "@protected": true,
15
- "id": "@id",
16
- "type": "@type",
17
- "challenge": "https://w3id.org/security#challenge",
18
- "created": {
19
- "@id": "http://purl.org/dc/terms/created",
20
- "@type": "http://www.w3.org/2001/XMLSchema#dateTime"
21
- },
22
- "domain": "https://w3id.org/security#domain",
23
- "expires": {
24
- "@id": "https://w3id.org/security#expiration",
25
- "@type": "http://www.w3.org/2001/XMLSchema#dateTime"
26
- },
27
- "nonce": "https://w3id.org/security#nonce",
28
- "previousProof": {
29
- "@id": "https://w3id.org/security#previousProof",
30
- "@type": "@id"
31
- },
32
- "proofPurpose": {
33
- "@id": "https://w3id.org/security#proofPurpose",
34
- "@type": "@vocab",
35
- "@context": {
36
- "@protected": true,
37
- "id": "@id",
38
- "type": "@type",
39
- "assertionMethod": {
40
- "@id": "https://w3id.org/security#assertionMethod",
41
- "@type": "@id",
42
- "@container": "@set"
43
- },
44
- "authentication": {
45
- "@id": "https://w3id.org/security#authenticationMethod",
46
- "@type": "@id",
47
- "@container": "@set"
48
- },
49
- "capabilityInvocation": {
50
- "@id": "https://w3id.org/security#capabilityInvocationMethod",
51
- "@type": "@id",
52
- "@container": "@set"
53
- },
54
- "capabilityDelegation": {
55
- "@id": "https://w3id.org/security#capabilityDelegationMethod",
56
- "@type": "@id",
57
- "@container": "@set"
58
- },
59
- "keyAgreement": {
60
- "@id": "https://w3id.org/security#keyAgreementMethod",
61
- "@type": "@id",
62
- "@container": "@set"
63
- }
64
- }
65
- },
66
- "cryptosuite": {
67
- "@id": "https://w3id.org/security#cryptosuite",
68
- "@type": "https://w3id.org/security#cryptosuiteString"
69
- },
70
- "proofValue": {
71
- "@id": "https://w3id.org/security#proofValue",
72
- "@type": "https://w3id.org/security#multibase"
73
- },
74
- "verificationMethod": {
75
- "@id": "https://w3id.org/security#verificationMethod",
76
- "@type": "@id"
77
- }
78
- }
79
- }
80
- }
81
- }
@@ -1,35 +0,0 @@
1
- {
2
- "@context": {
3
- "id": "@id",
4
- "type": "@type",
5
- "@protected": true,
6
- "Multikey": {
7
- "@id": "https://w3id.org/security#Multikey",
8
- "@context": {
9
- "@protected": true,
10
- "id": "@id",
11
- "type": "@type",
12
- "controller": {
13
- "@id": "https://w3id.org/security#controller",
14
- "@type": "@id"
15
- },
16
- "revoked": {
17
- "@id": "https://w3id.org/security#revoked",
18
- "@type": "http://www.w3.org/2001/XMLSchema#dateTime"
19
- },
20
- "expires": {
21
- "@id": "https://w3id.org/security#expiration",
22
- "@type": "http://www.w3.org/2001/XMLSchema#dateTime"
23
- },
24
- "publicKeyMultibase": {
25
- "@id": "https://w3id.org/security#publicKeyMultibase",
26
- "@type": "https://w3id.org/security#multibase"
27
- },
28
- "secretKeyMultibase": {
29
- "@id": "https://w3id.org/security#secretKeyMultibase",
30
- "@type": "https://w3id.org/security#multibase"
31
- }
32
- }
33
- }
34
- }
35
- }
@@ -1,74 +0,0 @@
1
- {
2
- "@context": {
3
- "id": "@id",
4
- "type": "@type",
5
- "dc": "http://purl.org/dc/terms/",
6
- "sec": "https://w3id.org/security#",
7
- "xsd": "http://www.w3.org/2001/XMLSchema#",
8
- "EcdsaKoblitzSignature2016": "sec:EcdsaKoblitzSignature2016",
9
- "Ed25519Signature2018": "sec:Ed25519Signature2018",
10
- "EncryptedMessage": "sec:EncryptedMessage",
11
- "GraphSignature2012": "sec:GraphSignature2012",
12
- "LinkedDataSignature2015": "sec:LinkedDataSignature2015",
13
- "LinkedDataSignature2016": "sec:LinkedDataSignature2016",
14
- "CryptographicKey": "sec:Key",
15
- "authenticationTag": "sec:authenticationTag",
16
- "canonicalizationAlgorithm": "sec:canonicalizationAlgorithm",
17
- "cipherAlgorithm": "sec:cipherAlgorithm",
18
- "cipherData": "sec:cipherData",
19
- "cipherKey": "sec:cipherKey",
20
- "created": {
21
- "@id": "dc:created",
22
- "@type": "xsd:dateTime"
23
- },
24
- "creator": {
25
- "@id": "dc:creator",
26
- "@type": "@id"
27
- },
28
- "digestAlgorithm": "sec:digestAlgorithm",
29
- "digestValue": "sec:digestValue",
30
- "domain": "sec:domain",
31
- "encryptionKey": "sec:encryptionKey",
32
- "expiration": {
33
- "@id": "sec:expiration",
34
- "@type": "xsd:dateTime"
35
- },
36
- "expires": {
37
- "@id": "sec:expiration",
38
- "@type": "xsd:dateTime"
39
- },
40
- "initializationVector": "sec:initializationVector",
41
- "iterationCount": "sec:iterationCount",
42
- "nonce": "sec:nonce",
43
- "normalizationAlgorithm": "sec:normalizationAlgorithm",
44
- "owner": {
45
- "@id": "sec:owner",
46
- "@type": "@id"
47
- },
48
- "password": "sec:password",
49
- "privateKey": {
50
- "@id": "sec:privateKey",
51
- "@type": "@id"
52
- },
53
- "privateKeyPem": "sec:privateKeyPem",
54
- "publicKey": {
55
- "@id": "sec:publicKey",
56
- "@type": "@id"
57
- },
58
- "publicKeyBase58": "sec:publicKeyBase58",
59
- "publicKeyPem": "sec:publicKeyPem",
60
- "publicKeyWif": "sec:publicKeyWif",
61
- "publicKeyService": {
62
- "@id": "sec:publicKeyService",
63
- "@type": "@id"
64
- },
65
- "revoked": {
66
- "@id": "sec:revoked",
67
- "@type": "xsd:dateTime"
68
- },
69
- "salt": "sec:salt",
70
- "signature": "sec:signature",
71
- "signatureAlgorithm": "sec:signingAlgorithm",
72
- "signatureValue": "sec:signatureValue"
73
- }
74
- }
@@ -1,10 +0,0 @@
1
- {
2
- "@context": {
3
- "wf": "https://purl.archive.org/socialweb/webfinger#",
4
- "xsd": "http://www.w3.org/2001/XMLSchema#",
5
- "webfinger": {
6
- "@id": "wf:webfinger",
7
- "@type": "xsd:string"
8
- }
9
- }
10
- }
@@ -1,387 +0,0 @@
1
- // deliver.mjs — signed outbound delivery + retry queue. Fedify's signRequest
2
- // does draft-cavage HTTP Signatures (what Mastodon verifies). Failures go to
3
- // a JSON-file queue with exponential backoff; peers that stay down are
4
- // dropped after MAX_ATTEMPTS (~3 days).
5
-
6
- import { signRequest } from '@fedify/fedify/sig';
7
- import { webcrypto } from 'node:crypto';
8
- import { attachProof } from './proof.mjs';
9
- import { pinnedFor, retryAfterMs, HTTP_TIMEOUT_MS } from '../shared/safefetch.mjs';
10
- import { USER_AGENT } from '../shared/ua.mjs';
11
- import { dropFollower } from './store.mjs';
12
-
13
- const MAX_REDIRECTS = 3;
14
-
15
- // draft-cavage signs `(request-target): <method> <path><query>`. Fedify 2.3.4
16
- // builds that line from the pathname alone, so a signature over any URL
17
- // carrying a query is one a correct verifier cannot reconstruct — a paged
18
- // collection at `?page=2`, a WordPress inbox at `?rest_route=…`. Re-sign just
19
- // that line, over the header list Fedify already chose; a URL with no query
20
- // comes back untouched, and anything unexpected is left exactly as signed.
21
- export async function withQueryInTarget(signed, privateKey) {
22
- const url = new URL(signed.url);
23
- if (!url.search) return signed;
24
- const header = signed.headers.get('signature');
25
- if (!header) return signed;
26
- const fields = Object.fromEntries(
27
- [...header.matchAll(/([A-Za-z]+)="([^"]*)"/g)].map(m => [m[1], m[2]]));
28
- const names = fields.headers?.split(/\s+/g) || [];
29
- if (!fields.signature || !names.includes('(request-target)')) return signed;
30
- if (names.some(n => n.startsWith('(') && n !== '(request-target)')) return signed;
31
- const message = names.map(n => n === '(request-target)'
32
- ? `(request-target): ${signed.method.toLowerCase()} ${url.pathname}${url.search}`
33
- : `${n}: ${(n === 'host' ? signed.headers.get('host') || url.host : signed.headers.get(n)) ?? ''}`)
34
- .join('\n');
35
- const sig = await webcrypto.subtle.sign('RSASSA-PKCS1-v1_5', privateKey,
36
- new TextEncoder().encode(message));
37
- const headers = new Headers(signed.headers);
38
- headers.set('signature',
39
- header.replace(/signature="[^"]*"/, `signature="${Buffer.from(sig).toString('base64')}"`));
40
- const init = { method: signed.method, headers, signal: signed.signal };
41
- if (signed.method !== 'GET' && signed.method !== 'HEAD') init.body = await signed.arrayBuffer();
42
- return new Request(signed.url, init);
43
- }
44
-
45
- const MAX_ATTEMPTS = 12; // 2^12 min ≈ 68h of backoff
46
- const TICK_MS = 60_000;
47
- const MAX_QUEUE = 2000; // beyond it, overflow dead-letters
48
-
49
- // Is this failure about the SERVER, or about this one recipient? A 410 Gone,
50
- // a 403, a 401 from an authorized-fetch instance are answers about one inbox;
51
- // cooling the whole host for them starves every other recipient on it — which
52
- // on a big instance is most of your followers. Only a refusal that is about
53
- // the server, or no answer at all, is grounds to leave it alone.
54
- const hostOf = (inbox) => { try { return new URL(inbox).host; } catch { return inbox; } };
55
- const aboutTheHost = (e) => !e.status || e.status >= 500 || e.status === 429;
56
- // A 410 says the inbox is gone for good and a 404 that nothing answers there:
57
- // neither earns a second POST. Gone also means whoever read there has left.
58
- const unsalvageable = (e) => e.status === 404 || e.status === 410;
59
-
60
- export class Deliverer {
61
- // passive: signing-only (viewer-mode agents) — no queue drain timer, so a
62
- // read-only agent never mutates shared delivery state. startQueue() flips
63
- // it live when a viewer is promoted to active.
64
- constructor({ store, keyId, rsaPrivate, actorId = null, edPrivate = null, proofKeyId = null,
65
- log = console.log, passive = false, onGone = null }) {
66
- this.store = store;
67
- // Called after followers at a gone inbox are dropped: the agent republishes
68
- // its followers collection.
69
- this.onGone = onGone;
70
- this.keyId = keyId;
71
- this.rsaPrivate = rsaPrivate;
72
- this.actorId = actorId;
73
- this.edPrivate = edPrivate;
74
- this.proofKeyId = proofKeyId;
75
- this.log = log;
76
- // How many fresh deliveries one attempt may carry. The Node deliverer
77
- // opens a socket per recipient; the browser's relay deliverer sends a
78
- // list, and sets this to what the relay accepts.
79
- this.batchSize = 1;
80
- if (!passive) this.startQueue();
81
- }
82
-
83
- startQueue() {
84
- if (this.timer) return;
85
- this.timer = setInterval(() => this.drainQueue().catch(e => this.log(`queue: ${e.message}`)), TICK_MS);
86
- this.timer.unref?.();
87
- }
88
-
89
- // Signed fetch — also used for GETs so authorized-fetch instances answer
90
- // us. Targets come from attacker-supplied documents, so every hop is
91
- // address-checked and the connection is pinned to the checked address.
92
- // Redirects are followed by hand because each hop needs its own signature
93
- // (the signature covers the request target).
94
- async signedFetch(url, init = {}) {
95
- let current = url;
96
- // Named on every hop: a remote operator seeing our deliveries or our
97
- // verify-by-dereference GETs should know what we are.
98
- //
99
- // And bounded. This was the one remote-facing path in the project without a
100
- // deadline — publisher, intake and the token grant all set one — so a peer
101
- // that accepted the connection and then stalled held us for undici's 300s
102
- // default. Against a 60s queue tick that is five overlapping drains
103
- // re-POSTing the same activity at a server already in trouble. One signal,
104
- // built once, so it covers all four redirect hops together rather than
105
- // giving each hop a fresh deadline.
106
- const withUa = {
107
- ...init,
108
- signal: init.signal || AbortSignal.timeout(HTTP_TIMEOUT_MS),
109
- headers: { 'user-agent': USER_AGENT, ...(init.headers || {}) },
110
- };
111
- for (let hop = 0; hop <= MAX_REDIRECTS; hop++) {
112
- const dispatcher = await pinnedFor(current);
113
- const req = new Request(current, withUa);
114
- const signed = await withQueryInTarget(
115
- await signRequest(req, this.rsaPrivate, new URL(this.keyId)), this.rsaPrivate);
116
- const res = await fetch(signed, { ...(dispatcher ? { dispatcher } : {}), redirect: 'manual' });
117
- if (res.status >= 300 && res.status < 400 && res.headers.get('location')) {
118
- current = new URL(res.headers.get('location'), current).href;
119
- continue;
120
- }
121
- // Where this ended up, which is not always where it was asked to go.
122
- // Callers compare the document's own id against the URL they REQUESTED,
123
- // so without this an open redirector on a victim's origin let an
124
- // attacker's server answer for a victim's URL and be believed.
125
- try { Object.defineProperty(res, 'finalUrl', { value: current, configurable: true }); }
126
- catch { /* a frozen Response: the caller falls back to the requested URL */ }
127
- return res;
128
- }
129
- throw new Error(`too many redirects from ${url}`);
130
- }
131
-
132
- async deliverNow(inbox, activity) {
133
- const res = await this.signedFetch(inbox, {
134
- method: 'POST',
135
- headers: { 'content-type': 'application/activity+json' },
136
- body: JSON.stringify(activity),
137
- });
138
- if (res.status >= 400) {
139
- // Carry what the server told us instead of flattening it to a string.
140
- // The Response used to be discarded here, headers and all, which is why
141
- // a `Retry-After: 3600` was answered with four more POSTs inside the
142
- // hour it asked for.
143
- const err = new Error(`POST ${inbox} → ${res.status}`);
144
- err.status = res.status;
145
- // Only when the header is ACTUALLY there. Defaulting made every 503
146
- // without one — which is most of them — collapse the exponential ladder
147
- // to a flat 60s, the opposite of the intent. A remote's own instruction
148
- // is honoured up to a day rather than the pod path's 30-minute ceiling:
149
- // MAX_ATTEMPTS bounds the wait anyway.
150
- const ra = retryAfterMs(res, 24 * 60 * 60_000);
151
- if (ra != null) err.retryAfterMs = ra;
152
- throw err;
153
- }
154
- return res;
155
- }
156
-
157
- // Deliver, queueing on failure.
158
- // FEP-8b32: a proof on everything WE author, so a server that meets one of
159
- // our activities second-hand can verify it without asking us.
160
- //
161
- // Only ours. An activity we forward on someone else's behalf keeps whatever
162
- // proof its author gave it — signing that one as an assertion of ours would
163
- // be claiming to have written it.
164
- async proofed(activity) {
165
- if (!this.edPrivate || !this.proofKeyId || !activity || typeof activity !== 'object') return activity;
166
- if (activity.proof) return activity;
167
- const actor = typeof activity.actor === 'string' ? activity.actor : activity.actor?.id;
168
- if (!this.actorId || actor !== this.actorId) return activity;
169
- try {
170
- return await attachProof(activity,
171
- { privateKey: this.edPrivate, verificationMethod: this.proofKeyId });
172
- } catch (e) {
173
- this.log(`proof: ${e.message}`); // an unproved activity still federates
174
- return activity;
175
- }
176
- }
177
-
178
- // One attempt per target, answered in order: `{ ok: true }` or `{ error }`
179
- // with the error deliverNow would have thrown. Here one at a time; the
180
- // relay deliverer sends the whole list in one call.
181
- async deliverManyNow(targets) {
182
- const out = [];
183
- for (const t of targets) {
184
- try { await this.deliverNow(t.inbox, t.activity); out.push({ ok: true }); }
185
- catch (error) { out.push({ error }); }
186
- }
187
- return out;
188
- }
189
-
190
- // A fresh activity of this actor's, for the outbox its owner reads. Never
191
- // allowed to stop a delivery; a retry from the queue is not fresh.
192
- _sent(activity) {
193
- try { this.onSent?.(activity); } catch (e) { this.log(`owner's outbox record: ${e.message}`); }
194
- }
195
-
196
- // An inbox on a blocked domain is never delivered to, whoever still lists it.
197
- _blockedInbox(inbox) {
198
- try { return !!this.store.getBlocklist?.().domains.length && this.store.isBlocked?.(new URL(inbox).origin + '/'); }
199
- catch { return false; }
200
- }
201
-
202
- async deliver(inbox, activity) {
203
- this._sent(activity);
204
- if (this._blockedInbox(inbox)) return;
205
- // Proved before anything else, so the copy that goes on the queue is the
206
- // copy that was signed — a retry days later must not post a bare activity.
207
- const signed = await this.proofed(activity);
208
- if (this._queueIfCooling(inbox, signed)) return;
209
- const [result] = await this.deliverManyNow([{ inbox, activity: signed }]);
210
- await this._settle(inbox, signed, result);
211
- }
212
-
213
- // A host we already know is refusing: queue without asking again. This is
214
- // the path a FRESH activity takes, so without it a fan-out to a struggling
215
- // server opened one socket per follower before any of this applied.
216
- _queueIfCooling(inbox, signed) {
217
- const host = hostOf(inbox);
218
- const until = this._cooling?.get(host);
219
- if (!until || until <= Date.now()) return false;
220
- this.log(`${host} is cooling — queueing ${signed.type} rather than asking again`);
221
- this._enqueue({ inbox, activity: signed, attempts: 1, nextAt: until });
222
- return true;
223
- }
224
-
225
- // What one attempt's outcome means for the queue.
226
- async _settle(inbox, signed, result) {
227
- if (result.ok) { this.log(`delivered ${signed.type} → ${inbox}`); return; }
228
- const e = result.error;
229
- if (unsalvageable(e)) { await this._unsalvageable(inbox, e); return; }
230
- this.log(`delivery failed (${e.message}) — queued`);
231
- const wait = e.retryAfterMs || 60_000;
232
- if (aboutTheHost(e)) {
233
- this._cooling ||= new Map();
234
- this._cooling.set(hostOf(inbox), Date.now() + wait);
235
- }
236
- this._enqueue({ inbox, activity: signed, attempts: 1, nextAt: Date.now() + wait });
237
- }
238
-
239
- // Not retried, and on a 410 the followers who received there are dropped,
240
- // so the next fan-out stops asking; the followers collection is republished
241
- // through onGone. A 404 drops only this delivery.
242
- async _unsalvageable(inbox, e) {
243
- if (e.status !== 410) { this.log(`delivery dropped (${e.message}) — nothing answers there`); return; }
244
- const contacts = this.store.getContacts?.();
245
- const left = (contacts?.followers || []).filter(f => f.inbox === inbox || f.sharedInbox === inbox);
246
- this.log(`${inbox} is gone (410) — delivery dropped${left.length ? `, ${left.length} follower(s) there forgotten` : ''}`);
247
- if (!left.length) return;
248
- for (const f of left) dropFollower(contacts, f.actor, 'inbox-gone');
249
- this.store.setContacts(contacts);
250
- try { await this.onGone?.(); } catch (err) { this.log(`followers republish after 410: ${err.message}`); }
251
- }
252
-
253
- // The queue has a ceiling: a fan-out into a sea of down servers must not grow
254
- // queue.json without bound. Overflow keeps the evidence as a dead letter.
255
- _enqueue(item) {
256
- const q = this.store.getQueue();
257
- if (q.length >= MAX_QUEUE) {
258
- this.log(`delivery queue is full (${MAX_QUEUE}) — dead-lettering ${item.activity?.type} → ${item.inbox}`);
259
- this.store.addDeadLetter({ inboxUrl: item.inbox, reason: 'delivery queue full', activity: item.activity });
260
- return;
261
- }
262
- q.push(item);
263
- this.store.setQueue(q);
264
- }
265
-
266
- async deliverToAll(inboxes, activity) {
267
- this._sent(activity);
268
- // Proved once for the whole fan-out: every recipient gets the same bytes,
269
- // and one signature is computed rather than one per follower.
270
- const signed = await this.proofed(activity);
271
- // Shared inboxes deduplicate fan-out to the same server. Sent in batches
272
- // of batchSize, and a host found cooling by one batch is not asked again
273
- // by the next.
274
- const targets = [...new Set(inboxes)].filter((inbox) => !this._blockedInbox(inbox))
275
- .map((inbox) => ({ inbox, activity: signed }));
276
- for (let i = 0; i < targets.length; i += this.batchSize) {
277
- const chunk = targets.slice(i, i + this.batchSize).filter((t) => !this._queueIfCooling(t.inbox, signed));
278
- if (!chunk.length) continue;
279
- const results = await this.deliverManyNow(chunk);
280
- for (let k = 0; k < chunk.length; k++) await this._settle(chunk[k].inbox, signed, results[k]);
281
- }
282
- }
283
-
284
- // Serialized, for the same reason Intake.drain is: the tick is 60s and a
285
- // drain over slow peers outlasts it, so a second run started on top of the
286
- // first. Both read their own clone of queue.json, so both re-POSTed every due
287
- // activity — duplicate deliveries at a server that is already failing — and
288
- // both then wrote `keep` back from a stale snapshot, losing the attempt
289
- // counts that are supposed to make the backoff converge.
290
- async drainQueue() {
291
- if (this._draining) { this._drainAgain = true; return this._draining; }
292
- this._draining = this._drainQueueOnce().finally(() => {
293
- this._draining = null;
294
- if (this._drainAgain) { this._drainAgain = false; this.drainQueue().catch(e => this.log(`queue: ${e.message}`)); }
295
- });
296
- return this._draining;
297
- }
298
-
299
- // The queue is walked per HOST, not per item.
300
- //
301
- // It used to be a flat sequential loop, which had two costs against a server
302
- // that was down. Every due item for that host was POSTed — the first failure
303
- // told us nothing the code could act on — and because each request carries a
304
- // 15s deadline, K items for one dead host held the drain for up to 15K
305
- // seconds while every healthy peer's activity waited behind them. Compounding
306
- // requests at a struggling server, and head-of-line blocking of everyone
307
- // else: the shape of the incident this project has a postmortem for.
308
- //
309
- // One failure now cools the whole host for the rest of this drain, and a
310
- // Retry-After it sent decides for how long. The breaker is in memory; what
311
- // persists is nextAt, which the queue already carried.
312
- async _drainQueueOnce() {
313
- const q = this.store.getQueue();
314
- if (!q.length) return;
315
- const now = Date.now();
316
- const keep = [];
317
- // Whether anything actually moved. The only early return above is on an
318
- // EMPTY queue, so one item with a far-future nextAt used to rewrite
319
- // queue.json on all 1440 ticks of a day with byte-identical content —
320
- // PodStore.write has no equality check, and the ordinary ladder reaches
321
- // hours-long waits by attempt 6, so any peer that fails a few times got
322
- // there. A length compare is not enough: getQueue() hands back a clone, so
323
- // attempts/nextAt are mutated in place and the count stays the same.
324
- let changed = false;
325
- // Outlives the drain: a Retry-After only reached items that happened to be
326
- // due in the same pass, so a sibling due a minute later ignored it entirely.
327
- this._cooling ||= new Map(); // host → until
328
- for (const [h, until] of this._cooling) if (until <= now) this._cooling.delete(h);
329
-
330
- const ladderFor = (item) => {
331
- const base = Math.min(2 ** item.attempts, 2 ** MAX_ATTEMPTS) * 60_000;
332
- return Math.round(base * (0.85 + Math.random() * 0.3)); // jittered, not lockstep
333
- };
334
-
335
- for (const item of q) {
336
- // Due first, THEN cooling: an item that is not yet due must not have its
337
- // ladder advanced on every 60s tick of a 15-minute cooldown. Once
338
- // deferred its nextAt IS the cooldown, so it advances exactly once per
339
- // cooldown — the same rate as the item that opened the socket.
340
- if (item.nextAt > now) { keep.push(item); continue; }
341
- const host = hostOf(item.inbox);
342
- const until = this._cooling.get(host);
343
- if (until && until > now) {
344
- // A sibling already failed against this host. Defer without opening a
345
- // socket — but ADVANCE THE LADDER, or only the one item that actually
346
- // made a request ever climbs it and a queue of K items takes K times
347
- // as long to give up as the module promises.
348
- item.attempts += 1;
349
- changed = true;
350
- if (item.attempts > MAX_ATTEMPTS) {
351
- this.log(`giving up on ${item.inbox} after ${MAX_ATTEMPTS} attempts`);
352
- continue;
353
- }
354
- item.nextAt = Math.max(item.nextAt, until);
355
- keep.push(item);
356
- continue;
357
- }
358
- try {
359
- await this.deliverNow(item.inbox, item.activity);
360
- changed = true;
361
- this.log(`retry ok: ${item.activity.type} → ${item.inbox}`);
362
- } catch (e) {
363
- if (unsalvageable(e)) { changed = true; await this._unsalvageable(item.inbox, e); continue; }
364
- item.attempts += 1;
365
- changed = true;
366
- const wait = e.retryAfterMs || ladderFor(item);
367
- // Cool the host BEFORE the give-up test: a failure is evidence about
368
- // the server whether or not the item that produced it survives, and
369
- // skipping this left the flat behaviour intact for exactly the backlog
370
- // that has just aged out.
371
- if (aboutTheHost(e)) {
372
- this._cooling.set(host, now + wait);
373
- if (e.retryAfterMs) this.log(`${host} asked for ${Math.round(wait / 1000)}s — honouring it`);
374
- }
375
- if (item.attempts > MAX_ATTEMPTS) {
376
- this.log(`giving up on ${item.inbox} after ${MAX_ATTEMPTS} attempts`);
377
- continue;
378
- }
379
- item.nextAt = now + wait;
380
- keep.push(item);
381
- }
382
- }
383
- if (changed) this.store.setQueue(keep);
384
- }
385
-
386
- stop() { clearInterval(this.timer); this.timer = null; }
387
- }