fedipod-server 0.29.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (444) hide show
  1. package/README.md +16 -6
  2. package/dist/claims.d.ts +2 -0
  3. package/dist/claims.js +13 -4
  4. package/dist/door.d.ts +4 -0
  5. package/dist/door.js +31 -0
  6. package/dist/fedipod.d.ts +15 -0
  7. package/dist/fedipod.js +13 -0
  8. package/dist/front.d.ts +3 -0
  9. package/dist/front.js +92 -0
  10. package/dist/handler.d.ts +36 -101
  11. package/dist/handler.js +93 -644
  12. package/dist/handler.jsonld +2 -30
  13. package/dist/identities.d.ts +71 -0
  14. package/dist/identities.js +236 -0
  15. package/dist/mounts.d.ts +43 -0
  16. package/dist/mounts.js +123 -0
  17. package/dist/opt-in.d.ts +46 -0
  18. package/dist/opt-in.js +176 -0
  19. package/dist/private-read.d.ts +4 -0
  20. package/dist/private-read.js +34 -0
  21. package/package.json +12 -20
  22. package/lib/client/c2s.mjs +0 -636
  23. package/lib/client/localapi.mjs +0 -87
  24. package/lib/client/masto/accounts.mjs +0 -310
  25. package/lib/client/masto/body.mjs +0 -156
  26. package/lib/client/masto/index.mjs +0 -206
  27. package/lib/client/masto/instance.mjs +0 -112
  28. package/lib/client/masto/media.mjs +0 -79
  29. package/lib/client/masto/oauth.mjs +0 -656
  30. package/lib/client/masto/render.mjs +0 -518
  31. package/lib/client/masto/statuses.mjs +0 -372
  32. package/lib/client/masto/timelines.mjs +0 -438
  33. package/lib/client/oidc-auth.mjs +0 -62
  34. package/lib/client/streaming.mjs +0 -154
  35. package/lib/client/webpush.mjs +0 -98
  36. package/lib/connections/acctfeed.mjs +0 -257
  37. package/lib/connections/atproto.mjs +0 -309
  38. package/lib/connections/bskyfeed.mjs +0 -243
  39. package/lib/connections/bskygroup.mjs +0 -162
  40. package/lib/connections/fediacct.mjs +0 -253
  41. package/lib/connections/import.mjs +0 -357
  42. package/lib/connections/tagfeed.mjs +0 -212
  43. package/lib/connections/vault.mjs +0 -114
  44. package/lib/core/as2.mjs +0 -206
  45. package/lib/core/contexts/activitystreams.json +0 -379
  46. package/lib/core/contexts/anno.json +0 -126
  47. package/lib/core/contexts/did-v1.json +0 -57
  48. package/lib/core/contexts/fep-5711.json +0 -36
  49. package/lib/core/contexts/gotosocial.json +0 -86
  50. package/lib/core/contexts/identity-v1.json +0 -152
  51. package/lib/core/contexts/index.mjs +0 -63
  52. package/lib/core/contexts/join-lemmy.json +0 -33
  53. package/lib/core/contexts/joinmastodon.json +0 -28
  54. package/lib/core/contexts/litepub-0.1.json +0 -60
  55. package/lib/core/contexts/map.json +0 -19
  56. package/lib/core/contexts/miscellany.json +0 -19
  57. package/lib/core/contexts/quotes.json +0 -18
  58. package/lib/core/contexts/schemaorg.json +0 -8845
  59. package/lib/core/contexts/security-data-integrity-v1.json +0 -78
  60. package/lib/core/contexts/security-data-integrity-v2.json +0 -81
  61. package/lib/core/contexts/security-multikey-v1.json +0 -35
  62. package/lib/core/contexts/security-v1.json +0 -74
  63. package/lib/core/contexts/webfinger.json +0 -10
  64. package/lib/core/deliver.mjs +0 -387
  65. package/lib/core/graphview.mjs +0 -327
  66. package/lib/core/intake/activities.mjs +0 -649
  67. package/lib/core/intake/activity.mjs +0 -318
  68. package/lib/core/intake/channel.mjs +0 -144
  69. package/lib/core/intake/group.mjs +0 -258
  70. package/lib/core/intake/index.mjs +0 -732
  71. package/lib/core/intake/notes.mjs +0 -367
  72. package/lib/core/intake/verify.mjs +0 -142
  73. package/lib/core/keys.mjs +0 -153
  74. package/lib/core/lease.mjs +0 -206
  75. package/lib/core/place.mjs +0 -82
  76. package/lib/core/polls.mjs +0 -105
  77. package/lib/core/profile-page.mjs +0 -104
  78. package/lib/core/proof.mjs +0 -79
  79. package/lib/core/publisher/collections.mjs +0 -272
  80. package/lib/core/publisher/index.mjs +0 -522
  81. package/lib/core/publisher/notes.mjs +0 -519
  82. package/lib/core/publisher/own.mjs +0 -143
  83. package/lib/core/publisher/questions.mjs +0 -241
  84. package/lib/core/publisher/restore.mjs +0 -224
  85. package/lib/core/shapes/activitystreams.ttl +0 -157
  86. package/lib/core/shapes/index.mjs +0 -132
  87. package/lib/core/shapes/shapes-text.mjs +0 -13
  88. package/lib/core/social.mjs +0 -561
  89. package/lib/core/storage.mjs +0 -176
  90. package/lib/core/store.mjs +0 -578
  91. package/lib/core/wire-quotes.mjs +0 -71
  92. package/lib/core/wire.mjs +0 -925
  93. package/lib/device/account.mjs +0 -87
  94. package/lib/device/admin/index.mjs +0 -13
  95. package/lib/device/admin/origins.mjs +0 -35
  96. package/lib/device/admin/routes/connections.mjs +0 -144
  97. package/lib/device/admin/routes/gateway.mjs +0 -199
  98. package/lib/device/admin/routes/lifecycle.mjs +0 -200
  99. package/lib/device/admin/routes/owner.mjs +0 -322
  100. package/lib/device/admin/routes/setup.mjs +0 -428
  101. package/lib/device/admin/routes/social.mjs +0 -188
  102. package/lib/device/admin/server.mjs +0 -95
  103. package/lib/device/admin/static.mjs +0 -247
  104. package/lib/device/admin/surface.mjs +0 -315
  105. package/lib/device/certs.mjs +0 -281
  106. package/lib/device/cli/commands/account.mjs +0 -586
  107. package/lib/device/cli/commands/run.mjs +0 -278
  108. package/lib/device/cli/commands/service.mjs +0 -221
  109. package/lib/device/cli/commands/setup.mjs +0 -489
  110. package/lib/device/cli/commands/state.mjs +0 -561
  111. package/lib/device/cli/context.mjs +0 -288
  112. package/lib/device/export-collections.mjs +0 -161
  113. package/lib/device/gateway-move.mjs +0 -58
  114. package/lib/device/home.mjs +0 -161
  115. package/lib/device/migrate.mjs +0 -115
  116. package/lib/device/ports.mjs +0 -27
  117. package/lib/device/remote.mjs +0 -54
  118. package/lib/device/setup.mjs +0 -496
  119. package/lib/device/update.mjs +0 -96
  120. package/lib/gateway/caches.mjs +0 -36
  121. package/lib/gateway/directory.mjs +0 -90
  122. package/lib/gateway/front-core.mjs +0 -966
  123. package/lib/gateway/gateway-core.mjs +0 -244
  124. package/lib/gateway/headers.mjs +0 -49
  125. package/lib/gateway/httpsig.mjs +0 -159
  126. package/lib/gateway/notices.mjs +0 -84
  127. package/lib/gateway/quiet.mjs +0 -189
  128. package/lib/gateway/relay-extras.mjs +0 -89
  129. package/lib/gateway/token-claims.mjs +0 -16
  130. package/lib/pod/README.md +0 -61
  131. package/lib/pod/actor.mjs +0 -96
  132. package/lib/pod/collection.mjs +0 -77
  133. package/lib/pod/containers.mjs +0 -140
  134. package/lib/pod/discovery.mjs +0 -46
  135. package/lib/pod/featured.mjs +0 -18
  136. package/lib/pod/followers.mjs +0 -24
  137. package/lib/pod/following.mjs +0 -10
  138. package/lib/pod/http.mjs +0 -74
  139. package/lib/pod/inbox.mjs +0 -166
  140. package/lib/pod/links.mjs +0 -35
  141. package/lib/pod/location.mjs +0 -52
  142. package/lib/pod/media.mjs +0 -27
  143. package/lib/pod/notes.mjs +0 -78
  144. package/lib/pod/notifications.mjs +0 -89
  145. package/lib/pod/outbox.mjs +0 -18
  146. package/lib/pod/package.json +0 -19
  147. package/lib/pod/policy.mjs +0 -58
  148. package/lib/pod/private.mjs +0 -19
  149. package/lib/pod/root.mjs +0 -104
  150. package/lib/pod/state.mjs +0 -40
  151. package/lib/pod/transport.mjs +0 -674
  152. package/lib/pod/type-index.mjs +0 -101
  153. package/lib/pod/urls.mjs +0 -91
  154. package/lib/server/embed.mjs +0 -424
  155. package/lib/session/README.md +0 -137
  156. package/lib/session/demo.html +0 -94
  157. package/lib/session/fedi-account.mjs +0 -417
  158. package/lib/session/fedi-login.mjs +0 -123
  159. package/lib/session/oidc-session.mjs +0 -233
  160. package/lib/session/package.json +0 -49
  161. package/lib/shared/guard.mjs +0 -213
  162. package/lib/shared/links.mjs +0 -9
  163. package/lib/shared/safefetch.mjs +0 -235
  164. package/lib/shared/ua.mjs +0 -29
  165. package/phanpy/dist/404.html +0 -40
  166. package/phanpy/dist/_headers +0 -2
  167. package/phanpy/dist/apple-touch-icon.png +0 -0
  168. package/phanpy/dist/assets/ICONS-DIPJeU0C.js +0 -2
  169. package/phanpy/dist/assets/ICONS-DIPJeU0C.js.map +0 -1
  170. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js +0 -183
  171. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js.map +0 -1
  172. package/phanpy/dist/assets/Temml-CCjoacWt.woff2 +0 -0
  173. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js +0 -2
  174. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js.map +0 -1
  175. package/phanpy/dist/assets/boosts-carousel-BiOaNdMT.jpg +0 -0
  176. package/phanpy/dist/assets/catch-up-O5q5C75Z.png +0 -0
  177. package/phanpy/dist/assets/chunk-aKtaBQYM.js +0 -1
  178. package/phanpy/dist/assets/compose-CFEx7wb4.js +0 -2
  179. package/phanpy/dist/assets/compose-CFEx7wb4.js.map +0 -1
  180. package/phanpy/dist/assets/compose-ZJN5xSb4.js +0 -35
  181. package/phanpy/dist/assets/compose-ZJN5xSb4.js.map +0 -1
  182. package/phanpy/dist/assets/debug.module-YFQgwnIr.js +0 -52
  183. package/phanpy/dist/assets/debug.module-YFQgwnIr.js.map +0 -1
  184. package/phanpy/dist/assets/dom-p1YcJ5Rw.js +0 -2
  185. package/phanpy/dist/assets/dom-p1YcJ5Rw.js.map +0 -1
  186. package/phanpy/dist/assets/home-mobile-dark@2x-Dc-J8-SM.png +0 -0
  187. package/phanpy/dist/assets/home-mobile-light@2x-Bd3fod8m.png +0 -0
  188. package/phanpy/dist/assets/home-tablet-dark@2x-BgcNI8le.png +0 -0
  189. package/phanpy/dist/assets/home-tablet-light@2x-BW2RV9T6.png +0 -0
  190. package/phanpy/dist/assets/icons/add-circle-line-WD0mwORD.js +0 -1
  191. package/phanpy/dist/assets/icons/alert-line-CpFUMf9s.js +0 -1
  192. package/phanpy/dist/assets/icons/android-2-line-Bzxnrd3S.js +0 -1
  193. package/phanpy/dist/assets/icons/announcement-line-5nwaJFJm.js +0 -1
  194. package/phanpy/dist/assets/icons/arrow-down-circle-line-a7Id9-Iv.js +0 -1
  195. package/phanpy/dist/assets/icons/arrow-down-line-B8uzXzq6.js +0 -1
  196. package/phanpy/dist/assets/icons/arrow-left-line-CGrGT9C-.js +0 -1
  197. package/phanpy/dist/assets/icons/arrow-right-line-CE-HERfX.js +0 -1
  198. package/phanpy/dist/assets/icons/arrow-to-up-line-CvdQjmcy.js +0 -1
  199. package/phanpy/dist/assets/icons/arrow-up-circle-line-DEparSNF.js +0 -1
  200. package/phanpy/dist/assets/icons/arrow-up-line-C7yBeugc.js +0 -1
  201. package/phanpy/dist/assets/icons/arrows-right-line-BtbXmJGP.js +0 -1
  202. package/phanpy/dist/assets/icons/at-line-CF66Bznk.js +0 -1
  203. package/phanpy/dist/assets/icons/attachment-line-BY8It-l9.js +0 -1
  204. package/phanpy/dist/assets/icons/blockquote-line-BS6pU_hm.js +0 -1
  205. package/phanpy/dist/assets/icons/board-line-C0UWXyA6.js +0 -1
  206. package/phanpy/dist/assets/icons/bookmark-line-1CtX5JLF.js +0 -1
  207. package/phanpy/dist/assets/icons/building-5-line-Dd59MzbO.js +0 -1
  208. package/phanpy/dist/assets/icons/bus-2-line-6_dvA0GG.js +0 -1
  209. package/phanpy/dist/assets/icons/calendar-day-line-Crpl_fmu.js +0 -1
  210. package/phanpy/dist/assets/icons/calendar-month-line-vommts2C.js +0 -1
  211. package/phanpy/dist/assets/icons/calendar-time-add-line-BU_DTlQk.js +0 -1
  212. package/phanpy/dist/assets/icons/camera-line-Cv69MEei.js +0 -1
  213. package/phanpy/dist/assets/icons/celebrate-line-B8DvIoi0.js +0 -1
  214. package/phanpy/dist/assets/icons/chart-bar-line-FK-QOmtF.js +0 -1
  215. package/phanpy/dist/assets/icons/chart-line-line-BGcJAFWw.js +0 -1
  216. package/phanpy/dist/assets/icons/chat-3-line-YFK2-hwz.js +0 -1
  217. package/phanpy/dist/assets/icons/check-circle-line-DsAxFr5-.js +0 -1
  218. package/phanpy/dist/assets/icons/clipboard-line-BBp364gJ.js +0 -1
  219. package/phanpy/dist/assets/icons/close-circle-line-CICdiuGz.js +0 -1
  220. package/phanpy/dist/assets/icons/close-line-DYrFWcjv.js +0 -1
  221. package/phanpy/dist/assets/icons/cloud-line-tiQAbah8.js +0 -1
  222. package/phanpy/dist/assets/icons/code-line-fAl8iiV3.js +0 -1
  223. package/phanpy/dist/assets/icons/comment-2-line-CR3g7WeB.js +0 -1
  224. package/phanpy/dist/assets/icons/copy-2-line-CLW69yF5.js +0 -1
  225. package/phanpy/dist/assets/icons/delete-2-line-B8xmbr4n.js +0 -1
  226. package/phanpy/dist/assets/icons/document-3-line-DBGNhAg2.js +0 -1
  227. package/phanpy/dist/assets/icons/document-line-C7mb9sb7.js +0 -1
  228. package/phanpy/dist/assets/icons/down-line-BGqSSThd.js +0 -1
  229. package/phanpy/dist/assets/icons/edit-4-line-DcgGaEhx.js +0 -1
  230. package/phanpy/dist/assets/icons/emoji-2-line-D8YgnM-y.js +0 -1
  231. package/phanpy/dist/assets/icons/exit-line-Dc07BS-x.js +0 -1
  232. package/phanpy/dist/assets/icons/external-link-line-BvpSkmjO.js +0 -1
  233. package/phanpy/dist/assets/icons/eye-2-line-CiWXx-f_.js +0 -1
  234. package/phanpy/dist/assets/icons/eye-close-line-BgTaSJ4P.js +0 -1
  235. package/phanpy/dist/assets/icons/filter-2-line-B_mR2usy.js +0 -1
  236. package/phanpy/dist/assets/icons/filter-line-C_nm-3cU.js +0 -1
  237. package/phanpy/dist/assets/icons/flag-1-line-C2HB05I0.js +0 -1
  238. package/phanpy/dist/assets/icons/forbid-circle-line-D3LTT9yd.js +0 -1
  239. package/phanpy/dist/assets/icons/formula-line-DLrt2d6j.js +0 -1
  240. package/phanpy/dist/assets/icons/grid-line-CgUmEikf.js +0 -1
  241. package/phanpy/dist/assets/icons/group-line-C5fnX0wU.js +0 -1
  242. package/phanpy/dist/assets/icons/hand-finger-2-line-BGgxbuL9.js +0 -1
  243. package/phanpy/dist/assets/icons/hashtag-line-CyTEEXBb.js +0 -1
  244. package/phanpy/dist/assets/icons/heart-crack-line-BZddbO2C.js +0 -1
  245. package/phanpy/dist/assets/icons/heart-line-CJ7K47J4.js +0 -1
  246. package/phanpy/dist/assets/icons/history-2-line-kWWvFzqv.js +0 -1
  247. package/phanpy/dist/assets/icons/history-line-bGQiwbTH.js +0 -1
  248. package/phanpy/dist/assets/icons/home-3-line-fRU1zeLG.js +0 -1
  249. package/phanpy/dist/assets/icons/information-line-iNk6-sOY.js +0 -1
  250. package/phanpy/dist/assets/icons/keyboard-line-DsCyuQNz.js +0 -1
  251. package/phanpy/dist/assets/icons/layout-4-line-CZkOX52Z.js +0 -1
  252. package/phanpy/dist/assets/icons/layout-5-line-B_znt5wO.js +0 -1
  253. package/phanpy/dist/assets/icons/left-line-eUw0tya4.js +0 -1
  254. package/phanpy/dist/assets/icons/lightning-line-DaKoDdix.js +0 -1
  255. package/phanpy/dist/assets/icons/link-2-line-DCqLmMA7.js +0 -1
  256. package/phanpy/dist/assets/icons/list-check-line-BAxosBh9.js +0 -1
  257. package/phanpy/dist/assets/icons/lock-line-CPoaXeUW.js +0 -1
  258. package/phanpy/dist/assets/icons/mail-line-B0P8aa1L.js +0 -1
  259. package/phanpy/dist/assets/icons/moon-line-CEqNAToP.js +0 -1
  260. package/phanpy/dist/assets/icons/more-1-fill-Dw2e5xab.js +0 -1
  261. package/phanpy/dist/assets/icons/more-3-line-BIiVjYTz.js +0 -1
  262. package/phanpy/dist/assets/icons/notification-line-BZZq2Gtu.js +0 -1
  263. package/phanpy/dist/assets/icons/pencil-line-CKh8-A1v.js +0 -1
  264. package/phanpy/dist/assets/icons/photo-album-line-Bnfg2u40.js +0 -1
  265. package/phanpy/dist/assets/icons/pin-line-DpTolyhs.js +0 -1
  266. package/phanpy/dist/assets/icons/play-fill-B0-G_8lX.js +0 -1
  267. package/phanpy/dist/assets/icons/qrcode-2-line-B6SPCaHn.js +0 -1
  268. package/phanpy/dist/assets/icons/quill-pen-line-B6LUrnCP.js +0 -1
  269. package/phanpy/dist/assets/icons/quote-left-fill-hQZ1cj_6.js +0 -1
  270. package/phanpy/dist/assets/icons/radar-line-CKyroTth.js +0 -1
  271. package/phanpy/dist/assets/icons/react-line-CoIKhhtK.js +0 -1
  272. package/phanpy/dist/assets/icons/refresh-2-line-D0mTF97S.js +0 -1
  273. package/phanpy/dist/assets/icons/right-line-B3KWJaqc.js +0 -1
  274. package/phanpy/dist/assets/icons/rocket-line-4KZl537D.js +0 -1
  275. package/phanpy/dist/assets/icons/round-fill-C69NTrZ0.js +0 -1
  276. package/phanpy/dist/assets/icons/round-line-B9k_1uo-.js +0 -1
  277. package/phanpy/dist/assets/icons/route-line-B28ReHcE.js +0 -1
  278. package/phanpy/dist/assets/icons/rows-4-line-CrBniagM.js +0 -1
  279. package/phanpy/dist/assets/icons/scan-line-DSf74YdP.js +0 -1
  280. package/phanpy/dist/assets/icons/search-2-line-B6geIU1z.js +0 -1
  281. package/phanpy/dist/assets/icons/settings-3-line-azJwK47w.js +0 -1
  282. package/phanpy/dist/assets/icons/settings-6-line-C_5zc5YR.js +0 -1
  283. package/phanpy/dist/assets/icons/share-2-line-D5MxWjrm.js +0 -1
  284. package/phanpy/dist/assets/icons/share-forward-line-Cp61fZzZ.js +0 -1
  285. package/phanpy/dist/assets/icons/sparkles-2-line-DYYyXTaW.js +0 -1
  286. package/phanpy/dist/assets/icons/sparkles-line-C2hY1s6I.js +0 -1
  287. package/phanpy/dist/assets/icons/time-line-BF3eet1v.js +0 -1
  288. package/phanpy/dist/assets/icons/transfer-4-line-oisfvTBw.js +0 -1
  289. package/phanpy/dist/assets/icons/translate-line-BFWol2Ce.js +0 -1
  290. package/phanpy/dist/assets/icons/unlock-line-X_x5vwv3.js +0 -1
  291. package/phanpy/dist/assets/icons/upload-3-line-DgzwUJeW.js +0 -1
  292. package/phanpy/dist/assets/icons/user-4-line-BVSynZCp.js +0 -1
  293. package/phanpy/dist/assets/icons/user-add-2-line-BlGS5Q8q.js +0 -1
  294. package/phanpy/dist/assets/icons/user-add-line-BbXdHG4z.js +0 -1
  295. package/phanpy/dist/assets/icons/user-edit-line-BFAHOV0X.js +0 -1
  296. package/phanpy/dist/assets/icons/user-follow-line-BXux0wSd.js +0 -1
  297. package/phanpy/dist/assets/icons/user-star-line-DdYlpHLU.js +0 -1
  298. package/phanpy/dist/assets/icons/user-warning-line-Cj43j0_E.js +0 -1
  299. package/phanpy/dist/assets/icons/user-x-line-DIDgNlPH.js +0 -1
  300. package/phanpy/dist/assets/icons/volume-line-Bs390KQt.js +0 -1
  301. package/phanpy/dist/assets/icons/volume-mute-line-DzlzIqFZ.js +0 -1
  302. package/phanpy/dist/assets/icons/walk-line-yNXfB-md.js +0 -1
  303. package/phanpy/dist/assets/icons/world-2-line-CenkGIwj.js +0 -1
  304. package/phanpy/dist/assets/icons/zoom-in-line-CaENUphf.js +0 -1
  305. package/phanpy/dist/assets/icons/zoom-out-line-BDNk0EWo.js +0 -1
  306. package/phanpy/dist/assets/instances-BNPptnn-.json +0 -333
  307. package/phanpy/dist/assets/locales/ar-SA-CfheRbCu.js +0 -1
  308. package/phanpy/dist/assets/locales/ca-ES-DHRW86Tz.js +0 -1
  309. package/phanpy/dist/assets/locales/cs-CZ-CKoqEuA1.js +0 -1
  310. package/phanpy/dist/assets/locales/de-DE-ByRPMRFy.js +0 -1
  311. package/phanpy/dist/assets/locales/eo-UY-CPC7wLCS.js +0 -1
  312. package/phanpy/dist/assets/locales/es-ES-dJa0Fd9t.js +0 -1
  313. package/phanpy/dist/assets/locales/eu-ES-C3djlPR2.js +0 -1
  314. package/phanpy/dist/assets/locales/fa-IR-DTT490Ck.js +0 -1
  315. package/phanpy/dist/assets/locales/fi-FI-B23MCPuz.js +0 -1
  316. package/phanpy/dist/assets/locales/fr-FR-BcaQsO5C.js +0 -1
  317. package/phanpy/dist/assets/locales/gl-ES-BR-CVKBN.js +0 -1
  318. package/phanpy/dist/assets/locales/he-IL-CfheRbCu.js +0 -1
  319. package/phanpy/dist/assets/locales/hu-HU-CfheRbCu.js +0 -1
  320. package/phanpy/dist/assets/locales/it-IT-C1136UFV.js +0 -1
  321. package/phanpy/dist/assets/locales/ja-JP-CRZmRAhD.js +0 -1
  322. package/phanpy/dist/assets/locales/kab-Cz8xH_TT.js +0 -1
  323. package/phanpy/dist/assets/locales/ko-KR-CG9UiY4o.js +0 -1
  324. package/phanpy/dist/assets/locales/lt-LT-CJcI6sHZ.js +0 -1
  325. package/phanpy/dist/assets/locales/nb-NO-CfheRbCu.js +0 -1
  326. package/phanpy/dist/assets/locales/nl-NL-DxN4Yc1t.js +0 -1
  327. package/phanpy/dist/assets/locales/oc-FR-CfheRbCu.js +0 -1
  328. package/phanpy/dist/assets/locales/pl-PL-DkwGXf6P.js +0 -1
  329. package/phanpy/dist/assets/locales/pseudo-LOCALE-CQ4XxkQ0.js +0 -1
  330. package/phanpy/dist/assets/locales/pt-BR-nGL0HdFS.js +0 -1
  331. package/phanpy/dist/assets/locales/pt-PT-Cp17aj2z.js +0 -1
  332. package/phanpy/dist/assets/locales/ru-RU-0Y8cIoaK.js +0 -1
  333. package/phanpy/dist/assets/locales/th-TH-CfheRbCu.js +0 -1
  334. package/phanpy/dist/assets/locales/tok-CfheRbCu.js +0 -1
  335. package/phanpy/dist/assets/locales/tr-TR-CfheRbCu.js +0 -1
  336. package/phanpy/dist/assets/locales/uk-UA-C5E3dFBf.js +0 -1
  337. package/phanpy/dist/assets/locales/zh-CN-BHJi7_et.js +0 -1
  338. package/phanpy/dist/assets/locales/zh-TW-CfheRbCu.js +0 -1
  339. package/phanpy/dist/assets/main-BdqNbG-a.js +0 -26
  340. package/phanpy/dist/assets/main-BdqNbG-a.js.map +0 -1
  341. package/phanpy/dist/assets/mock-home-DGhR__He.js +0 -2
  342. package/phanpy/dist/assets/mock-home-DGhR__He.js.map +0 -1
  343. package/phanpy/dist/assets/multi-column-ROck0NVt.jpg +0 -0
  344. package/phanpy/dist/assets/multi-hashtag-timeline-DH5INVHi.jpg +0 -0
  345. package/phanpy/dist/assets/nested-comments-thread-hv59kZLc.jpg +0 -0
  346. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js +0 -2
  347. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js.map +0 -1
  348. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js +0 -20
  349. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js.map +0 -1
  350. package/phanpy/dist/assets/style-B1iLPTPR.css +0 -2
  351. package/phanpy/dist/assets/temml-DuyIQMei.js +0 -97
  352. package/phanpy/dist/assets/temml-DuyIQMei.js.map +0 -1
  353. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js +0 -2
  354. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js.map +0 -1
  355. package/phanpy/dist/assets/year-in-posts-B2lywqdx.png +0 -0
  356. package/phanpy/dist/assets/year-in-posts-DJv_star.js +0 -3
  357. package/phanpy/dist/assets/year-in-posts-DJv_star.js.map +0 -1
  358. package/phanpy/dist/compose/index.html +0 -20
  359. package/phanpy/dist/favicon.ico +0 -0
  360. package/phanpy/dist/index.html +0 -73
  361. package/phanpy/dist/logo-192.png +0 -0
  362. package/phanpy/dist/logo-512.png +0 -0
  363. package/phanpy/dist/logo-badge-72.png +0 -0
  364. package/phanpy/dist/logo-maskable-512.png +0 -0
  365. package/phanpy/dist/logo-monochrome-512.png +0 -0
  366. package/phanpy/dist/logo-monochrome-maskable-512.png +0 -0
  367. package/phanpy/dist/manifest.webmanifest +0 -1
  368. package/phanpy/dist/og-image-2.jpg +0 -0
  369. package/phanpy/dist/og-image.png +0 -0
  370. package/phanpy/dist/robots.txt +0 -2
  371. package/phanpy/dist/sw.js +0 -2
  372. package/phanpy/dist/sw.js.map +0 -1
  373. package/phanpy/dist/version.json +0 -1
  374. package/run-agent.mjs +0 -899
  375. package/vendor/gate.cjs +0 -138
  376. package/vendor/idp-grant.cjs +0 -394
  377. package/vendor/jfetch.cjs +0 -16
  378. package/web/admin/actors.js +0 -147
  379. package/web/admin/bar.css +0 -126
  380. package/web/admin/bar.js +0 -99
  381. package/web/admin/client/client.js +0 -66
  382. package/web/admin/client/index.html +0 -69
  383. package/web/admin/client-pick.js +0 -79
  384. package/web/admin/common.js +0 -23
  385. package/web/admin/connections.js +0 -112
  386. package/web/admin/gateway.js +0 -133
  387. package/web/admin/group.js +0 -258
  388. package/web/admin/index.html +0 -612
  389. package/web/admin/notices-bar.js +0 -90
  390. package/web/admin/oauth-signin.mjs +0 -37
  391. package/web/admin/record.js +0 -393
  392. package/web/admin/setup/index.html +0 -257
  393. package/web/admin/setup/setup.js +0 -339
  394. package/web/admin/tokens.css +0 -68
  395. package/web/admin/upkeep.js +0 -177
  396. package/web/admin/window.css +0 -55
  397. package/web/admin/window.js +0 -136
  398. package/web/app/README.md +0 -81
  399. package/web/app/admin-facade.mjs +0 -588
  400. package/web/app/agent.mjs +0 -672
  401. package/web/app/atproto-browser.mjs +0 -86
  402. package/web/app/authorize_interaction.html +0 -56
  403. package/web/app/authorize_interaction.js +0 -69
  404. package/web/app/boot.mjs +0 -616
  405. package/web/app/deliver-relay.mjs +0 -129
  406. package/web/app/dist/boot.js +0 -34562
  407. package/web/app/dist/boot.js.map +0 -7
  408. package/web/app/dist/sw.js +0 -73456
  409. package/web/app/dist/sw.js.map +0 -7
  410. package/web/app/fediacct-browser.mjs +0 -146
  411. package/web/app/gateway-move.mjs +0 -60
  412. package/web/app/idb-kv.mjs +0 -35
  413. package/web/app/index.html +0 -258
  414. package/web/app/keys-browser.mjs +0 -71
  415. package/web/app/keystore.mjs +0 -82
  416. package/web/app/oidc-session.mjs +0 -6
  417. package/web/app/pod-auth.mjs +0 -248
  418. package/web/app/pod-remote.mjs +0 -84
  419. package/web/app/shims/_globals.mjs +0 -2
  420. package/web/app/shims/fedify-sig.mjs +0 -77
  421. package/web/app/shims/node-crypto.mjs +0 -113
  422. package/web/app/shims/node-fs.mjs +0 -17
  423. package/web/app/shims/node-path.mjs +0 -19
  424. package/web/app/shims/node-url.mjs +0 -7
  425. package/web/app/shims/prelude.js +0 -58
  426. package/web/app/shims/safefetch.mjs +0 -58
  427. package/web/app/shims/shapes-text.mjs +0 -8
  428. package/web/app/shims/web-push.mjs +0 -14
  429. package/web/app/signup.mjs +0 -357
  430. package/web/app/sw-src.mjs +0 -220
  431. package/web/app/update.js +0 -70
  432. package/web/front/admin.html +0 -55
  433. package/web/front/admin.js +0 -89
  434. package/web/front/install.sh +0 -69
  435. package/web/front/new-account.html +0 -35
  436. package/web/front/new-account.js +0 -13
  437. package/web/front/notices.html +0 -69
  438. package/web/front/notices.js +0 -107
  439. package/web/front/run.html +0 -64
  440. package/web/front/run.js +0 -221
  441. package/web/front/solid-oidc-client.js +0 -6
  442. package/web/icons/forum.svg +0 -11
  443. package/web/icons/gateway.svg +0 -14
  444. package/web/icons/local.svg +0 -11
@@ -1,46 +0,0 @@
1
- // discovery.mjs — the documents that make a handle resolve.
2
- //
3
- // These live at the HOST root, not in the actor's container, because that is
4
- // the only place the fediverse looks: @name@host is resolved at
5
- // https://host/.well-known/webfinger and nowhere else. A pod that does not own
6
- // the root of its host can still publish them, but nothing will ever ask.
7
- //
8
- // Every one is public by definition — a discovery document nobody may read
9
- // discovers nothing — so the Read rule is not a parameter here. It travels
10
- // with the write because publishing one of these unreadable is a failure mode
11
- // with an entire verification pass devoted to catching it.
12
-
13
- const PUBLIC_READ = ['Read'];
14
-
15
- // ---- the owner's agent ----
16
-
17
- /** The JRD that answers `acct:name@host`. */
18
- export async function writeWebfinger(pod, urls, jrd) {
19
- await pod.putJson(urls.webfinger, jrd, 'application/jrd+json');
20
- await pod.setAcl(urls.webfinger, PUBLIC_READ);
21
- }
22
-
23
- /** RFC 6415 host-meta: the LRDD template some implementations prefer. */
24
- export async function writeHostMeta(pod, urls, xml) {
25
- const url = urls.base + '.well-known/host-meta';
26
- await pod.put(url, xml, 'application/xrd+xml');
27
- await pod.setAcl(url, PUBLIC_READ);
28
- }
29
-
30
- /**
31
- * NodeInfo, which is two documents: a pointer at the protocol-required root,
32
- * and the document itself in the actor's own tree.
33
- *
34
- * Four requests, one fact — "this pod answers nodeinfo". Split into separate
35
- * operations, a caller could write the pointer and not what it points at,
36
- * which is worse than neither.
37
- */
38
- export async function writeNodeinfo(pod, urls, { pointer, doc }) {
39
- const pointerUrl = urls.base + '.well-known/nodeinfo';
40
- const docUrl = urls.home + 'ap/nodeinfo-2.0';
41
- await pod.putJson(pointerUrl, pointer, 'application/json');
42
- await pod.setAcl(pointerUrl, PUBLIC_READ);
43
- await pod.putJson(docUrl, doc, 'application/json');
44
- await pod.setAcl(docUrl, PUBLIC_READ);
45
- return docUrl;
46
- }
@@ -1,18 +0,0 @@
1
- // featured.mjs — ap/featured and ap/moderators: the two small public rosters.
2
- //
3
- // Together because both are short, flat, public lists that say "these are the
4
- // ones that matter", and neither is big enough to page. `featured` is the
5
- // pinned posts; `moderators` is FEP-1b12's roster, which a recipient validates
6
- // a group's announced moderation against — published only when a group
7
- // actually has moderators, since an empty roster and no roster mean different
8
- // things.
9
-
10
- import * as collection from './collection.mjs';
11
-
12
- // ---- the owner's agent ----
13
-
14
- export const write = (pod, urls, doc) =>
15
- collection.writeFlat(pod, urls.featured, doc, { publicRead: true });
16
-
17
- export const writeModerators = (pod, urls, doc) =>
18
- collection.writeFlat(pod, urls.moderators, doc, { publicRead: true });
@@ -1,24 +0,0 @@
1
- // followers.mjs — ap/followers: who follows this actor, paged.
2
- //
3
- // Paged like the outbox, and for the same reason: a popular account's follower
4
- // list is large, and a remote server should read a small head rather than pull
5
- // all of it. Read back to reconcile — anyone the pod says follows us that we
6
- // have no record of is a sign the local half is BEHIND the pod, and publishing
7
- // blindly over them would drop them from the wire.
8
-
9
- import * as collection from './collection.mjs';
10
-
11
- // ---- the owner's agent ----
12
-
13
- export const writePage = (pod, pageUrl, doc, opts) => collection.writePage(pod, pageUrl, doc, opts);
14
- export const writeHead = (pod, urls, doc, opts) => collection.writeHead(pod, urls.followers, doc, opts);
15
- export const dropPage = (pod, pageUrl) => collection.dropPage(pod, pageUrl);
16
-
17
- /**
18
- * Every follower the pod currently publishes, or null if it publishes none.
19
- *
20
- * `alsoItems`, unlike the outbox: the flat followers collection this project
21
- * used to write put them under `items` rather than `orderedItems`.
22
- */
23
- export const readPublished = (pod, urls) =>
24
- collection.readPaged(pod, urls.followers, { max: 100_000, alsoItems: true });
@@ -1,10 +0,0 @@
1
- // following.mjs — ap/following: who this actor follows.
2
- //
3
- // Flat, not paged: it is bounded by what one person chose to do, where the
4
- // followers list is bounded by what everyone else chose.
5
-
6
- import * as collection from './collection.mjs';
7
-
8
- // ---- the owner's agent ----
9
-
10
- export const write = (pod, urls, doc, opts) => collection.writeFlat(pod, urls.following, doc, opts);
package/lib/pod/http.mjs DELETED
@@ -1,74 +0,0 @@
1
- // http.mjs — the two HTTP manners this library needs, and nothing else.
2
- //
3
- // FediPod has lib/safefetch.mjs, which does far more: DNS pinning, private
4
- // address refusal, redirect re-checking. None of that can come here, because
5
- // it imports node:dns and node:net and this library must run unmodified inside
6
- // a service worker. What IS needed on both sides is a byte budget and a reading
7
- // of Retry-After, so they live here in a form with no runtime of their own.
8
- //
9
- // Deliberately NOT a fetch wrapper. The library never opens a connection by
10
- // itself; every request goes through a transport or a fetcher the caller
11
- // supplies, which is what lets the same code serve an authenticated agent, a
12
- // keyless gateway, and a test with no network at all.
13
-
14
- // Five megabytes is what the wider project uses as a body budget, and a
15
- // document this library reads is a pod resource, not a stranger's timeline.
16
- const MAX_BYTES = 5 * 1024 * 1024;
17
-
18
- // Thirty minutes is a ceiling, not a policy: a hostile or confused header must
19
- // not be able to park a caller for a day. Callers that want a tighter ceiling
20
- // pass their own — the browser transport does.
21
- const COOLDOWN_MAX_MS = 30 * 60_000;
22
-
23
- /**
24
- * How long a server asked to be left alone, or **null** when it did not say.
25
- *
26
- * The null matters and must not become a default. The caller decides what
27
- * absence means: a pod falls back to a flat cooldown, while a delivery queue
28
- * keeps its exponential ladder — and returning a default here once collapsed
29
- * that ladder to a flat 60s for every 503 without the header, which is most
30
- * of them.
31
- */
32
- export function retryAfterMs(res, max = COOLDOWN_MAX_MS) {
33
- const raw = res?.headers?.get?.('retry-after');
34
- if (!raw) return null;
35
- const secs = Number(raw);
36
- // A floor of one second: a server answering `Retry-After: 0` is still asking
37
- // for a pause, and honouring it as "none" is how a throttle becomes a spin.
38
- if (Number.isFinite(secs)) return Math.min(Math.max(secs, 1) * 1000, max);
39
- const when = Date.parse(raw); // the HTTP-date spelling
40
- if (Number.isFinite(when)) return Math.min(Math.max(when - Date.now(), 1000), max);
41
- return null;
42
- }
43
-
44
- /**
45
- * Read a response body with a hard byte budget.
46
- *
47
- * Checking `content-length` and then handing back `res.text()` is not a cap: a
48
- * chunked response carries no `content-length` at all, and an inbox listing is
49
- * public-Append, so its size is in other people's hands. Stream it and stop at
50
- * the budget.
51
- *
52
- * TextDecoder rather than Buffer — it exists in both runtimes — and
53
- * `stream: true` so a UTF-8 sequence split across two chunks still decodes.
54
- */
55
- export async function readCapped(res, max = MAX_BYTES) {
56
- const len = Number(res.headers?.get?.('content-length') || 0);
57
- if (len > max) throw new Error(`response too large (${len} bytes)`);
58
- if (!res.body) return res.text();
59
- const reader = res.body.getReader();
60
- const decoder = new TextDecoder('utf-8');
61
- let out = '';
62
- let total = 0;
63
- for (;;) {
64
- const { done, value } = await reader.read();
65
- if (done) break;
66
- total += value.length;
67
- if (total > max) {
68
- await reader.cancel();
69
- throw new Error(`response exceeded ${max} bytes`);
70
- }
71
- out += decoder.decode(value, { stream: true });
72
- }
73
- return out + decoder.decode();
74
- }
package/lib/pod/inbox.mjs DELETED
@@ -1,166 +0,0 @@
1
- // inbox.mjs — ap/inbox/: what arrives, and who may touch it.
2
- //
3
- // One file for the whole inbox, because the inbox is where two different
4
- // parties meet and neither half is comprehensible alone: a delivery gateway
5
- // may only ADD to it, holding at most an Append token; the owner's agent
6
- // lists, reads and removes, holding the pod's own credential. Splitting them
7
- // by who does them would put the two ends of one contract in two files.
8
-
9
- const DELIVERY_CT = 'application/activity+json';
10
- const RECEIPT_CT = 'application/json';
11
-
12
- // ---- a delivery gateway: appends verified mail, and can do nothing else ----
13
-
14
- /**
15
- * PUT one document into a pod inbox, with an Append token when the caller
16
- * holds one and anonymously when it does not.
17
- *
18
- * Sending no `authorization` header is not the same as sending an empty one:
19
- * `Bearer undefined` is a credential the pod will reject, where absence is a
20
- * public Append the pod may well allow. This is the one place that gets to
21
- * decide that, because it lived in two adapters and had to be right in both.
22
- *
23
- * @returns {Promise<boolean>} whether it landed
24
- */
25
- export async function appendWithToken(url, body, contentType, { appendToken = null, fetchImpl = fetch, report = null } = {}) {
26
- const headers = { 'content-type': contentType,
27
- ...(appendToken ? { authorization: `Bearer ${appendToken}` } : {}) };
28
- const r = await fetchImpl(url, { method: 'PUT', headers, body }).catch(() => null);
29
- // The pod's answer, for a caller that keeps a log: a refused write is
30
- // otherwise a bare "failed" with the status thrown away.
31
- report?.(r ? r.status : 0);
32
- return !!r && r.status < 400;
33
- }
34
-
35
- /**
36
- * The delivery itself, named by the hash of its own bytes.
37
- *
38
- * Content-addressed on purpose: the same activity delivered twice writes the
39
- * same document twice, so a retrying origin cannot produce duplicates in
40
- * someone's inbox.
41
- *
42
- * A failure here must reach the ORIGIN as a 5xx so it retries over its own
43
- * ladder — that is what preserves the pod's buffer property without the
44
- * gateway holding any state of its own.
45
- */
46
- export async function appendVerifiedDelivery(podPut, inboxUrl, hash, raw) {
47
- return podPut(inboxUrl + hash, raw, DELIVERY_CT);
48
- }
49
-
50
- /**
51
- * The verification receipt, written beside the delivery it vouches for.
52
- *
53
- * Best-effort by design: a delivery that landed but whose receipt did not is
54
- * read as unverified at the drain, which is a lesser thing than losing it.
55
- */
56
- export async function writeReceiptBeside(podPut, inboxUrl, hash, receipt) {
57
- await podPut(inboxUrl + hash + '.receipt.json', JSON.stringify(receipt), RECEIPT_CT)
58
- .catch(() => {});
59
- }
60
-
61
- // ---- the owner's agent: brings it into being and decides who may post ----
62
-
63
- /**
64
- * The canary that makes the container exist.
65
- *
66
- * Written without an access rule of its own, because the rule that matters is
67
- * the container's and is stated separately — see setPosture, which a caller
68
- * must reach for deliberately rather than inherit by accident.
69
- */
70
- export async function writeKeep(pod, urls) {
71
- await pod.putJson(urls.inbox + '.keep', { keep: true }, 'application/json');
72
- }
73
-
74
- /**
75
- * Who may deliver here.
76
- *
77
- * 'open' anyone may Append — an inbox the fediverse can post to
78
- * 'closed' nobody may — a quiesced actor, still resolving, taking no mail
79
- * { gatewayWebId } only that WebID may — mail arrives through a door that
80
- * verifies it first, and nobody may go round the door
81
- *
82
- * One operation because the three are one decision, and they were made in five
83
- * places: the profile publish, three separate methods, and the manage surface
84
- * reaching past all of them to set the ACL directly. A posture set in one of
85
- * those and not the others is an inbox that is open when it should be shut.
86
- */
87
- export async function setPosture(pod, urls, posture) {
88
- // Restated at every start, and most starts find it already so: the rule is
89
- // read first and written only when it differs (transport.setAcl ifChanged).
90
- if (posture === 'open') return pod.setAcl(urls.inbox, ['Append'], { ifChanged: true });
91
- if (posture === 'closed') return pod.setAcl(urls.inbox, [], { ifChanged: true });
92
- const webId = posture?.gatewayWebId;
93
- if (!webId) throw new Error(`inbox.setPosture: unknown posture ${JSON.stringify(posture)}`);
94
- // Public loses Append; the door keeps it. Both halves in one write, because
95
- // between two writes the inbox is either open to everyone or shut to the door.
96
- return pod.setAcl(urls.inbox, [], { appendAgents: [webId], ifChanged: true });
97
- }
98
-
99
- /**
100
- * What is waiting, oldest first.
101
- *
102
- * A defensive copy, because the transport hands back the SAME array on a 304
103
- * and the inbox is polled constantly — a caller that sorted or spliced in
104
- * place would corrupt the cache for every later reader.
105
- */
106
- export async function list(pod, urls) {
107
- const children = await pod.listContainer(urls.inbox);
108
- return children.map((c) => ({ ...c }));
109
- }
110
-
111
- /**
112
- * One item's bytes.
113
- *
114
- * A pod that would not GIVE us the item has told us nothing about it. Reading
115
- * a 500 as an empty body once made it "unparsable JSON" — which is a
116
- * REJECTION, so the delivery was dead-lettered with nothing recorded and then
117
- * DELETED: destroyed by a transient fault, with no trace of what it had been.
118
- * Anything but 404 throws, and the caller's retry path takes it. 404 is the
119
- * exception: the item is already gone, so removing it is right.
120
- *
121
- * Capped rather than read whole: the listing's size is advisory, the inbox is
122
- * public-Append, and the body is whatever a stranger chose to send.
123
- *
124
- * @returns {Promise<{status:number, raw:string|null}>}
125
- */
126
- export async function readItem(pod, url, { maxBytes, readCapped }) {
127
- const res = await pod.fetch(url, { headers: { accept: '*/*' } });
128
- if (res.status >= 400 && res.status !== 404) throw new Error(`inbox item GET → ${res.status}`);
129
- return { status: res.status, raw: res.status < 400 ? await readCapped(res, maxBytes) : null };
130
- }
131
-
132
- /** The gateway's receipt for an item, unparsed and unverified, or null. */
133
- export async function readDeliveryReceipt(pod, itemUrl, { maxBytes, readCapped }) {
134
- const res = await pod.fetch(itemUrl + '.receipt.json', { headers: { accept: 'application/json' } });
135
- if (res.status >= 400) return null;
136
- return JSON.parse(await readCapped(res, maxBytes));
137
- }
138
-
139
- /**
140
- * Remove an item that has been dealt with.
141
- *
142
- * This must NOT know about the caller's state: the drain deletes only after
143
- * its own state write has landed, and folding that gate in here would put the
144
- * decision somewhere with no view of whether it did. Getting that wrong
145
- * deletes deliveries whose record never persisted — silent, and unrecoverable.
146
- *
147
- * @returns {Promise<boolean>} whether the pod removed it
148
- */
149
- export const dropHandledItem = (pod, url) => pod.delete(url);
150
-
151
- /**
152
- * Remove the receipt a gateway wrote beside an item, once the item is gone.
153
- * Best-effort: a receipt that stays is a stray document, never a lost
154
- * delivery. Left behind, they were one stray per delivery, forever.
155
- */
156
- export const dropReceiptBeside = (pod, url) => pod.delete(url + '.receipt.json').catch(() => false);
157
-
158
- /**
159
- * Receipts whose item is no longer in the inbox, from the last listing: what
160
- * earlier drains left behind. The drain removes a few of these each sweep
161
- * until none are left.
162
- */
163
- export const orphanReceipts = (pod, urls) => pod.orphanReceipts?.(urls.inbox) ?? [];
164
-
165
- /** Remove one such stray. @returns {Promise<boolean>} whether the pod removed it */
166
- export const dropStrayReceipt = (pod, url) => pod.delete(url).catch(() => false);
package/lib/pod/links.mjs DELETED
@@ -1,35 +0,0 @@
1
- // links.mjs — reading RFC 8288 Link headers.
2
- //
3
- // Solid says where a resource's access control lives, where a storage
4
- // describes itself, and who owns a storage, by putting a link on the response.
5
- // Working any of those out from the resource's own URL instead is exactly what
6
- // the specs tell clients not to do, so this is the one place that reads them.
7
-
8
- /**
9
- * Every target a Link header gives for one relation, resolved against the URL
10
- * the header came from. A header may carry several links, and one link may
11
- * carry several relation names.
12
- */
13
- export function linkTargets(headerValue, rel, baseUrl) {
14
- if (!headerValue) return [];
15
- const wanted = String(rel).toLowerCase();
16
- const out = [];
17
- // Split on the commas BETWEEN links: one inside a URI has its closing angle
18
- // bracket still ahead of it, and is left alone.
19
- for (const part of String(headerValue).split(/,(?![^<]*>)/u)) {
20
- const link = /^\s*<([^>]*)>\s*(.*)$/u.exec(part);
21
- if (!link) continue;
22
- const relParam = /(?:^|;)\s*rel\s*=\s*(?:"([^"]*)"|([^;"\s]+))/iu.exec(link[2]);
23
- const names = (relParam?.[1] ?? relParam?.[2] ?? '').toLowerCase().split(/\s+/u);
24
- if (!names.includes(wanted)) continue;
25
- try { out.push(new URL(link[1], baseUrl).href); } catch { /* not a URL we can follow */ }
26
- }
27
- return out;
28
- }
29
-
30
- /** The relations this library follows. */
31
- export const REL = {
32
- acl: 'acl',
33
- storageDescription: 'http://www.w3.org/ns/solid/terms#storageDescription',
34
- owner: 'http://www.w3.org/ns/solid/terms#owner',
35
- };
@@ -1,52 +0,0 @@
1
- // location.mjs — where in a pod an application's container goes.
2
- //
3
- // The container's own name is the caller's. The person says which container of
4
- // their pod holds it, as a path on the pod's own origin: `/` for a subdomained
5
- // pod, `/jeff/` for a suffixed one, or any container below either. Everything then lives under `<that><name>`, and the root kept is that
6
- // place relative to the pod.
7
-
8
- // The pod's own furniture: its profile, its settings, its well-known documents.
9
- const RESERVED = new Set(['profile', 'settings', '.well-known']);
10
- const SEGMENT = /^[A-Za-z0-9._-]+$/u;
11
-
12
- /** The prefilled answer: the pod's own root, as a path. */
13
- export function podRootPath(podBase) {
14
- return new URL(podBase).pathname;
15
- }
16
-
17
- /**
18
- * The container path someone typed, checked against their pod. Returns
19
- * `{ root }` — the root relative to the pod, ending in `name` — or
20
- * `{ problem }` saying what is wrong, in words for them.
21
- */
22
- export function rootFromContainer(podBase, typed, name) {
23
- const base = new URL(podBase);
24
- let path = String(typed ?? '').trim() || base.pathname;
25
- if (!path.startsWith('/')) path = '/' + path;
26
- if (!path.endsWith('/')) path += '/';
27
- if (!path.startsWith(base.pathname)) {
28
- return { problem: `that is not in your pod — your pod starts at ${base.pathname}` };
29
- }
30
- const inside = path.slice(base.pathname.length);
31
- const segments = inside.split('/').filter(Boolean);
32
- if (segments.some(s => s === '.' || s === '..')) return { problem: 'a container path cannot go up with ..' };
33
- if (segments.some(s => !SEGMENT.test(s))) {
34
- return { problem: 'container names are letters, digits, dots, dashes and underscores' };
35
- }
36
- if (segments.length && RESERVED.has(segments[0])) {
37
- return { problem: `${base.pathname}${segments[0]}/ belongs to your pod itself — choose another container` };
38
- }
39
- if (segments.length > 8) return { problem: 'that is nested too deep — eight containers at most' };
40
- return { root: (segments.length ? segments.join('/') + '/' : '') + name };
41
- }
42
-
43
- /** Where the account lives, in full: the pod plus its root. */
44
- export const homeOf = (podBase, root) => podBase + root;
45
-
46
- /** The root back from a pod actor's address: `<pod><root>ap/actor`. */
47
- export function rootOfActor(podBase, actorUrl) {
48
- const a = String(actorUrl || '');
49
- if (!a.startsWith(podBase) || !a.endsWith('ap/actor')) return null;
50
- const root = a.slice(podBase.length, -'ap/actor'.length);
51
- return root.endsWith('/') ? root : null;
52
- }
package/lib/pod/media.mjs DELETED
@@ -1,27 +0,0 @@
1
- // media.mjs — ap/media/: the bytes an attachment points at.
2
- //
3
- // The only tree here holding things that are not documents. Public-Read,
4
- // because an attachment url travels inside a post to servers that will fetch
5
- // it without credentials — and unlike an actor or a note, nothing checks that
6
- // the url belongs to the identity that posted it, which is why media stays on
7
- // the pod even for an identity whose ids are advertised elsewhere: proxying
8
- // blobs would be pure cost for no verification gained.
9
-
10
- const PUBLIC_READ = ['Read'];
11
-
12
- // ---- the owner's agent ----
13
-
14
- export async function provisionContainer(pod, urls) {
15
- await pod.putJson(urls.media + '.keep', { keep: true }, 'application/json');
16
- await pod.setAcl(urls.media, PUBLIC_READ);
17
- }
18
-
19
- /**
20
- * One uploaded file.
21
- *
22
- * Takes the container as given: an upload into a container that was never
23
- * provisioned is a 404, or worse a file nobody outside can read, so the caller
24
- * ensures the container first — see provisionContainer, and the `exists` probe
25
- * in containers.mjs that keeps a worker restart from re-provisioning.
26
- */
27
- export const write = (pod, url, bytes, contentType) => pod.put(url, bytes, contentType);
package/lib/pod/notes.mjs DELETED
@@ -1,78 +0,0 @@
1
- // notes.mjs — ap/notes/: the posts themselves, and the two documents each one
2
- // drags with it.
3
- //
4
- // A published post is not one document. It is the Note, the Create activity
5
- // that announced it, and a replies collection remote servers will dereference
6
- // — and they have different lifetimes, which is the whole reason this file
7
- // exists. Deleting a post REPLACES the Note with a Tombstone (a peer learns
8
- // the post was deleted, rather than getting a bare 404 it reads as a temporary
9
- // failure) while DELETING the Create outright, because the Create was an
10
- // action that has been withdrawn rather than an object that still exists.
11
- //
12
- // The container is public-Read and the notes inherit it. The Tombstone is the
13
- // exception that has to state its own rule: a private post lives in a
14
- // different, owner-only container, so there is nothing public to inherit.
15
-
16
- const PUBLIC_READ = ['Read'];
17
-
18
- // ---- the owner's agent ----
19
-
20
- /** The notes container itself, public-Read so everything under it inherits. */
21
- export async function provisionContainer(pod, urls) {
22
- await pod.putJson(urls.notes + '.keep', { keep: true }, 'application/json');
23
- await pod.setAcl(urls.notes, PUBLIC_READ);
24
- }
25
-
26
- /** The Note. Inherits the container's rule; states none of its own. */
27
- export const write = (pod, noteId, doc) => pod.putJson(noteId, doc);
28
-
29
- /** The Create that announced it — its own document, at a derived id. */
30
- export const writeCreate = (pod, createId, doc) => pod.putJson(createId, doc);
31
-
32
- /**
33
- * An empty replies collection, written with the note.
34
- *
35
- * Remote servers dereference `replies`, and a dangling pointer that 404s is
36
- * worse than no pointer at all.
37
- */
38
- export const writeEmptyReplies = (pod, repliesId, doc) => pod.putJson(repliesId, doc);
39
-
40
- /** The replies collection as it stands. */
41
- export const readReplies = (pod, repliesId) => pod.getJson(repliesId);
42
- export const writeReplies = (pod, repliesId, doc) => pod.putJson(repliesId, doc);
43
-
44
- /** One published note, as the pod currently serves it. */
45
- export const read = (pod, noteId) => pod.getJson(noteId);
46
-
47
- /**
48
- * Replace a note with a Tombstone, and keep it readable.
49
- *
50
- * The Read rule is stated explicitly here even though the public container
51
- * grants it: a private or direct post lives in the owner-only container, and
52
- * its Tombstone still has to be fetchable by the servers being told about the
53
- * deletion.
54
- */
55
- export async function writeTombstone(pod, noteId, doc) {
56
- await pod.putJson(noteId, doc);
57
- await pod.setAcl(noteId, PUBLIC_READ);
58
- }
59
-
60
- /** The replies collection, once the note it belonged to is gone. */
61
- export const dropReplies = (pod, repliesId) => pod.delete(repliesId).catch(() => {});
62
-
63
- /**
64
- * What the container holds, with the derived documents filtered out.
65
- *
66
- * A listing returns the Note, its `-create` and its `-replies` alike; only the
67
- * first is a post, and handing the other two to a reader that expects posts
68
- * produces failures that read like corruption.
69
- */
70
- export async function list(pod, urls) {
71
- const children = await pod.listContainer(urls.notes);
72
- return children
73
- .filter((c) => !/(-create|-replies|-delete|-update-[^/]+)$/.test(c.url) && !/\/(announce|undo)-\d+$/.test(c.url)
74
- && !c.url.endsWith('.keep'))
75
- // A defensive copy: the transport hands back the same array on a 304, so a
76
- // caller that sorts in place would corrupt it for every later reader.
77
- .map((c) => ({ ...c }));
78
- }
@@ -1,89 +0,0 @@
1
- // notifications.mjs — being told when the inbox changes, instead of asking.
2
- //
3
- // A pod that offers Solid Notifications lets a client open a socket and hear
4
- // about a container the moment it changes, which is the difference between
5
- // mail arriving and mail being noticed two minutes later. Discovering that
6
- // service takes two unauthenticated reads of the pod's own description, and
7
- // then one authenticated POST to subscribe.
8
- //
9
- // This is the ONLY module here that parses RDF itself, which is why it is its
10
- // own file: a service that only ever appends to an inbox can import inbox.mjs
11
- // without pulling a parser in behind it.
12
-
13
- import * as $rdf from 'rdflib';
14
- import { readCapped } from './http.mjs';
15
- import { linkTargets, REL } from './links.mjs';
16
-
17
- const RDF = $rdf.Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#');
18
- const NOTIFY = $rdf.Namespace('http://www.w3.org/ns/solid/notifications#');
19
- const WS_CHANNEL = 'WebSocketChannel2023';
20
-
21
- // ---- anyone at all: a pod describes its own services publicly ----
22
-
23
- /**
24
- * Where this pod describes the services it offers.
25
- *
26
- * The pod says so on any response about one of its resources; the well-known
27
- * path is only what a pod that says nothing has always used. Unauthenticated
28
- * on purpose — this is a public fact about the server, asked before there is
29
- * anything to authenticate about.
30
- */
31
- export async function storageDescriptionUrl(podBase, { fetchImpl = fetch, headers = {}, timeoutMs = 20_000 } = {}) {
32
- try {
33
- const head = await fetchImpl(podBase, {
34
- method: 'HEAD', headers, signal: AbortSignal.timeout(timeoutMs),
35
- });
36
- const [found] = linkTargets(head.headers.get('link'), REL.storageDescription, podBase);
37
- if (found) return found;
38
- } catch { /* the well-known path below */ }
39
- return podBase + '.well-known/solid';
40
- }
41
-
42
- /**
43
- * The websocket channel service this pod offers, or null when it offers none.
44
- *
45
- * Asked of rdflib rather than pattern-matched: the description is RDF, and the
46
- * gap between "a string that appears in the document" and "the service this
47
- * pod actually advertises" is where quiet bugs live. A pod may name the type
48
- * on the service, or name the service's channelType — both are asked for.
49
- */
50
- export async function readWebSocketChannel(descUrl, { fetchImpl = fetch, headers = {}, timeoutMs = 20_000 } = {}) {
51
- const res = await fetchImpl(descUrl, {
52
- headers: { accept: 'text/turtle', ...headers },
53
- signal: AbortSignal.timeout(timeoutMs),
54
- });
55
- const g = $rdf.graph();
56
- try {
57
- $rdf.parse(await readCapped(res), g, descUrl, 'text/turtle');
58
- } catch (e) {
59
- return { channel: null, error: `service description unparsable (${e.message})` };
60
- }
61
- const channel = g.each(null, RDF('type'), NOTIFY(WS_CHANNEL), null).map((n) => n.value).find(Boolean)
62
- || g.each(null, NOTIFY('channelType'), NOTIFY(WS_CHANNEL), null).map((n) => n.value).find(Boolean);
63
- return { channel: channel || null, error: channel ? null : `no ${WS_CHANNEL} service` };
64
- }
65
-
66
- // ---- the owner's agent ----
67
-
68
- /**
69
- * Subscribe to changes on the inbox.
70
- *
71
- * `podTopicUrl` is POD-SPACE, and the parameter is named that way because
72
- * getting it wrong fails in a way nothing else here does: the topic travels in
73
- * the BODY, so the advertised-to-pod url map a transport applies to the
74
- * request LINE never reaches it. An identity whose ids are advertised
75
- * elsewhere would name a container the pod cannot grant read on, and the
76
- * subscription comes back 403.
77
- */
78
- export async function subscribeToInbox(pod, { channelUrl, podTopicUrl, ...rest }) {
79
- return pod.fetch(channelUrl, {
80
- method: 'POST',
81
- headers: { 'content-type': 'application/ld+json' },
82
- body: JSON.stringify({
83
- '@context': ['https://www.w3.org/ns/solid/notification/v1'],
84
- type: `http://www.w3.org/ns/solid/notifications#${WS_CHANNEL}`,
85
- topic: podTopicUrl,
86
- ...rest,
87
- }),
88
- });
89
- }
@@ -1,18 +0,0 @@
1
- // outbox.mjs — ap/outbox: everything this actor has published, paged.
2
- //
3
- // Public by definition, and read by strangers rather than by us: a remote
4
- // server walks it to backfill an account it has just met. It is also what a
5
- // rebuild reads to recover posts a lost machine no longer has, which is why
6
- // readPublished tolerates the flat shape this project used to write.
7
-
8
- import * as collection from './collection.mjs';
9
-
10
- // ---- the owner's agent ----
11
-
12
- export const writePage = (pod, pageUrl, doc, opts) => collection.writePage(pod, pageUrl, doc, opts);
13
- export const writeHead = (pod, urls, doc, opts) => collection.writeHead(pod, urls.outbox, doc, opts);
14
- export const dropPage = (pod, pageUrl) => collection.dropPage(pod, pageUrl);
15
-
16
- /** Every activity the pod currently publishes, or null if it publishes none. */
17
- export const readPublished = (pod, urls) =>
18
- collection.readPaged(pod, urls.outbox, { max: 10_000 });
@@ -1,19 +0,0 @@
1
- {
2
- "name": "solid-ap-pod",
3
- "version": "0.1.0",
4
- "description": "Read and write an ActivityPub actor's documents on a Solid pod: the container layout, an injected-session transport, WAC access control, and one module per pod resource.",
5
- "type": "module",
6
- "license": "MIT",
7
- "exports": {
8
- "./urls.mjs": "./urls.mjs",
9
- "./transport.mjs": "./transport.mjs",
10
- "./http.mjs": "./http.mjs",
11
- "./links.mjs": "./links.mjs"
12
- },
13
- "dependencies": {
14
- "rdflib": "^2.4.0"
15
- },
16
- "engines": {
17
- "node": ">=20"
18
- }
19
- }