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,6 +0,0 @@
1
- // oidc-session.mjs — FediPod's Solid-OIDC session: the solid-oidc-session
2
- // library (lib/session/) bound to this app's database and client name. The
3
- // page and the service worker both import this file, so both read one session.
4
- import { solidOidcSession } from '../../lib/session/oidc-session.mjs';
5
-
6
- export const { beginLogin, completeLogin, getSession, signOut } = solidOidcSession({ dbName: 'fedipod-oidc', clientName: 'FediPod' });
@@ -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
- })();