fedipod-server 0.28.1 → 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 (438) hide show
  1. package/README.md +38 -34
  2. package/config/server.json +22 -0
  3. package/dist/claims.js +3 -2
  4. package/dist/directory.d.ts +2 -0
  5. package/dist/door.d.ts +4 -0
  6. package/dist/door.js +31 -0
  7. package/dist/fedipod.d.ts +16 -0
  8. package/dist/fedipod.js +13 -0
  9. package/dist/front.d.ts +3 -0
  10. package/dist/front.js +94 -0
  11. package/dist/handler.d.ts +39 -101
  12. package/dist/handler.js +86 -617
  13. package/dist/handler.jsonld +6 -30
  14. package/dist/identities.d.ts +62 -0
  15. package/dist/identities.js +236 -0
  16. package/dist/mounts.d.ts +43 -0
  17. package/dist/mounts.js +123 -0
  18. package/dist/opt-in.d.ts +46 -0
  19. package/dist/opt-in.js +176 -0
  20. package/dist/store-pod.js +37 -0
  21. package/package.json +10 -18
  22. package/lib/client/c2s.mjs +0 -582
  23. package/lib/client/localapi.mjs +0 -87
  24. package/lib/client/masto/accounts.mjs +0 -309
  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 -371
  65. package/lib/core/graphview.mjs +0 -327
  66. package/lib/core/intake/activities.mjs +0 -633
  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 -256
  70. package/lib/core/intake/index.mjs +0 -701
  71. package/lib/core/intake/notes.mjs +0 -360
  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/polls.mjs +0 -105
  76. package/lib/core/profile-page.mjs +0 -104
  77. package/lib/core/proof.mjs +0 -79
  78. package/lib/core/publisher/collections.mjs +0 -237
  79. package/lib/core/publisher/index.mjs +0 -500
  80. package/lib/core/publisher/notes.mjs +0 -453
  81. package/lib/core/publisher/questions.mjs +0 -239
  82. package/lib/core/publisher/restore.mjs +0 -224
  83. package/lib/core/shapes/activitystreams.ttl +0 -157
  84. package/lib/core/shapes/index.mjs +0 -132
  85. package/lib/core/shapes/shapes-text.mjs +0 -13
  86. package/lib/core/social.mjs +0 -531
  87. package/lib/core/storage.mjs +0 -176
  88. package/lib/core/store.mjs +0 -568
  89. package/lib/core/wire-quotes.mjs +0 -71
  90. package/lib/core/wire.mjs +0 -889
  91. package/lib/device/account.mjs +0 -87
  92. package/lib/device/admin/index.mjs +0 -13
  93. package/lib/device/admin/origins.mjs +0 -35
  94. package/lib/device/admin/routes/connections.mjs +0 -144
  95. package/lib/device/admin/routes/gateway.mjs +0 -199
  96. package/lib/device/admin/routes/lifecycle.mjs +0 -200
  97. package/lib/device/admin/routes/owner.mjs +0 -322
  98. package/lib/device/admin/routes/setup.mjs +0 -412
  99. package/lib/device/admin/routes/social.mjs +0 -188
  100. package/lib/device/admin/server.mjs +0 -95
  101. package/lib/device/admin/static.mjs +0 -247
  102. package/lib/device/admin/surface.mjs +0 -315
  103. package/lib/device/certs.mjs +0 -281
  104. package/lib/device/cli/commands/account.mjs +0 -586
  105. package/lib/device/cli/commands/run.mjs +0 -278
  106. package/lib/device/cli/commands/service.mjs +0 -221
  107. package/lib/device/cli/commands/setup.mjs +0 -447
  108. package/lib/device/cli/commands/state.mjs +0 -561
  109. package/lib/device/cli/context.mjs +0 -288
  110. package/lib/device/export-collections.mjs +0 -161
  111. package/lib/device/gateway-move.mjs +0 -58
  112. package/lib/device/home.mjs +0 -161
  113. package/lib/device/migrate.mjs +0 -115
  114. package/lib/device/ports.mjs +0 -27
  115. package/lib/device/remote.mjs +0 -54
  116. package/lib/device/setup.mjs +0 -459
  117. package/lib/device/update.mjs +0 -96
  118. package/lib/gateway/caches.mjs +0 -36
  119. package/lib/gateway/directory.mjs +0 -90
  120. package/lib/gateway/front-core.mjs +0 -970
  121. package/lib/gateway/gateway-core.mjs +0 -165
  122. package/lib/gateway/headers.mjs +0 -49
  123. package/lib/gateway/httpsig.mjs +0 -159
  124. package/lib/gateway/notices.mjs +0 -84
  125. package/lib/gateway/quiet.mjs +0 -189
  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/media.mjs +0 -27
  138. package/lib/pod/notes.mjs +0 -80
  139. package/lib/pod/notifications.mjs +0 -89
  140. package/lib/pod/outbox.mjs +0 -18
  141. package/lib/pod/package.json +0 -19
  142. package/lib/pod/policy.mjs +0 -58
  143. package/lib/pod/private.mjs +0 -19
  144. package/lib/pod/root.mjs +0 -104
  145. package/lib/pod/state.mjs +0 -40
  146. package/lib/pod/transport.mjs +0 -525
  147. package/lib/pod/urls.mjs +0 -85
  148. package/lib/server/embed.mjs +0 -423
  149. package/lib/session/README.md +0 -137
  150. package/lib/session/demo.html +0 -94
  151. package/lib/session/fedi-account.mjs +0 -408
  152. package/lib/session/fedi-login.mjs +0 -123
  153. package/lib/session/oidc-session.mjs +0 -233
  154. package/lib/session/package.json +0 -49
  155. package/lib/shared/guard.mjs +0 -213
  156. package/lib/shared/links.mjs +0 -9
  157. package/lib/shared/safefetch.mjs +0 -235
  158. package/lib/shared/ua.mjs +0 -29
  159. package/phanpy/dist/404.html +0 -40
  160. package/phanpy/dist/_headers +0 -2
  161. package/phanpy/dist/apple-touch-icon.png +0 -0
  162. package/phanpy/dist/assets/ICONS-DIPJeU0C.js +0 -2
  163. package/phanpy/dist/assets/ICONS-DIPJeU0C.js.map +0 -1
  164. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js +0 -183
  165. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js.map +0 -1
  166. package/phanpy/dist/assets/Temml-CCjoacWt.woff2 +0 -0
  167. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js +0 -2
  168. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js.map +0 -1
  169. package/phanpy/dist/assets/boosts-carousel-BiOaNdMT.jpg +0 -0
  170. package/phanpy/dist/assets/catch-up-O5q5C75Z.png +0 -0
  171. package/phanpy/dist/assets/chunk-aKtaBQYM.js +0 -1
  172. package/phanpy/dist/assets/compose-CFEx7wb4.js +0 -2
  173. package/phanpy/dist/assets/compose-CFEx7wb4.js.map +0 -1
  174. package/phanpy/dist/assets/compose-ZJN5xSb4.js +0 -35
  175. package/phanpy/dist/assets/compose-ZJN5xSb4.js.map +0 -1
  176. package/phanpy/dist/assets/debug.module-YFQgwnIr.js +0 -52
  177. package/phanpy/dist/assets/debug.module-YFQgwnIr.js.map +0 -1
  178. package/phanpy/dist/assets/dom-p1YcJ5Rw.js +0 -2
  179. package/phanpy/dist/assets/dom-p1YcJ5Rw.js.map +0 -1
  180. package/phanpy/dist/assets/home-mobile-dark@2x-Dc-J8-SM.png +0 -0
  181. package/phanpy/dist/assets/home-mobile-light@2x-Bd3fod8m.png +0 -0
  182. package/phanpy/dist/assets/home-tablet-dark@2x-BgcNI8le.png +0 -0
  183. package/phanpy/dist/assets/home-tablet-light@2x-BW2RV9T6.png +0 -0
  184. package/phanpy/dist/assets/icons/add-circle-line-WD0mwORD.js +0 -1
  185. package/phanpy/dist/assets/icons/alert-line-CpFUMf9s.js +0 -1
  186. package/phanpy/dist/assets/icons/android-2-line-Bzxnrd3S.js +0 -1
  187. package/phanpy/dist/assets/icons/announcement-line-5nwaJFJm.js +0 -1
  188. package/phanpy/dist/assets/icons/arrow-down-circle-line-a7Id9-Iv.js +0 -1
  189. package/phanpy/dist/assets/icons/arrow-down-line-B8uzXzq6.js +0 -1
  190. package/phanpy/dist/assets/icons/arrow-left-line-CGrGT9C-.js +0 -1
  191. package/phanpy/dist/assets/icons/arrow-right-line-CE-HERfX.js +0 -1
  192. package/phanpy/dist/assets/icons/arrow-to-up-line-CvdQjmcy.js +0 -1
  193. package/phanpy/dist/assets/icons/arrow-up-circle-line-DEparSNF.js +0 -1
  194. package/phanpy/dist/assets/icons/arrow-up-line-C7yBeugc.js +0 -1
  195. package/phanpy/dist/assets/icons/arrows-right-line-BtbXmJGP.js +0 -1
  196. package/phanpy/dist/assets/icons/at-line-CF66Bznk.js +0 -1
  197. package/phanpy/dist/assets/icons/attachment-line-BY8It-l9.js +0 -1
  198. package/phanpy/dist/assets/icons/blockquote-line-BS6pU_hm.js +0 -1
  199. package/phanpy/dist/assets/icons/board-line-C0UWXyA6.js +0 -1
  200. package/phanpy/dist/assets/icons/bookmark-line-1CtX5JLF.js +0 -1
  201. package/phanpy/dist/assets/icons/building-5-line-Dd59MzbO.js +0 -1
  202. package/phanpy/dist/assets/icons/bus-2-line-6_dvA0GG.js +0 -1
  203. package/phanpy/dist/assets/icons/calendar-day-line-Crpl_fmu.js +0 -1
  204. package/phanpy/dist/assets/icons/calendar-month-line-vommts2C.js +0 -1
  205. package/phanpy/dist/assets/icons/calendar-time-add-line-BU_DTlQk.js +0 -1
  206. package/phanpy/dist/assets/icons/camera-line-Cv69MEei.js +0 -1
  207. package/phanpy/dist/assets/icons/celebrate-line-B8DvIoi0.js +0 -1
  208. package/phanpy/dist/assets/icons/chart-bar-line-FK-QOmtF.js +0 -1
  209. package/phanpy/dist/assets/icons/chart-line-line-BGcJAFWw.js +0 -1
  210. package/phanpy/dist/assets/icons/chat-3-line-YFK2-hwz.js +0 -1
  211. package/phanpy/dist/assets/icons/check-circle-line-DsAxFr5-.js +0 -1
  212. package/phanpy/dist/assets/icons/clipboard-line-BBp364gJ.js +0 -1
  213. package/phanpy/dist/assets/icons/close-circle-line-CICdiuGz.js +0 -1
  214. package/phanpy/dist/assets/icons/close-line-DYrFWcjv.js +0 -1
  215. package/phanpy/dist/assets/icons/cloud-line-tiQAbah8.js +0 -1
  216. package/phanpy/dist/assets/icons/code-line-fAl8iiV3.js +0 -1
  217. package/phanpy/dist/assets/icons/comment-2-line-CR3g7WeB.js +0 -1
  218. package/phanpy/dist/assets/icons/copy-2-line-CLW69yF5.js +0 -1
  219. package/phanpy/dist/assets/icons/delete-2-line-B8xmbr4n.js +0 -1
  220. package/phanpy/dist/assets/icons/document-3-line-DBGNhAg2.js +0 -1
  221. package/phanpy/dist/assets/icons/document-line-C7mb9sb7.js +0 -1
  222. package/phanpy/dist/assets/icons/down-line-BGqSSThd.js +0 -1
  223. package/phanpy/dist/assets/icons/edit-4-line-DcgGaEhx.js +0 -1
  224. package/phanpy/dist/assets/icons/emoji-2-line-D8YgnM-y.js +0 -1
  225. package/phanpy/dist/assets/icons/exit-line-Dc07BS-x.js +0 -1
  226. package/phanpy/dist/assets/icons/external-link-line-BvpSkmjO.js +0 -1
  227. package/phanpy/dist/assets/icons/eye-2-line-CiWXx-f_.js +0 -1
  228. package/phanpy/dist/assets/icons/eye-close-line-BgTaSJ4P.js +0 -1
  229. package/phanpy/dist/assets/icons/filter-2-line-B_mR2usy.js +0 -1
  230. package/phanpy/dist/assets/icons/filter-line-C_nm-3cU.js +0 -1
  231. package/phanpy/dist/assets/icons/flag-1-line-C2HB05I0.js +0 -1
  232. package/phanpy/dist/assets/icons/forbid-circle-line-D3LTT9yd.js +0 -1
  233. package/phanpy/dist/assets/icons/formula-line-DLrt2d6j.js +0 -1
  234. package/phanpy/dist/assets/icons/grid-line-CgUmEikf.js +0 -1
  235. package/phanpy/dist/assets/icons/group-line-C5fnX0wU.js +0 -1
  236. package/phanpy/dist/assets/icons/hand-finger-2-line-BGgxbuL9.js +0 -1
  237. package/phanpy/dist/assets/icons/hashtag-line-CyTEEXBb.js +0 -1
  238. package/phanpy/dist/assets/icons/heart-crack-line-BZddbO2C.js +0 -1
  239. package/phanpy/dist/assets/icons/heart-line-CJ7K47J4.js +0 -1
  240. package/phanpy/dist/assets/icons/history-2-line-kWWvFzqv.js +0 -1
  241. package/phanpy/dist/assets/icons/history-line-bGQiwbTH.js +0 -1
  242. package/phanpy/dist/assets/icons/home-3-line-fRU1zeLG.js +0 -1
  243. package/phanpy/dist/assets/icons/information-line-iNk6-sOY.js +0 -1
  244. package/phanpy/dist/assets/icons/keyboard-line-DsCyuQNz.js +0 -1
  245. package/phanpy/dist/assets/icons/layout-4-line-CZkOX52Z.js +0 -1
  246. package/phanpy/dist/assets/icons/layout-5-line-B_znt5wO.js +0 -1
  247. package/phanpy/dist/assets/icons/left-line-eUw0tya4.js +0 -1
  248. package/phanpy/dist/assets/icons/lightning-line-DaKoDdix.js +0 -1
  249. package/phanpy/dist/assets/icons/link-2-line-DCqLmMA7.js +0 -1
  250. package/phanpy/dist/assets/icons/list-check-line-BAxosBh9.js +0 -1
  251. package/phanpy/dist/assets/icons/lock-line-CPoaXeUW.js +0 -1
  252. package/phanpy/dist/assets/icons/mail-line-B0P8aa1L.js +0 -1
  253. package/phanpy/dist/assets/icons/moon-line-CEqNAToP.js +0 -1
  254. package/phanpy/dist/assets/icons/more-1-fill-Dw2e5xab.js +0 -1
  255. package/phanpy/dist/assets/icons/more-3-line-BIiVjYTz.js +0 -1
  256. package/phanpy/dist/assets/icons/notification-line-BZZq2Gtu.js +0 -1
  257. package/phanpy/dist/assets/icons/pencil-line-CKh8-A1v.js +0 -1
  258. package/phanpy/dist/assets/icons/photo-album-line-Bnfg2u40.js +0 -1
  259. package/phanpy/dist/assets/icons/pin-line-DpTolyhs.js +0 -1
  260. package/phanpy/dist/assets/icons/play-fill-B0-G_8lX.js +0 -1
  261. package/phanpy/dist/assets/icons/qrcode-2-line-B6SPCaHn.js +0 -1
  262. package/phanpy/dist/assets/icons/quill-pen-line-B6LUrnCP.js +0 -1
  263. package/phanpy/dist/assets/icons/quote-left-fill-hQZ1cj_6.js +0 -1
  264. package/phanpy/dist/assets/icons/radar-line-CKyroTth.js +0 -1
  265. package/phanpy/dist/assets/icons/react-line-CoIKhhtK.js +0 -1
  266. package/phanpy/dist/assets/icons/refresh-2-line-D0mTF97S.js +0 -1
  267. package/phanpy/dist/assets/icons/right-line-B3KWJaqc.js +0 -1
  268. package/phanpy/dist/assets/icons/rocket-line-4KZl537D.js +0 -1
  269. package/phanpy/dist/assets/icons/round-fill-C69NTrZ0.js +0 -1
  270. package/phanpy/dist/assets/icons/round-line-B9k_1uo-.js +0 -1
  271. package/phanpy/dist/assets/icons/route-line-B28ReHcE.js +0 -1
  272. package/phanpy/dist/assets/icons/rows-4-line-CrBniagM.js +0 -1
  273. package/phanpy/dist/assets/icons/scan-line-DSf74YdP.js +0 -1
  274. package/phanpy/dist/assets/icons/search-2-line-B6geIU1z.js +0 -1
  275. package/phanpy/dist/assets/icons/settings-3-line-azJwK47w.js +0 -1
  276. package/phanpy/dist/assets/icons/settings-6-line-C_5zc5YR.js +0 -1
  277. package/phanpy/dist/assets/icons/share-2-line-D5MxWjrm.js +0 -1
  278. package/phanpy/dist/assets/icons/share-forward-line-Cp61fZzZ.js +0 -1
  279. package/phanpy/dist/assets/icons/sparkles-2-line-DYYyXTaW.js +0 -1
  280. package/phanpy/dist/assets/icons/sparkles-line-C2hY1s6I.js +0 -1
  281. package/phanpy/dist/assets/icons/time-line-BF3eet1v.js +0 -1
  282. package/phanpy/dist/assets/icons/transfer-4-line-oisfvTBw.js +0 -1
  283. package/phanpy/dist/assets/icons/translate-line-BFWol2Ce.js +0 -1
  284. package/phanpy/dist/assets/icons/unlock-line-X_x5vwv3.js +0 -1
  285. package/phanpy/dist/assets/icons/upload-3-line-DgzwUJeW.js +0 -1
  286. package/phanpy/dist/assets/icons/user-4-line-BVSynZCp.js +0 -1
  287. package/phanpy/dist/assets/icons/user-add-2-line-BlGS5Q8q.js +0 -1
  288. package/phanpy/dist/assets/icons/user-add-line-BbXdHG4z.js +0 -1
  289. package/phanpy/dist/assets/icons/user-edit-line-BFAHOV0X.js +0 -1
  290. package/phanpy/dist/assets/icons/user-follow-line-BXux0wSd.js +0 -1
  291. package/phanpy/dist/assets/icons/user-star-line-DdYlpHLU.js +0 -1
  292. package/phanpy/dist/assets/icons/user-warning-line-Cj43j0_E.js +0 -1
  293. package/phanpy/dist/assets/icons/user-x-line-DIDgNlPH.js +0 -1
  294. package/phanpy/dist/assets/icons/volume-line-Bs390KQt.js +0 -1
  295. package/phanpy/dist/assets/icons/volume-mute-line-DzlzIqFZ.js +0 -1
  296. package/phanpy/dist/assets/icons/walk-line-yNXfB-md.js +0 -1
  297. package/phanpy/dist/assets/icons/world-2-line-CenkGIwj.js +0 -1
  298. package/phanpy/dist/assets/icons/zoom-in-line-CaENUphf.js +0 -1
  299. package/phanpy/dist/assets/icons/zoom-out-line-BDNk0EWo.js +0 -1
  300. package/phanpy/dist/assets/instances-BNPptnn-.json +0 -333
  301. package/phanpy/dist/assets/locales/ar-SA-CfheRbCu.js +0 -1
  302. package/phanpy/dist/assets/locales/ca-ES-DHRW86Tz.js +0 -1
  303. package/phanpy/dist/assets/locales/cs-CZ-CKoqEuA1.js +0 -1
  304. package/phanpy/dist/assets/locales/de-DE-ByRPMRFy.js +0 -1
  305. package/phanpy/dist/assets/locales/eo-UY-CPC7wLCS.js +0 -1
  306. package/phanpy/dist/assets/locales/es-ES-dJa0Fd9t.js +0 -1
  307. package/phanpy/dist/assets/locales/eu-ES-C3djlPR2.js +0 -1
  308. package/phanpy/dist/assets/locales/fa-IR-DTT490Ck.js +0 -1
  309. package/phanpy/dist/assets/locales/fi-FI-B23MCPuz.js +0 -1
  310. package/phanpy/dist/assets/locales/fr-FR-BcaQsO5C.js +0 -1
  311. package/phanpy/dist/assets/locales/gl-ES-BR-CVKBN.js +0 -1
  312. package/phanpy/dist/assets/locales/he-IL-CfheRbCu.js +0 -1
  313. package/phanpy/dist/assets/locales/hu-HU-CfheRbCu.js +0 -1
  314. package/phanpy/dist/assets/locales/it-IT-C1136UFV.js +0 -1
  315. package/phanpy/dist/assets/locales/ja-JP-CRZmRAhD.js +0 -1
  316. package/phanpy/dist/assets/locales/kab-Cz8xH_TT.js +0 -1
  317. package/phanpy/dist/assets/locales/ko-KR-CG9UiY4o.js +0 -1
  318. package/phanpy/dist/assets/locales/lt-LT-CJcI6sHZ.js +0 -1
  319. package/phanpy/dist/assets/locales/nb-NO-CfheRbCu.js +0 -1
  320. package/phanpy/dist/assets/locales/nl-NL-DxN4Yc1t.js +0 -1
  321. package/phanpy/dist/assets/locales/oc-FR-CfheRbCu.js +0 -1
  322. package/phanpy/dist/assets/locales/pl-PL-DkwGXf6P.js +0 -1
  323. package/phanpy/dist/assets/locales/pseudo-LOCALE-CQ4XxkQ0.js +0 -1
  324. package/phanpy/dist/assets/locales/pt-BR-nGL0HdFS.js +0 -1
  325. package/phanpy/dist/assets/locales/pt-PT-Cp17aj2z.js +0 -1
  326. package/phanpy/dist/assets/locales/ru-RU-0Y8cIoaK.js +0 -1
  327. package/phanpy/dist/assets/locales/th-TH-CfheRbCu.js +0 -1
  328. package/phanpy/dist/assets/locales/tok-CfheRbCu.js +0 -1
  329. package/phanpy/dist/assets/locales/tr-TR-CfheRbCu.js +0 -1
  330. package/phanpy/dist/assets/locales/uk-UA-C5E3dFBf.js +0 -1
  331. package/phanpy/dist/assets/locales/zh-CN-BHJi7_et.js +0 -1
  332. package/phanpy/dist/assets/locales/zh-TW-CfheRbCu.js +0 -1
  333. package/phanpy/dist/assets/main-BdqNbG-a.js +0 -26
  334. package/phanpy/dist/assets/main-BdqNbG-a.js.map +0 -1
  335. package/phanpy/dist/assets/mock-home-DGhR__He.js +0 -2
  336. package/phanpy/dist/assets/mock-home-DGhR__He.js.map +0 -1
  337. package/phanpy/dist/assets/multi-column-ROck0NVt.jpg +0 -0
  338. package/phanpy/dist/assets/multi-hashtag-timeline-DH5INVHi.jpg +0 -0
  339. package/phanpy/dist/assets/nested-comments-thread-hv59kZLc.jpg +0 -0
  340. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js +0 -2
  341. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js.map +0 -1
  342. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js +0 -20
  343. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js.map +0 -1
  344. package/phanpy/dist/assets/style-B1iLPTPR.css +0 -2
  345. package/phanpy/dist/assets/temml-DuyIQMei.js +0 -97
  346. package/phanpy/dist/assets/temml-DuyIQMei.js.map +0 -1
  347. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js +0 -2
  348. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js.map +0 -1
  349. package/phanpy/dist/assets/year-in-posts-B2lywqdx.png +0 -0
  350. package/phanpy/dist/assets/year-in-posts-DJv_star.js +0 -3
  351. package/phanpy/dist/assets/year-in-posts-DJv_star.js.map +0 -1
  352. package/phanpy/dist/compose/index.html +0 -20
  353. package/phanpy/dist/favicon.ico +0 -0
  354. package/phanpy/dist/index.html +0 -73
  355. package/phanpy/dist/logo-192.png +0 -0
  356. package/phanpy/dist/logo-512.png +0 -0
  357. package/phanpy/dist/logo-badge-72.png +0 -0
  358. package/phanpy/dist/logo-maskable-512.png +0 -0
  359. package/phanpy/dist/logo-monochrome-512.png +0 -0
  360. package/phanpy/dist/logo-monochrome-maskable-512.png +0 -0
  361. package/phanpy/dist/manifest.webmanifest +0 -1
  362. package/phanpy/dist/og-image-2.jpg +0 -0
  363. package/phanpy/dist/og-image.png +0 -0
  364. package/phanpy/dist/robots.txt +0 -2
  365. package/phanpy/dist/sw.js +0 -2
  366. package/phanpy/dist/sw.js.map +0 -1
  367. package/phanpy/dist/version.json +0 -1
  368. package/run-agent.mjs +0 -897
  369. package/vendor/gate.cjs +0 -138
  370. package/vendor/idp-grant.cjs +0 -394
  371. package/vendor/jfetch.cjs +0 -16
  372. package/web/admin/actors.js +0 -145
  373. package/web/admin/bar.css +0 -126
  374. package/web/admin/bar.js +0 -99
  375. package/web/admin/client/client.js +0 -66
  376. package/web/admin/client/index.html +0 -69
  377. package/web/admin/client-pick.js +0 -79
  378. package/web/admin/common.js +0 -23
  379. package/web/admin/connections.js +0 -112
  380. package/web/admin/gateway.js +0 -133
  381. package/web/admin/group.js +0 -258
  382. package/web/admin/index.html +0 -603
  383. package/web/admin/notices-bar.js +0 -90
  384. package/web/admin/oauth-signin.mjs +0 -37
  385. package/web/admin/record.js +0 -390
  386. package/web/admin/setup/index.html +0 -241
  387. package/web/admin/setup/setup.js +0 -326
  388. package/web/admin/tokens.css +0 -68
  389. package/web/admin/upkeep.js +0 -177
  390. package/web/admin/window.css +0 -55
  391. package/web/admin/window.js +0 -136
  392. package/web/app/README.md +0 -81
  393. package/web/app/admin-facade.mjs +0 -588
  394. package/web/app/agent.mjs +0 -663
  395. package/web/app/atproto-browser.mjs +0 -86
  396. package/web/app/authorize_interaction.html +0 -56
  397. package/web/app/authorize_interaction.js +0 -69
  398. package/web/app/boot.mjs +0 -576
  399. package/web/app/deliver-relay.mjs +0 -129
  400. package/web/app/dist/boot.js +0 -34218
  401. package/web/app/dist/boot.js.map +0 -7
  402. package/web/app/dist/sw.js +0 -72810
  403. package/web/app/dist/sw.js.map +0 -7
  404. package/web/app/fediacct-browser.mjs +0 -146
  405. package/web/app/gateway-move.mjs +0 -60
  406. package/web/app/idb-kv.mjs +0 -35
  407. package/web/app/index.html +0 -242
  408. package/web/app/keys-browser.mjs +0 -71
  409. package/web/app/keystore.mjs +0 -82
  410. package/web/app/oidc-session.mjs +0 -6
  411. package/web/app/pod-auth.mjs +0 -248
  412. package/web/app/pod-remote.mjs +0 -84
  413. package/web/app/shims/_globals.mjs +0 -2
  414. package/web/app/shims/fedify-sig.mjs +0 -77
  415. package/web/app/shims/node-crypto.mjs +0 -113
  416. package/web/app/shims/node-fs.mjs +0 -17
  417. package/web/app/shims/node-path.mjs +0 -19
  418. package/web/app/shims/node-url.mjs +0 -7
  419. package/web/app/shims/prelude.js +0 -58
  420. package/web/app/shims/safefetch.mjs +0 -58
  421. package/web/app/shims/shapes-text.mjs +0 -8
  422. package/web/app/shims/web-push.mjs +0 -14
  423. package/web/app/signup.mjs +0 -318
  424. package/web/app/sw-src.mjs +0 -220
  425. package/web/app/update.js +0 -70
  426. package/web/front/admin.html +0 -55
  427. package/web/front/admin.js +0 -89
  428. package/web/front/install.sh +0 -69
  429. package/web/front/new-account.html +0 -35
  430. package/web/front/new-account.js +0 -13
  431. package/web/front/notices.html +0 -69
  432. package/web/front/notices.js +0 -107
  433. package/web/front/run.html +0 -58
  434. package/web/front/run.js +0 -195
  435. package/web/front/solid-oidc-client.js +0 -6
  436. package/web/icons/forum.svg +0 -11
  437. package/web/icons/gateway.svg +0 -14
  438. package/web/icons/local.svg +0 -11
@@ -1,248 +0,0 @@
1
- // pod-auth.mjs — the pod side of sign-in, done in the browser with no server
2
- // in between. It is the browser-native twin of lib/account.mjs and
3
- // vendor/idp-grant.cjs: create a Community Solid Server account and pod, mint a
4
- // client credential, and turn that credential into a DPoP-bound session whose
5
- // fetch writes to the pod. Everything a Node agent did against a CSS account
6
- // API, a page does here — proven cross-origin against solidcommunity.net on
7
- // 2026-09-06 (claude/validation/scn-cross-origin-spike.html).
8
- //
9
- // No dependency on lib/: lib is Node (node:crypto, undici, @fedify). This uses
10
- // only WebCrypto and fetch, so it runs in a tab and in a service worker.
11
-
12
- const b64u = (buf) => btoa(String.fromCharCode(...new Uint8Array(buf)))
13
- .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
14
- const enc = (o) => b64u(new TextEncoder().encode(JSON.stringify(o)));
15
- const sha256 = async (str) => crypto.subtle.digest('SHA-256', new TextEncoder().encode(str));
16
-
17
- // A CSS account-API call: JSON in, JSON out, the account token carried the way
18
- // CSS wants it (a bearer with its own scheme, not a cookie, in v7).
19
- async function accountFetch(url, { method = 'GET', body, token } = {}) {
20
- const headers = { accept: 'application/json' };
21
- if (body !== undefined) headers['content-type'] = 'application/json';
22
- if (token) headers.authorization = `CSS-Account-Token ${token}`;
23
- const res = await fetch(url, { method, headers, body: body === undefined ? undefined : JSON.stringify(body) });
24
- let json = null;
25
- try { json = await res.json(); } catch { /* non-JSON error bodies exist */ }
26
- return { status: res.status, json };
27
- }
28
-
29
- /** Is this origin a CSS v7 account API at all? Cheap pre-flight for the form. */
30
- export async function accountApiControls(issuer) {
31
- const origin = issuer.replace(/\/+$/, '');
32
- const { status, json } = await accountFetch(`${origin}/.account/`);
33
- if (status >= 400 || !json?.controls) return null;
34
- return json.controls;
35
- }
36
-
37
- /**
38
- * Create an account and a pod named `podName`. Idempotent on re-run: an
39
- * existing account logs in, an existing pod of the same name is reused. Refuses
40
- * to make a second pod on an account that already has one, which would give it
41
- * a second WebID a single credential could not match. Mirrors
42
- * lib/account.mjs's guards exactly, because the failure it prevents (a
43
- * credential bound to the wrong WebID that 403s every write) is the same here.
44
- */
45
- export async function createAccountWithPod({ issuer, email, password, podName }) {
46
- const origin = issuer.replace(/\/+$/, '');
47
- const accountRoot = `${origin}/.account/`;
48
-
49
- let token;
50
- const login = await accountFetch(`${accountRoot}login/password/`, { method: 'POST', body: { email, password } });
51
- if (login.status < 400 && login.json?.authorization) {
52
- token = login.json.authorization;
53
- } else {
54
- const create = await accountFetch(`${accountRoot}account/`, { method: 'POST' });
55
- if (!create.json?.authorization) {
56
- throw new Error(`could not create an account at ${origin} (HTTP ${create.status})`
57
- + ` — is sign-up open there? ${create.json?.message || ''}`);
58
- }
59
- token = create.json.authorization;
60
- const pwCreate = (await accountFetch(accountRoot, { token })).json?.controls?.password?.create;
61
- if (!pwCreate) throw new Error('this server is not a CSS v7 account API (no password control)');
62
- const pw = await accountFetch(pwCreate, { method: 'POST', token, body: { email, password } });
63
- if (pw.status >= 400) throw new Error(`could not set the password (HTTP ${pw.status}): ${pw.json?.message || ''}`);
64
- }
65
-
66
- const podCreate = (await accountFetch(accountRoot, { token })).json?.controls?.account?.pod;
67
- if (!podCreate) throw new Error('this server does not offer pod creation through its account API');
68
-
69
- const findOwn = async () => {
70
- const pods = (await accountFetch(podCreate, { token })).json?.pods || {};
71
- return Object.entries(pods).find(([url]) => {
72
- try {
73
- const u = new URL(url);
74
- return u.hostname === podName || u.hostname.startsWith(`${podName}.`)
75
- || u.pathname.split('/').filter(Boolean).includes(podName);
76
- } catch { return false; }
77
- }) || null;
78
- };
79
- const owned = Object.keys((await accountFetch(podCreate, { token })).json?.pods || {});
80
- if (owned.length && !(await findOwn())) {
81
- throw new Error(`${email} already has a pod on ${new URL(origin).host} — one account, one pod.`
82
- + ' A second identity needs its own account. Nothing was created.');
83
- }
84
- const made = await accountFetch(podCreate, { method: 'POST', token, body: { name: podName } });
85
- let pod = made.json?.pod || made.json?.podBaseUrl || null;
86
- let webId = made.json?.webId || null;
87
- if (made.status >= 400 || !pod) {
88
- const own = await findOwn();
89
- if (own) { pod = own[0]; webId = webId || own[1]?.webId || null; }
90
- else if (made.status >= 400) throw new Error(`pod creation failed (HTTP ${made.status}): ${made.json?.message || ''}`);
91
- }
92
- if (!pod) throw new Error('the server did not report a pod URL');
93
- return { pod: pod.endsWith('/') ? pod : pod + '/', webId, accountToken: token };
94
- }
95
-
96
- /**
97
- * Mint a client credential against the account. `accountToken` reuses a login
98
- * from createAccountWithPod; otherwise email+password logs in. Returns the
99
- * credential record the agent expects, minus remotePod (the caller adds it).
100
- */
101
- export async function mintCredential({ issuer, email, password, webId, podUrl, accountToken, name = 'fedipod' }) {
102
- const origin = issuer.replace(/\/+$/, '');
103
- const accountRoot = `${origin}/.account/`;
104
-
105
- let token = accountToken;
106
- if (!token) {
107
- // Sign in with the identifier the form gave (an email). If that account does
108
- // not own the target pod — or the sign-in fails outright — fall back to the
109
- // pod's subdomain as a username: older solidcommunity.net accounts sign in by
110
- // username, not email. Done behind the scenes so the form only asks for an email.
111
- const tryLogin = async (id) => {
112
- const r = await accountFetch(`${accountRoot}login/password/`, { method: 'POST', body: { email: id, password } });
113
- return (r.status < 400 && r.json?.authorization) ? r.json.authorization : null;
114
- };
115
- const ownsPod = async (tok) => {
116
- if (!podUrl) return true;
117
- try {
118
- const ctl = (await accountFetch(accountRoot, { token: tok })).json?.controls?.account?.webId;
119
- const links = ctl ? (await accountFetch(ctl, { token: tok })).json?.webIdLinks : null;
120
- return Object.keys(links || {}).some((w) => new URL(w).origin === new URL(podUrl).origin);
121
- } catch { return false; }
122
- };
123
- token = await tryLogin(email);
124
- let sub = null; try { sub = podUrl ? new URL(podUrl).host.split('.')[0] : null; } catch { /* podUrl not a URL */ }
125
- if (sub && sub !== email && (!token || !(await ownsPod(token)))) {
126
- const alt = await tryLogin(sub);
127
- if (alt) token = alt;
128
- }
129
- if (!token) throw new Error('account login failed — check the email or username and the password');
130
- }
131
-
132
- const controls = (await accountFetch(accountRoot, { token })).json?.controls;
133
- const ccUrl = controls?.account?.clientCredentials;
134
- if (!ccUrl) throw new Error('this server is not a CSS account API (no clientCredentials control)');
135
-
136
- let wid = webId;
137
- if (!wid) {
138
- const linkCtl = controls?.account?.webId;
139
- const links = linkCtl ? (await accountFetch(linkCtl, { token })).json?.webIdLinks : null;
140
- const all = links ? Object.keys(links) : [];
141
- if (!all.length) throw new Error('no WebID is linked to this account');
142
- if (podUrl) {
143
- // The credential MUST be for a WebID that owns the target pod, or every
144
- // write to it is rejected. Never fall back to an unrelated WebID: a
145
- // credential bound to the wrong identity 401s/403s on the pod, which is
146
- // the opaque "could not store the key" people then see.
147
- let origins = [];
148
- try { origins = all.filter((w) => new URL(w).origin === new URL(podUrl).origin); } catch { /* podUrl not a URL */ }
149
- if (!origins.length) {
150
- throw new Error(`the account you signed in with does not own ${new URL(podUrl).origin}. `
151
- + `It is linked to ${all.length} WebID${all.length > 1 ? 's' : ''} — on `
152
- + `${all.map((w) => new URL(w).host).join(', ')} — none of them this pod. `
153
- + 'Sign in with the account that owns this pod, or let FediPod make you a new one.');
154
- }
155
- wid = origins[0];
156
- } else {
157
- wid = all[0];
158
- }
159
- }
160
-
161
- const made = await accountFetch(ccUrl, { method: 'POST', token, body: { name, webId: wid } });
162
- if (made.status >= 400 || !made.json?.secret) throw new Error(`mint failed (HTTP ${made.status}): ${made.json?.message || ''}`);
163
- const tokenEndpoint = await discoverTokenEndpoint(origin);
164
- return { clientId: made.json.id, secret: made.json.secret, webId: wid, tokenEndpoint,
165
- resource: made.json.resource, issuerOrigin: origin,
166
- // Carried so sign-up can hand it straight back to revokeCredential. It is a
167
- // session token for the ACCOUNT — never stored, never written to the pod,
168
- // and gone with the tab.
169
- accountToken: token };
170
- }
171
-
172
- /**
173
- * Delete a client credential.
174
- *
175
- * The one sign-up mints is full, permanent access to the pod, and it is needed
176
- * only while sign-up is running — the agent itself runs on the Solid-OIDC
177
- * session. Leaving it behind meant every account carried an orphaned key that
178
- * nothing held and nobody would think to revoke, while the page told the user
179
- * it was "stored in this browser", which it never was.
180
- *
181
- * Best effort by design: a server that will not delete it leaves a credential
182
- * the owner can still revoke from their pod's own account page, and saying so
183
- * is better than failing a sign-up that otherwise worked.
184
- */
185
- export async function revokeCredential({ resource, accountToken }) {
186
- if (!resource || !accountToken) return false;
187
- try {
188
- const r = await accountFetch(resource, { method: 'DELETE', token: accountToken });
189
- return r.status < 400;
190
- } catch { return false; }
191
- }
192
-
193
- /** The OIDC token endpoint, from the issuer's discovery document. */
194
- export async function discoverTokenEndpoint(issuer) {
195
- const origin = issuer.replace(/\/+$/, '');
196
- try {
197
- const res = await fetch(`${origin}/.well-known/openid-configuration`, { headers: { accept: 'application/json' } });
198
- if (res.ok) {
199
- const doc = await res.json();
200
- if (doc.token_endpoint) return doc.token_endpoint;
201
- }
202
- } catch { /* fall through to the CSS default */ }
203
- return `${origin}/.oidc/token`;
204
- }
205
-
206
- /**
207
- * A DPoP-bound session: one ES256 proof key, a client-credentials access token
208
- * bound to it, and a `fetch` that signs every request. The same key must sign
209
- * the token request and every resource request, or the token's binding fails,
210
- * so the key is made once and kept.
211
- */
212
- export async function makeDpopSession({ clientId, secret, tokenEndpoint }) {
213
- const proofKey = await crypto.subtle.generateKey({ name: 'ECDSA', namedCurve: 'P-256' }, false, ['sign']);
214
- const jwk = await crypto.subtle.exportKey('jwk', proofKey.publicKey);
215
- const publicJwk = { kty: jwk.kty, crv: jwk.crv, x: jwk.x, y: jwk.y };
216
-
217
- const proof = async (htm, htu, ath) => {
218
- const header = { typ: 'dpop+jwt', alg: 'ES256', jwk: publicJwk };
219
- const payload = { htm, htu: htu.split('#')[0], jti: crypto.randomUUID(), iat: Math.floor(Date.now() / 1000), ...(ath ? { ath } : {}) };
220
- const data = `${enc(header)}.${enc(payload)}`;
221
- const sig = await crypto.subtle.sign({ name: 'ECDSA', hash: 'SHA-256' }, proofKey.privateKey, new TextEncoder().encode(data));
222
- return `${data}.${b64u(sig)}`;
223
- };
224
-
225
- let token = null; let expiresAt = 0;
226
- const refresh = async () => {
227
- const basic = btoa(`${encodeURIComponent(clientId)}:${encodeURIComponent(secret)}`);
228
- const res = await fetch(tokenEndpoint, {
229
- method: 'POST',
230
- headers: { authorization: `Basic ${basic}`, 'content-type': 'application/x-www-form-urlencoded', dpop: await proof('POST', tokenEndpoint) },
231
- body: 'grant_type=client_credentials&scope=webid',
232
- });
233
- const tok = await res.json().catch(() => ({}));
234
- if (!tok.access_token) throw new Error(`token request failed (HTTP ${res.status}): ${tok.error || ''}`);
235
- token = tok.access_token;
236
- expiresAt = Date.now() + Math.max(30, (tok.expires_in || 300) - 30) * 1000;
237
- return token;
238
- };
239
-
240
- const authFetch = async (url, init = {}) => {
241
- if (!token || Date.now() > expiresAt) await refresh();
242
- const ath = b64u(await sha256(token));
243
- const headers = { ...(init.headers || {}), authorization: `DPoP ${token}`, dpop: await proof((init.method || 'GET'), url, ath) };
244
- return fetch(url, { ...init, headers });
245
- };
246
-
247
- return { fetch: authFetch, refresh };
248
- }
@@ -1,84 +0,0 @@
1
- // pod-remote.mjs — the browser's pod transport, over a DPoP/OIDC session.
2
- //
3
- // The conversation with the pod — verbs, ACL documents, the deletion deny-list,
4
- // the Retry-After cooldown, container listings — is lib/pod/transport.mjs, the
5
- // same code the Node agent runs. This used to be a hand-kept fork of that file,
6
- // and the fork had drifted: no cooldown at all for a 429 without a Retry-After
7
- // header, no byte cap on a listing from a public-Append inbox, a swallowed
8
- // parse failure, and probes that were neither counted nor held back. Those are
9
- // gone with the fork.
10
- //
11
- // What genuinely differs, and all that is left here: this side retries a
12
- // dropped connection, and waits a throttle out instead of failing fast.
13
-
14
- import { PodTransport } from '../../lib/pod/transport.mjs';
15
-
16
- export { protectedFromDeletion } from '../../lib/pod/transport.mjs';
17
-
18
- // Retry transient edge throttling (dropped connections, 429/503) with backoff.
19
- const RETRY_MAX = 5;
20
- const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
21
- const backoff = (n) => Math.min(5000, 400 * 2 ** n) + Math.floor(Math.random() * 250);
22
-
23
- // A tighter ceiling than the Node side's thirty minutes: a tab is a person
24
- // waiting, and a hostile or confused header must not park them for half an hour.
25
- const COOLDOWN_MAX_MS = 5 * 60_000;
26
-
27
- export class BrowserRemotePod extends PodTransport {
28
- constructor(session, { webId, log = () => {}, role = 'agent' } = {}) {
29
- super(session, {
30
- webId,
31
- log,
32
- role,
33
- runtime: 'browser',
34
- // Wait the throttle out rather than refusing: there is a person here, and
35
- // an operation that resumes in four seconds beats one that fails and asks
36
- // them to try again.
37
- cooldownMode: 'wait',
38
- maxCooldownMs: COOLDOWN_MAX_MS,
39
- });
40
- }
41
-
42
- async warmup() { /* the DPoP session refreshes lazily */ }
43
-
44
- /**
45
- * solidcommunity.net sits behind an edge (Cloudflare) that throttles a burst
46
- * of requests: during first-boot provisioning the agent makes ~15 rapid
47
- * calls, and one comes back as a dropped connection ("Failed to fetch") or a
48
- * 429/503. A single dropped write used to abort the whole boot. Retry those
49
- * with escalating backoff — the throttle window clears in under a few seconds.
50
- * Safe to retry: a thrown request never reached the server, and a 429/503 was
51
- * refused, not applied.
52
- *
53
- * This overrides `_send`, not `fetch`, so it cannot skip the url map, the
54
- * cooldown accounting or the deletion deny-list — all of which sit in `fetch`
55
- * above it. The pod-wide pause is armed there too, so a retry here waits for
56
- * the whole pod rather than each call climbing its own ladder.
57
- */
58
- async _send(url, init) {
59
- let attempt = 0;
60
- for (;;) {
61
- try {
62
- const res = await this.session.fetch(url, init);
63
- if ((res.status === 429 || res.status === 503) && attempt < RETRY_MAX) {
64
- // Arm the pod-wide pause from THIS answer before retrying. The retry
65
- // happens inside `fetch`, so waiting for the outer `_observe` would
66
- // mean climbing the whole ladder while ignoring the Retry-After the
67
- // server just gave us. `_cooldownGate` then sleeps whatever was
68
- // armed; when the server named no delay, nothing is armed and the
69
- // backoff below paces it instead.
70
- this._observe(res);
71
- if (this.pausedUntil > Date.now()) await this._cooldownGate();
72
- else await sleep(backoff(attempt));
73
- attempt++;
74
- continue;
75
- }
76
- return res;
77
- } catch (e) {
78
- if (attempt >= RETRY_MAX) throw e;
79
- this.log(`[${this.label}] ${init?.method || 'GET'} ${url} failed (${e.message}); retry ${attempt + 1}/${RETRY_MAX}`);
80
- await sleep(backoff(attempt++));
81
- }
82
- }
83
- }
84
- }
@@ -1,2 +0,0 @@
1
- export const URL = globalThis.URL;
2
- export const URLSearchParams = globalThis.URLSearchParams;
@@ -1,77 +0,0 @@
1
- // fedify-sig.mjs — a browser stand-in for @fedify/fedify/sig.
2
- //
3
- // Fedify itself will not run in a browser: it reaches for node:dns, node:net
4
- // and node:process to resolve and fetch actors. Only two of its functions are
5
- // on the agent's path:
6
- //
7
- // signRequest — outbound HTTP Signatures (draft-cavage), what a remote
8
- // server verifies. Implemented here with WebCrypto and
9
- // proven byte-identical to Fedify's own output for the
10
- // same request and key (claude/validation/signing-shim/).
11
- // verifyRequestDetailed — inbound verification. The browser agent never runs
12
- // it: it trusts the gateway's receipt, exactly as the
13
- // agent does in the gateway's `trust` mode. Stubbed so a
14
- // bundled import resolves.
15
- //
16
- // A browser cannot set Date or Host on a request (both are forbidden header
17
- // names) and does not add them itself, so a signature that covers them can only
18
- // travel through the relay, which sends the signed headers verbatim. That is why
19
- // the real work is `sign()`, which returns the signed headers as data. The
20
- // browser deliverer hands that to the relay; `signRequest` wraps it into a
21
- // Request for the Fedify-shaped callers and the byte-equality proof.
22
-
23
- const b64 = (buf) => btoa(String.fromCharCode(...new Uint8Array(buf)));
24
-
25
- /**
26
- * Sign a request and return the parts to send: the covered header names, the
27
- * header values (Date/Host/Digest filled in), the body, and the target. Host is
28
- * always signed from the URL; the relay's own fetch sends the matching Host.
29
- */
30
- export async function sign({ url, method = 'POST', headers = {}, body }, privateKey, keyId) {
31
- const u = new URL(url);
32
- const m = method.toUpperCase();
33
- const signed = {};
34
- for (const [k, v] of Object.entries(headers)) {
35
- const name = k.toLowerCase();
36
- if (name !== 'signature' && name !== 'host') signed[name] = v;
37
- }
38
-
39
- let bodyBytes;
40
- if (m !== 'GET' && m !== 'HEAD' && body != null) {
41
- bodyBytes = typeof body === 'string' ? new TextEncoder().encode(body) : new Uint8Array(body);
42
- if (!('digest' in signed)) signed.digest = `SHA-256=${b64(await crypto.subtle.digest('SHA-256', bodyBytes))}`;
43
- }
44
- if (!('date' in signed)) signed.date = new Date().toUTCString();
45
- signed.host = u.host;
46
-
47
- const names = ['(request-target)', ...Object.keys(signed).sort()];
48
- const signingString = names.map((n) => (n === '(request-target)'
49
- ? `(request-target): ${m.toLowerCase()} ${u.pathname}${u.search}`
50
- : `${n}: ${signed[n]}`)).join('\n');
51
- const sig = await crypto.subtle.sign('RSASSA-PKCS1-v1_5', privateKey, new TextEncoder().encode(signingString));
52
- signed.signature = `keyId="${keyId.href || keyId}",algorithm="rsa-sha256",headers="${names.join(' ')}",signature="${b64(sig)}"`;
53
-
54
- return { url: u.href, method: m, headers: signed, body: bodyBytes ?? null, covered: names };
55
- }
56
-
57
- /** Fedify's signRequest shape: sign, then return a Request. Forbidden headers
58
- * (Host, Date) survive here only where the runtime allows them (Node); the
59
- * browser delivery path uses sign() and the relay instead. */
60
- export async function signRequest(request, privateKey, keyId) {
61
- const headers = {};
62
- for (const [k, v] of request.headers) headers[k] = v;
63
- const body = (request.method === 'GET' || request.method === 'HEAD')
64
- ? undefined : new Uint8Array(await request.clone().arrayBuffer());
65
- const s = await sign({ url: request.url, method: request.method, headers, body }, privateKey, keyId);
66
- const out = new Headers();
67
- for (const [k, v] of Object.entries(s.headers)) out.set(k, v);
68
- const init = { method: s.method, headers: out, signal: request.signal };
69
- if (s.body) init.body = s.body;
70
- return new Request(request.url, init);
71
- }
72
-
73
- // The browser agent verifies nothing itself — the gateway already did, and its
74
- // receipt is what the drain trusts. Present so the import resolves.
75
- export async function verifyRequestDetailed() {
76
- return { success: false, reason: 'the browser agent does not verify; it trusts the gateway receipt' };
77
- }
@@ -1,113 +0,0 @@
1
- // node-crypto.mjs — a browser stand-in for node:crypto, for the agent bundle.
2
- //
3
- // The agent uses only a small synchronous slice: SHA-256 (and HMAC-SHA-256)
4
- // hashing, random bytes, constant-time compare — plus WebCrypto (crypto.subtle),
5
- // which the browser has natively. Rather than pull in crypto-browserify (which
6
- // drags Node streams into the bundle), SHA-256 is implemented here in pure JS.
7
- // Key generation and KeyObject calls are never reached: keys are made by
8
- // keystore.mjs and loaded straight into WebCrypto.
9
-
10
- const K = new Uint32Array([
11
- 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
12
- 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
13
- 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
14
- 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
15
- 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
16
- 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
17
- 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
18
- 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2]);
19
- const rotr = (x, n) => (x >>> n) | (x << (32 - n));
20
-
21
- function sha256(bytes) {
22
- const l = bytes.length;
23
- const withOne = l + 1;
24
- const k = (56 - (withOne % 64) + 64) % 64;
25
- const total = withOne + k + 8;
26
- const m = new Uint8Array(total);
27
- m.set(bytes); m[l] = 0x80;
28
- const bits = l * 8;
29
- const dv = new DataView(m.buffer);
30
- dv.setUint32(total - 4, bits >>> 0);
31
- dv.setUint32(total - 8, Math.floor(bits / 0x100000000));
32
- const H = new Uint32Array([0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19]);
33
- const w = new Uint32Array(64);
34
- for (let i = 0; i < total; i += 64) {
35
- for (let t = 0; t < 16; t++) w[t] = dv.getUint32(i + t * 4);
36
- for (let t = 16; t < 64; t++) {
37
- const s0 = rotr(w[t-15],7) ^ rotr(w[t-15],18) ^ (w[t-15] >>> 3);
38
- const s1 = rotr(w[t-2],17) ^ rotr(w[t-2],19) ^ (w[t-2] >>> 10);
39
- w[t] = (w[t-16] + s0 + w[t-7] + s1) >>> 0;
40
- }
41
- let [a,b,c,d,e,f,g,h] = H;
42
- for (let t = 0; t < 64; t++) {
43
- const S1 = rotr(e,6) ^ rotr(e,11) ^ rotr(e,25);
44
- const ch = (e & f) ^ (~e & g);
45
- const t1 = (h + S1 + ch + K[t] + w[t]) >>> 0;
46
- const S0 = rotr(a,2) ^ rotr(a,13) ^ rotr(a,22);
47
- const maj = (a & b) ^ (a & c) ^ (b & c);
48
- const t2 = (S0 + maj) >>> 0;
49
- h=g; g=f; f=e; e=(d+t1)>>>0; d=c; c=b; b=a; a=(t1+t2)>>>0;
50
- }
51
- H[0]=(H[0]+a)>>>0; H[1]=(H[1]+b)>>>0; H[2]=(H[2]+c)>>>0; H[3]=(H[3]+d)>>>0;
52
- H[4]=(H[4]+e)>>>0; H[5]=(H[5]+f)>>>0; H[6]=(H[6]+g)>>>0; H[7]=(H[7]+h)>>>0;
53
- }
54
- const out = new Uint8Array(32);
55
- new DataView(out.buffer).setUint32(0, H[0]); new DataView(out.buffer).setUint32(4, H[1]);
56
- new DataView(out.buffer).setUint32(8, H[2]); new DataView(out.buffer).setUint32(12, H[3]);
57
- new DataView(out.buffer).setUint32(16, H[4]); new DataView(out.buffer).setUint32(20, H[5]);
58
- new DataView(out.buffer).setUint32(24, H[6]); new DataView(out.buffer).setUint32(28, H[7]);
59
- return out;
60
- }
61
- function hmacSha256(key, msg) {
62
- if (key.length > 64) key = sha256(key);
63
- const pad = new Uint8Array(64); pad.set(key);
64
- const ipad = new Uint8Array(64); const opad = new Uint8Array(64);
65
- for (let i = 0; i < 64; i++) { ipad[i] = pad[i] ^ 0x36; opad[i] = pad[i] ^ 0x5c; }
66
- const inner = sha256(concat(ipad, msg));
67
- return sha256(concat(opad, inner));
68
- }
69
- const concat = (a, b) => { const o = new Uint8Array(a.length + b.length); o.set(a); o.set(b, a.length); return o; };
70
- const toBytes = (data, enc) => {
71
- if (data == null) return new Uint8Array(0);
72
- if (typeof data === 'string') {
73
- if (enc === 'hex') return Uint8Array.from(data.match(/.{1,2}/g) || [], (h) => parseInt(h, 16));
74
- if (enc === 'base64') return Uint8Array.from(atob(data), (c) => c.charCodeAt(0));
75
- return new TextEncoder().encode(data);
76
- }
77
- return data instanceof Uint8Array ? data : new Uint8Array(data);
78
- };
79
- const encode = (bytes, enc) => {
80
- if (!enc || enc === 'buffer') return bytes;
81
- if (enc === 'hex') return [...bytes].map((b) => b.toString(16).padStart(2, '0')).join('');
82
- const b64 = btoa(String.fromCharCode(...bytes));
83
- if (enc === 'base64url') return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
84
- return b64; // base64
85
- };
86
-
87
- export function createHash(alg) {
88
- if (alg !== 'sha256') throw new Error(`node-crypto shim: only sha256 is implemented (got ${alg})`);
89
- let acc = new Uint8Array(0);
90
- return { update(d, e) { acc = concat(acc, toBytes(d, e)); return this; }, digest(enc) { return encode(sha256(acc), enc); } };
91
- }
92
- export function createHmac(alg, key) {
93
- if (alg !== 'sha256') throw new Error(`node-crypto shim: only hmac-sha256 is implemented (got ${alg})`);
94
- const k = toBytes(key); let acc = new Uint8Array(0);
95
- return { update(d, e) { acc = concat(acc, toBytes(d, e)); return this; }, digest(enc) { return encode(hmacSha256(k, acc), enc); } };
96
- }
97
- // A Buffer, not a bare Uint8Array, so callers' `.toString('hex')` works (the
98
- // prelude defines Buffer before any bundle code runs).
99
- export function randomBytes(n) { const b = new Uint8Array(n); crypto.getRandomValues(b); return globalThis.Buffer ? globalThis.Buffer.from(b) : b; }
100
- export const webcrypto = globalThis.crypto;
101
- export const randomUUID = () => globalThis.crypto.randomUUID();
102
- export function timingSafeEqual(a, b) {
103
- if (a.length !== b.length) return false;
104
- let out = 0; for (let i = 0; i < a.length; i++) out |= a[i] ^ b[i];
105
- return out === 0;
106
- }
107
- const unavailable = (name) => () => { throw new Error(`node:crypto ${name} is not available in the browser agent`); };
108
- export const generateKeyPairSync = unavailable('generateKeyPairSync');
109
- export const createPrivateKey = unavailable('createPrivateKey');
110
- export const createPublicKey = unavailable('createPublicKey');
111
- export const scryptSync = unavailable('scryptSync');
112
- export default { createHash, createHmac, randomBytes, webcrypto, randomUUID, timingSafeEqual,
113
- generateKeyPairSync, createPrivateKey, createPublicKey, scryptSync };
@@ -1,17 +0,0 @@
1
- // node-fs.mjs — the tiny synchronous slice of node:fs touched at import time.
2
- // ua.mjs and publisher.mjs read package.json for the version; everything else
3
- // (FileStorage, home, certs) is never constructed in the browser.
4
- const PKG = JSON.stringify({ version: '0.18.0', name: 'fedipod' });
5
- export const readFileSync = (p) => {
6
- if (String(p).endsWith('package.json')) return PKG;
7
- throw new Error(`node:fs readFileSync(${p}) is not available in the browser agent`);
8
- };
9
- export const existsSync = () => false;
10
- const nope = (name) => () => { throw new Error(`node:fs ${name} is not available in the browser agent`); };
11
- export const writeFileSync = nope('writeFileSync');
12
- export const mkdirSync = nope('mkdirSync');
13
- export const readdirSync = () => [];
14
- export const statSync = nope('statSync');
15
- export const unlinkSync = nope('unlinkSync');
16
- export const rmSync = nope('rmSync');
17
- export default { readFileSync, existsSync, writeFileSync, mkdirSync, readdirSync, statSync, unlinkSync, rmSync };
@@ -1,19 +0,0 @@
1
- // node-path.mjs — the POSIX slice of node:path the agent uses in the browser.
2
- const normalize = (p) => {
3
- const up = p.startsWith('/');
4
- const parts = [];
5
- for (const seg of p.split('/')) {
6
- if (!seg || seg === '.') continue;
7
- if (seg === '..') { if (parts.length && parts[parts.length - 1] !== '..') parts.pop(); else if (!up) parts.push('..'); }
8
- else parts.push(seg);
9
- }
10
- return (up ? '/' : '') + parts.join('/') || (up ? '/' : '.');
11
- };
12
- const join = (...segs) => normalize(segs.filter((s) => s != null && s !== '').join('/'));
13
- const dirname = (p) => { const i = p.replace(/\/$/, '').lastIndexOf('/'); return i <= 0 ? (i === 0 ? '/' : '.') : p.slice(0, i); };
14
- const basename = (p, ext) => { let b = p.slice(p.lastIndexOf('/') + 1); if (ext && b.endsWith(ext)) b = b.slice(0, -ext.length); return b; };
15
- const extname = (p) => { const b = basename(p); const i = b.lastIndexOf('.'); return i > 0 ? b.slice(i) : ''; };
16
- const resolve = (...segs) => join(...segs);
17
- const posix = { join, dirname, basename, extname, resolve, normalize, sep: '/' };
18
- export { join, dirname, basename, extname, resolve, normalize, posix };
19
- export default { join, dirname, basename, extname, resolve, normalize, posix, sep: '/' };
@@ -1,7 +0,0 @@
1
- // node-url.mjs — the node:url slice the agent uses. URL is native; the two
2
- // file-path converters are only ever called with data: or http URLs in the
3
- // browser build, so plain string surgery suffices.
4
- export const fileURLToPath = (u) => { const s = typeof u === 'string' ? u : u.href; return s.replace(/^file:\/\//, ''); };
5
- export const pathToFileURL = (p) => new URL('file://' + (p.startsWith('/') ? p : '/' + p));
6
- export { URL, URLSearchParams } from './_globals.mjs';
7
- export default { URL: globalThis.URL, URLSearchParams: globalThis.URLSearchParams, fileURLToPath, pathToFileURL };
@@ -1,58 +0,0 @@
1
- // prelude.js — globals the bundled Node code expects, set once before it runs.
2
- // Injected as the bundle's banner. Kept minimal and local: Buffer is a subclass
3
- // of Uint8Array (not a prototype patch), so nothing else in the page is touched.
4
- globalThis.process ??= { env: {}, argv: [], platform: 'browser', cwd: () => '/', nextTick: (f, ...a) => queueMicrotask(() => f(...a)) };
5
- globalThis.Buffer ??= (() => {
6
- const b64 = (u) => btoa(String.fromCharCode(...u));
7
- const hex = (u) => { let s = ''; for (const b of u) s += b.toString(16).padStart(2, '0'); return s; };
8
- class Buf extends Uint8Array {
9
- // Uint8Array.indexOf finds a single BYTE; Node's Buffer finds a whole
10
- // subsequence, and lib/mastoapi.mjs's readMultipart walks a multipart body
11
- // by searching for the boundary and for the CRLFCRLF that ends each part's
12
- // headers. Without this every search returned -1, so an upload came back
13
- // "file required" however good the bytes were.
14
- indexOf(needle, from = 0) {
15
- const pat = typeof needle === 'string' ? new TextEncoder().encode(needle)
16
- : needle instanceof Uint8Array ? needle : null;
17
- if (pat === null) return super.indexOf(needle, from); // a single byte
18
- if (pat.length === 0) return Math.min(from, this.length);
19
- const last = this.length - pat.length;
20
- outer: for (let i = Math.max(0, from); i <= last; i++) {
21
- for (let j = 0; j < pat.length; j++) if (this[i + j] !== pat[j]) continue outer;
22
- return i;
23
- }
24
- return -1;
25
- }
26
- toString(enc) {
27
- if (enc === 'hex') return hex(this);
28
- if (enc === 'base64') return b64(this);
29
- if (enc === 'base64url') return b64(this).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
30
- return new TextDecoder().decode(this);
31
- }
32
- }
33
- const fromString = (s, enc) => {
34
- if (enc === 'hex') return Buf.from(s.match(/.{1,2}/g) || [], (h) => parseInt(h, 16));
35
- if (enc === 'base64' || enc === 'base64url') {
36
- const n = s.replace(/-/g, '+').replace(/_/g, '/');
37
- return Buf.from(atob(n + '==='.slice((n.length + 3) % 4)), (c) => c.charCodeAt(0));
38
- }
39
- return Buf.from(new TextEncoder().encode(s));
40
- };
41
- const from = (d, enc) => {
42
- if (typeof d === 'string') return fromString(d, enc);
43
- if (typeof d === 'function') { const args = arguments; return Uint8Array.from.call(Buf, args[0], args[1]); }
44
- const b = new Buf(d.length); b.set(d); return b;
45
- };
46
- const fromAny = (d, e) => {
47
- if (typeof d === 'string') return fromString(d, e);
48
- if (typeof e === 'function') { const arr = Array.from(d, e); const b = new Buf(arr.length); b.set(arr); return b; }
49
- if (d instanceof Uint8Array || Array.isArray(d)) { const b = new Buf(d.length); b.set(d); return b; }
50
- return new Buf(d);
51
- };
52
- return {
53
- from: fromAny,
54
- concat: (list) => { const n = list.reduce((s, x) => s + x.length, 0); const o = new Buf(n); let i = 0; for (const x of list) { o.set(x, i); i += x.length; } return o; },
55
- alloc: (n) => new Buf(n),
56
- isBuffer: (x) => x instanceof Uint8Array,
57
- };
58
- })();