fedipod-server 0.28.1 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (438) hide show
  1. package/README.md +38 -34
  2. package/config/server.json +22 -0
  3. package/dist/claims.js +3 -2
  4. package/dist/directory.d.ts +2 -0
  5. package/dist/door.d.ts +4 -0
  6. package/dist/door.js +31 -0
  7. package/dist/fedipod.d.ts +16 -0
  8. package/dist/fedipod.js +13 -0
  9. package/dist/front.d.ts +3 -0
  10. package/dist/front.js +94 -0
  11. package/dist/handler.d.ts +39 -101
  12. package/dist/handler.js +86 -617
  13. package/dist/handler.jsonld +6 -30
  14. package/dist/identities.d.ts +62 -0
  15. package/dist/identities.js +236 -0
  16. package/dist/mounts.d.ts +43 -0
  17. package/dist/mounts.js +123 -0
  18. package/dist/opt-in.d.ts +46 -0
  19. package/dist/opt-in.js +176 -0
  20. package/dist/store-pod.js +37 -0
  21. package/package.json +10 -18
  22. package/lib/client/c2s.mjs +0 -582
  23. package/lib/client/localapi.mjs +0 -87
  24. package/lib/client/masto/accounts.mjs +0 -309
  25. package/lib/client/masto/body.mjs +0 -156
  26. package/lib/client/masto/index.mjs +0 -206
  27. package/lib/client/masto/instance.mjs +0 -112
  28. package/lib/client/masto/media.mjs +0 -79
  29. package/lib/client/masto/oauth.mjs +0 -656
  30. package/lib/client/masto/render.mjs +0 -518
  31. package/lib/client/masto/statuses.mjs +0 -372
  32. package/lib/client/masto/timelines.mjs +0 -438
  33. package/lib/client/oidc-auth.mjs +0 -62
  34. package/lib/client/streaming.mjs +0 -154
  35. package/lib/client/webpush.mjs +0 -98
  36. package/lib/connections/acctfeed.mjs +0 -257
  37. package/lib/connections/atproto.mjs +0 -309
  38. package/lib/connections/bskyfeed.mjs +0 -243
  39. package/lib/connections/bskygroup.mjs +0 -162
  40. package/lib/connections/fediacct.mjs +0 -253
  41. package/lib/connections/import.mjs +0 -357
  42. package/lib/connections/tagfeed.mjs +0 -212
  43. package/lib/connections/vault.mjs +0 -114
  44. package/lib/core/as2.mjs +0 -206
  45. package/lib/core/contexts/activitystreams.json +0 -379
  46. package/lib/core/contexts/anno.json +0 -126
  47. package/lib/core/contexts/did-v1.json +0 -57
  48. package/lib/core/contexts/fep-5711.json +0 -36
  49. package/lib/core/contexts/gotosocial.json +0 -86
  50. package/lib/core/contexts/identity-v1.json +0 -152
  51. package/lib/core/contexts/index.mjs +0 -63
  52. package/lib/core/contexts/join-lemmy.json +0 -33
  53. package/lib/core/contexts/joinmastodon.json +0 -28
  54. package/lib/core/contexts/litepub-0.1.json +0 -60
  55. package/lib/core/contexts/map.json +0 -19
  56. package/lib/core/contexts/miscellany.json +0 -19
  57. package/lib/core/contexts/quotes.json +0 -18
  58. package/lib/core/contexts/schemaorg.json +0 -8845
  59. package/lib/core/contexts/security-data-integrity-v1.json +0 -78
  60. package/lib/core/contexts/security-data-integrity-v2.json +0 -81
  61. package/lib/core/contexts/security-multikey-v1.json +0 -35
  62. package/lib/core/contexts/security-v1.json +0 -74
  63. package/lib/core/contexts/webfinger.json +0 -10
  64. package/lib/core/deliver.mjs +0 -371
  65. package/lib/core/graphview.mjs +0 -327
  66. package/lib/core/intake/activities.mjs +0 -633
  67. package/lib/core/intake/activity.mjs +0 -318
  68. package/lib/core/intake/channel.mjs +0 -144
  69. package/lib/core/intake/group.mjs +0 -256
  70. package/lib/core/intake/index.mjs +0 -701
  71. package/lib/core/intake/notes.mjs +0 -360
  72. package/lib/core/intake/verify.mjs +0 -142
  73. package/lib/core/keys.mjs +0 -153
  74. package/lib/core/lease.mjs +0 -206
  75. package/lib/core/polls.mjs +0 -105
  76. package/lib/core/profile-page.mjs +0 -104
  77. package/lib/core/proof.mjs +0 -79
  78. package/lib/core/publisher/collections.mjs +0 -237
  79. package/lib/core/publisher/index.mjs +0 -500
  80. package/lib/core/publisher/notes.mjs +0 -453
  81. package/lib/core/publisher/questions.mjs +0 -239
  82. package/lib/core/publisher/restore.mjs +0 -224
  83. package/lib/core/shapes/activitystreams.ttl +0 -157
  84. package/lib/core/shapes/index.mjs +0 -132
  85. package/lib/core/shapes/shapes-text.mjs +0 -13
  86. package/lib/core/social.mjs +0 -531
  87. package/lib/core/storage.mjs +0 -176
  88. package/lib/core/store.mjs +0 -568
  89. package/lib/core/wire-quotes.mjs +0 -71
  90. package/lib/core/wire.mjs +0 -889
  91. package/lib/device/account.mjs +0 -87
  92. package/lib/device/admin/index.mjs +0 -13
  93. package/lib/device/admin/origins.mjs +0 -35
  94. package/lib/device/admin/routes/connections.mjs +0 -144
  95. package/lib/device/admin/routes/gateway.mjs +0 -199
  96. package/lib/device/admin/routes/lifecycle.mjs +0 -200
  97. package/lib/device/admin/routes/owner.mjs +0 -322
  98. package/lib/device/admin/routes/setup.mjs +0 -412
  99. package/lib/device/admin/routes/social.mjs +0 -188
  100. package/lib/device/admin/server.mjs +0 -95
  101. package/lib/device/admin/static.mjs +0 -247
  102. package/lib/device/admin/surface.mjs +0 -315
  103. package/lib/device/certs.mjs +0 -281
  104. package/lib/device/cli/commands/account.mjs +0 -586
  105. package/lib/device/cli/commands/run.mjs +0 -278
  106. package/lib/device/cli/commands/service.mjs +0 -221
  107. package/lib/device/cli/commands/setup.mjs +0 -447
  108. package/lib/device/cli/commands/state.mjs +0 -561
  109. package/lib/device/cli/context.mjs +0 -288
  110. package/lib/device/export-collections.mjs +0 -161
  111. package/lib/device/gateway-move.mjs +0 -58
  112. package/lib/device/home.mjs +0 -161
  113. package/lib/device/migrate.mjs +0 -115
  114. package/lib/device/ports.mjs +0 -27
  115. package/lib/device/remote.mjs +0 -54
  116. package/lib/device/setup.mjs +0 -459
  117. package/lib/device/update.mjs +0 -96
  118. package/lib/gateway/caches.mjs +0 -36
  119. package/lib/gateway/directory.mjs +0 -90
  120. package/lib/gateway/front-core.mjs +0 -970
  121. package/lib/gateway/gateway-core.mjs +0 -165
  122. package/lib/gateway/headers.mjs +0 -49
  123. package/lib/gateway/httpsig.mjs +0 -159
  124. package/lib/gateway/notices.mjs +0 -84
  125. package/lib/gateway/quiet.mjs +0 -189
  126. package/lib/pod/README.md +0 -61
  127. package/lib/pod/actor.mjs +0 -96
  128. package/lib/pod/collection.mjs +0 -77
  129. package/lib/pod/containers.mjs +0 -140
  130. package/lib/pod/discovery.mjs +0 -46
  131. package/lib/pod/featured.mjs +0 -18
  132. package/lib/pod/followers.mjs +0 -24
  133. package/lib/pod/following.mjs +0 -10
  134. package/lib/pod/http.mjs +0 -74
  135. package/lib/pod/inbox.mjs +0 -166
  136. package/lib/pod/links.mjs +0 -35
  137. package/lib/pod/media.mjs +0 -27
  138. package/lib/pod/notes.mjs +0 -80
  139. package/lib/pod/notifications.mjs +0 -89
  140. package/lib/pod/outbox.mjs +0 -18
  141. package/lib/pod/package.json +0 -19
  142. package/lib/pod/policy.mjs +0 -58
  143. package/lib/pod/private.mjs +0 -19
  144. package/lib/pod/root.mjs +0 -104
  145. package/lib/pod/state.mjs +0 -40
  146. package/lib/pod/transport.mjs +0 -525
  147. package/lib/pod/urls.mjs +0 -85
  148. package/lib/server/embed.mjs +0 -423
  149. package/lib/session/README.md +0 -137
  150. package/lib/session/demo.html +0 -94
  151. package/lib/session/fedi-account.mjs +0 -408
  152. package/lib/session/fedi-login.mjs +0 -123
  153. package/lib/session/oidc-session.mjs +0 -233
  154. package/lib/session/package.json +0 -49
  155. package/lib/shared/guard.mjs +0 -213
  156. package/lib/shared/links.mjs +0 -9
  157. package/lib/shared/safefetch.mjs +0 -235
  158. package/lib/shared/ua.mjs +0 -29
  159. package/phanpy/dist/404.html +0 -40
  160. package/phanpy/dist/_headers +0 -2
  161. package/phanpy/dist/apple-touch-icon.png +0 -0
  162. package/phanpy/dist/assets/ICONS-DIPJeU0C.js +0 -2
  163. package/phanpy/dist/assets/ICONS-DIPJeU0C.js.map +0 -1
  164. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js +0 -183
  165. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js.map +0 -1
  166. package/phanpy/dist/assets/Temml-CCjoacWt.woff2 +0 -0
  167. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js +0 -2
  168. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js.map +0 -1
  169. package/phanpy/dist/assets/boosts-carousel-BiOaNdMT.jpg +0 -0
  170. package/phanpy/dist/assets/catch-up-O5q5C75Z.png +0 -0
  171. package/phanpy/dist/assets/chunk-aKtaBQYM.js +0 -1
  172. package/phanpy/dist/assets/compose-CFEx7wb4.js +0 -2
  173. package/phanpy/dist/assets/compose-CFEx7wb4.js.map +0 -1
  174. package/phanpy/dist/assets/compose-ZJN5xSb4.js +0 -35
  175. package/phanpy/dist/assets/compose-ZJN5xSb4.js.map +0 -1
  176. package/phanpy/dist/assets/debug.module-YFQgwnIr.js +0 -52
  177. package/phanpy/dist/assets/debug.module-YFQgwnIr.js.map +0 -1
  178. package/phanpy/dist/assets/dom-p1YcJ5Rw.js +0 -2
  179. package/phanpy/dist/assets/dom-p1YcJ5Rw.js.map +0 -1
  180. package/phanpy/dist/assets/home-mobile-dark@2x-Dc-J8-SM.png +0 -0
  181. package/phanpy/dist/assets/home-mobile-light@2x-Bd3fod8m.png +0 -0
  182. package/phanpy/dist/assets/home-tablet-dark@2x-BgcNI8le.png +0 -0
  183. package/phanpy/dist/assets/home-tablet-light@2x-BW2RV9T6.png +0 -0
  184. package/phanpy/dist/assets/icons/add-circle-line-WD0mwORD.js +0 -1
  185. package/phanpy/dist/assets/icons/alert-line-CpFUMf9s.js +0 -1
  186. package/phanpy/dist/assets/icons/android-2-line-Bzxnrd3S.js +0 -1
  187. package/phanpy/dist/assets/icons/announcement-line-5nwaJFJm.js +0 -1
  188. package/phanpy/dist/assets/icons/arrow-down-circle-line-a7Id9-Iv.js +0 -1
  189. package/phanpy/dist/assets/icons/arrow-down-line-B8uzXzq6.js +0 -1
  190. package/phanpy/dist/assets/icons/arrow-left-line-CGrGT9C-.js +0 -1
  191. package/phanpy/dist/assets/icons/arrow-right-line-CE-HERfX.js +0 -1
  192. package/phanpy/dist/assets/icons/arrow-to-up-line-CvdQjmcy.js +0 -1
  193. package/phanpy/dist/assets/icons/arrow-up-circle-line-DEparSNF.js +0 -1
  194. package/phanpy/dist/assets/icons/arrow-up-line-C7yBeugc.js +0 -1
  195. package/phanpy/dist/assets/icons/arrows-right-line-BtbXmJGP.js +0 -1
  196. package/phanpy/dist/assets/icons/at-line-CF66Bznk.js +0 -1
  197. package/phanpy/dist/assets/icons/attachment-line-BY8It-l9.js +0 -1
  198. package/phanpy/dist/assets/icons/blockquote-line-BS6pU_hm.js +0 -1
  199. package/phanpy/dist/assets/icons/board-line-C0UWXyA6.js +0 -1
  200. package/phanpy/dist/assets/icons/bookmark-line-1CtX5JLF.js +0 -1
  201. package/phanpy/dist/assets/icons/building-5-line-Dd59MzbO.js +0 -1
  202. package/phanpy/dist/assets/icons/bus-2-line-6_dvA0GG.js +0 -1
  203. package/phanpy/dist/assets/icons/calendar-day-line-Crpl_fmu.js +0 -1
  204. package/phanpy/dist/assets/icons/calendar-month-line-vommts2C.js +0 -1
  205. package/phanpy/dist/assets/icons/calendar-time-add-line-BU_DTlQk.js +0 -1
  206. package/phanpy/dist/assets/icons/camera-line-Cv69MEei.js +0 -1
  207. package/phanpy/dist/assets/icons/celebrate-line-B8DvIoi0.js +0 -1
  208. package/phanpy/dist/assets/icons/chart-bar-line-FK-QOmtF.js +0 -1
  209. package/phanpy/dist/assets/icons/chart-line-line-BGcJAFWw.js +0 -1
  210. package/phanpy/dist/assets/icons/chat-3-line-YFK2-hwz.js +0 -1
  211. package/phanpy/dist/assets/icons/check-circle-line-DsAxFr5-.js +0 -1
  212. package/phanpy/dist/assets/icons/clipboard-line-BBp364gJ.js +0 -1
  213. package/phanpy/dist/assets/icons/close-circle-line-CICdiuGz.js +0 -1
  214. package/phanpy/dist/assets/icons/close-line-DYrFWcjv.js +0 -1
  215. package/phanpy/dist/assets/icons/cloud-line-tiQAbah8.js +0 -1
  216. package/phanpy/dist/assets/icons/code-line-fAl8iiV3.js +0 -1
  217. package/phanpy/dist/assets/icons/comment-2-line-CR3g7WeB.js +0 -1
  218. package/phanpy/dist/assets/icons/copy-2-line-CLW69yF5.js +0 -1
  219. package/phanpy/dist/assets/icons/delete-2-line-B8xmbr4n.js +0 -1
  220. package/phanpy/dist/assets/icons/document-3-line-DBGNhAg2.js +0 -1
  221. package/phanpy/dist/assets/icons/document-line-C7mb9sb7.js +0 -1
  222. package/phanpy/dist/assets/icons/down-line-BGqSSThd.js +0 -1
  223. package/phanpy/dist/assets/icons/edit-4-line-DcgGaEhx.js +0 -1
  224. package/phanpy/dist/assets/icons/emoji-2-line-D8YgnM-y.js +0 -1
  225. package/phanpy/dist/assets/icons/exit-line-Dc07BS-x.js +0 -1
  226. package/phanpy/dist/assets/icons/external-link-line-BvpSkmjO.js +0 -1
  227. package/phanpy/dist/assets/icons/eye-2-line-CiWXx-f_.js +0 -1
  228. package/phanpy/dist/assets/icons/eye-close-line-BgTaSJ4P.js +0 -1
  229. package/phanpy/dist/assets/icons/filter-2-line-B_mR2usy.js +0 -1
  230. package/phanpy/dist/assets/icons/filter-line-C_nm-3cU.js +0 -1
  231. package/phanpy/dist/assets/icons/flag-1-line-C2HB05I0.js +0 -1
  232. package/phanpy/dist/assets/icons/forbid-circle-line-D3LTT9yd.js +0 -1
  233. package/phanpy/dist/assets/icons/formula-line-DLrt2d6j.js +0 -1
  234. package/phanpy/dist/assets/icons/grid-line-CgUmEikf.js +0 -1
  235. package/phanpy/dist/assets/icons/group-line-C5fnX0wU.js +0 -1
  236. package/phanpy/dist/assets/icons/hand-finger-2-line-BGgxbuL9.js +0 -1
  237. package/phanpy/dist/assets/icons/hashtag-line-CyTEEXBb.js +0 -1
  238. package/phanpy/dist/assets/icons/heart-crack-line-BZddbO2C.js +0 -1
  239. package/phanpy/dist/assets/icons/heart-line-CJ7K47J4.js +0 -1
  240. package/phanpy/dist/assets/icons/history-2-line-kWWvFzqv.js +0 -1
  241. package/phanpy/dist/assets/icons/history-line-bGQiwbTH.js +0 -1
  242. package/phanpy/dist/assets/icons/home-3-line-fRU1zeLG.js +0 -1
  243. package/phanpy/dist/assets/icons/information-line-iNk6-sOY.js +0 -1
  244. package/phanpy/dist/assets/icons/keyboard-line-DsCyuQNz.js +0 -1
  245. package/phanpy/dist/assets/icons/layout-4-line-CZkOX52Z.js +0 -1
  246. package/phanpy/dist/assets/icons/layout-5-line-B_znt5wO.js +0 -1
  247. package/phanpy/dist/assets/icons/left-line-eUw0tya4.js +0 -1
  248. package/phanpy/dist/assets/icons/lightning-line-DaKoDdix.js +0 -1
  249. package/phanpy/dist/assets/icons/link-2-line-DCqLmMA7.js +0 -1
  250. package/phanpy/dist/assets/icons/list-check-line-BAxosBh9.js +0 -1
  251. package/phanpy/dist/assets/icons/lock-line-CPoaXeUW.js +0 -1
  252. package/phanpy/dist/assets/icons/mail-line-B0P8aa1L.js +0 -1
  253. package/phanpy/dist/assets/icons/moon-line-CEqNAToP.js +0 -1
  254. package/phanpy/dist/assets/icons/more-1-fill-Dw2e5xab.js +0 -1
  255. package/phanpy/dist/assets/icons/more-3-line-BIiVjYTz.js +0 -1
  256. package/phanpy/dist/assets/icons/notification-line-BZZq2Gtu.js +0 -1
  257. package/phanpy/dist/assets/icons/pencil-line-CKh8-A1v.js +0 -1
  258. package/phanpy/dist/assets/icons/photo-album-line-Bnfg2u40.js +0 -1
  259. package/phanpy/dist/assets/icons/pin-line-DpTolyhs.js +0 -1
  260. package/phanpy/dist/assets/icons/play-fill-B0-G_8lX.js +0 -1
  261. package/phanpy/dist/assets/icons/qrcode-2-line-B6SPCaHn.js +0 -1
  262. package/phanpy/dist/assets/icons/quill-pen-line-B6LUrnCP.js +0 -1
  263. package/phanpy/dist/assets/icons/quote-left-fill-hQZ1cj_6.js +0 -1
  264. package/phanpy/dist/assets/icons/radar-line-CKyroTth.js +0 -1
  265. package/phanpy/dist/assets/icons/react-line-CoIKhhtK.js +0 -1
  266. package/phanpy/dist/assets/icons/refresh-2-line-D0mTF97S.js +0 -1
  267. package/phanpy/dist/assets/icons/right-line-B3KWJaqc.js +0 -1
  268. package/phanpy/dist/assets/icons/rocket-line-4KZl537D.js +0 -1
  269. package/phanpy/dist/assets/icons/round-fill-C69NTrZ0.js +0 -1
  270. package/phanpy/dist/assets/icons/round-line-B9k_1uo-.js +0 -1
  271. package/phanpy/dist/assets/icons/route-line-B28ReHcE.js +0 -1
  272. package/phanpy/dist/assets/icons/rows-4-line-CrBniagM.js +0 -1
  273. package/phanpy/dist/assets/icons/scan-line-DSf74YdP.js +0 -1
  274. package/phanpy/dist/assets/icons/search-2-line-B6geIU1z.js +0 -1
  275. package/phanpy/dist/assets/icons/settings-3-line-azJwK47w.js +0 -1
  276. package/phanpy/dist/assets/icons/settings-6-line-C_5zc5YR.js +0 -1
  277. package/phanpy/dist/assets/icons/share-2-line-D5MxWjrm.js +0 -1
  278. package/phanpy/dist/assets/icons/share-forward-line-Cp61fZzZ.js +0 -1
  279. package/phanpy/dist/assets/icons/sparkles-2-line-DYYyXTaW.js +0 -1
  280. package/phanpy/dist/assets/icons/sparkles-line-C2hY1s6I.js +0 -1
  281. package/phanpy/dist/assets/icons/time-line-BF3eet1v.js +0 -1
  282. package/phanpy/dist/assets/icons/transfer-4-line-oisfvTBw.js +0 -1
  283. package/phanpy/dist/assets/icons/translate-line-BFWol2Ce.js +0 -1
  284. package/phanpy/dist/assets/icons/unlock-line-X_x5vwv3.js +0 -1
  285. package/phanpy/dist/assets/icons/upload-3-line-DgzwUJeW.js +0 -1
  286. package/phanpy/dist/assets/icons/user-4-line-BVSynZCp.js +0 -1
  287. package/phanpy/dist/assets/icons/user-add-2-line-BlGS5Q8q.js +0 -1
  288. package/phanpy/dist/assets/icons/user-add-line-BbXdHG4z.js +0 -1
  289. package/phanpy/dist/assets/icons/user-edit-line-BFAHOV0X.js +0 -1
  290. package/phanpy/dist/assets/icons/user-follow-line-BXux0wSd.js +0 -1
  291. package/phanpy/dist/assets/icons/user-star-line-DdYlpHLU.js +0 -1
  292. package/phanpy/dist/assets/icons/user-warning-line-Cj43j0_E.js +0 -1
  293. package/phanpy/dist/assets/icons/user-x-line-DIDgNlPH.js +0 -1
  294. package/phanpy/dist/assets/icons/volume-line-Bs390KQt.js +0 -1
  295. package/phanpy/dist/assets/icons/volume-mute-line-DzlzIqFZ.js +0 -1
  296. package/phanpy/dist/assets/icons/walk-line-yNXfB-md.js +0 -1
  297. package/phanpy/dist/assets/icons/world-2-line-CenkGIwj.js +0 -1
  298. package/phanpy/dist/assets/icons/zoom-in-line-CaENUphf.js +0 -1
  299. package/phanpy/dist/assets/icons/zoom-out-line-BDNk0EWo.js +0 -1
  300. package/phanpy/dist/assets/instances-BNPptnn-.json +0 -333
  301. package/phanpy/dist/assets/locales/ar-SA-CfheRbCu.js +0 -1
  302. package/phanpy/dist/assets/locales/ca-ES-DHRW86Tz.js +0 -1
  303. package/phanpy/dist/assets/locales/cs-CZ-CKoqEuA1.js +0 -1
  304. package/phanpy/dist/assets/locales/de-DE-ByRPMRFy.js +0 -1
  305. package/phanpy/dist/assets/locales/eo-UY-CPC7wLCS.js +0 -1
  306. package/phanpy/dist/assets/locales/es-ES-dJa0Fd9t.js +0 -1
  307. package/phanpy/dist/assets/locales/eu-ES-C3djlPR2.js +0 -1
  308. package/phanpy/dist/assets/locales/fa-IR-DTT490Ck.js +0 -1
  309. package/phanpy/dist/assets/locales/fi-FI-B23MCPuz.js +0 -1
  310. package/phanpy/dist/assets/locales/fr-FR-BcaQsO5C.js +0 -1
  311. package/phanpy/dist/assets/locales/gl-ES-BR-CVKBN.js +0 -1
  312. package/phanpy/dist/assets/locales/he-IL-CfheRbCu.js +0 -1
  313. package/phanpy/dist/assets/locales/hu-HU-CfheRbCu.js +0 -1
  314. package/phanpy/dist/assets/locales/it-IT-C1136UFV.js +0 -1
  315. package/phanpy/dist/assets/locales/ja-JP-CRZmRAhD.js +0 -1
  316. package/phanpy/dist/assets/locales/kab-Cz8xH_TT.js +0 -1
  317. package/phanpy/dist/assets/locales/ko-KR-CG9UiY4o.js +0 -1
  318. package/phanpy/dist/assets/locales/lt-LT-CJcI6sHZ.js +0 -1
  319. package/phanpy/dist/assets/locales/nb-NO-CfheRbCu.js +0 -1
  320. package/phanpy/dist/assets/locales/nl-NL-DxN4Yc1t.js +0 -1
  321. package/phanpy/dist/assets/locales/oc-FR-CfheRbCu.js +0 -1
  322. package/phanpy/dist/assets/locales/pl-PL-DkwGXf6P.js +0 -1
  323. package/phanpy/dist/assets/locales/pseudo-LOCALE-CQ4XxkQ0.js +0 -1
  324. package/phanpy/dist/assets/locales/pt-BR-nGL0HdFS.js +0 -1
  325. package/phanpy/dist/assets/locales/pt-PT-Cp17aj2z.js +0 -1
  326. package/phanpy/dist/assets/locales/ru-RU-0Y8cIoaK.js +0 -1
  327. package/phanpy/dist/assets/locales/th-TH-CfheRbCu.js +0 -1
  328. package/phanpy/dist/assets/locales/tok-CfheRbCu.js +0 -1
  329. package/phanpy/dist/assets/locales/tr-TR-CfheRbCu.js +0 -1
  330. package/phanpy/dist/assets/locales/uk-UA-C5E3dFBf.js +0 -1
  331. package/phanpy/dist/assets/locales/zh-CN-BHJi7_et.js +0 -1
  332. package/phanpy/dist/assets/locales/zh-TW-CfheRbCu.js +0 -1
  333. package/phanpy/dist/assets/main-BdqNbG-a.js +0 -26
  334. package/phanpy/dist/assets/main-BdqNbG-a.js.map +0 -1
  335. package/phanpy/dist/assets/mock-home-DGhR__He.js +0 -2
  336. package/phanpy/dist/assets/mock-home-DGhR__He.js.map +0 -1
  337. package/phanpy/dist/assets/multi-column-ROck0NVt.jpg +0 -0
  338. package/phanpy/dist/assets/multi-hashtag-timeline-DH5INVHi.jpg +0 -0
  339. package/phanpy/dist/assets/nested-comments-thread-hv59kZLc.jpg +0 -0
  340. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js +0 -2
  341. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js.map +0 -1
  342. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js +0 -20
  343. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js.map +0 -1
  344. package/phanpy/dist/assets/style-B1iLPTPR.css +0 -2
  345. package/phanpy/dist/assets/temml-DuyIQMei.js +0 -97
  346. package/phanpy/dist/assets/temml-DuyIQMei.js.map +0 -1
  347. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js +0 -2
  348. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js.map +0 -1
  349. package/phanpy/dist/assets/year-in-posts-B2lywqdx.png +0 -0
  350. package/phanpy/dist/assets/year-in-posts-DJv_star.js +0 -3
  351. package/phanpy/dist/assets/year-in-posts-DJv_star.js.map +0 -1
  352. package/phanpy/dist/compose/index.html +0 -20
  353. package/phanpy/dist/favicon.ico +0 -0
  354. package/phanpy/dist/index.html +0 -73
  355. package/phanpy/dist/logo-192.png +0 -0
  356. package/phanpy/dist/logo-512.png +0 -0
  357. package/phanpy/dist/logo-badge-72.png +0 -0
  358. package/phanpy/dist/logo-maskable-512.png +0 -0
  359. package/phanpy/dist/logo-monochrome-512.png +0 -0
  360. package/phanpy/dist/logo-monochrome-maskable-512.png +0 -0
  361. package/phanpy/dist/manifest.webmanifest +0 -1
  362. package/phanpy/dist/og-image-2.jpg +0 -0
  363. package/phanpy/dist/og-image.png +0 -0
  364. package/phanpy/dist/robots.txt +0 -2
  365. package/phanpy/dist/sw.js +0 -2
  366. package/phanpy/dist/sw.js.map +0 -1
  367. package/phanpy/dist/version.json +0 -1
  368. package/run-agent.mjs +0 -897
  369. package/vendor/gate.cjs +0 -138
  370. package/vendor/idp-grant.cjs +0 -394
  371. package/vendor/jfetch.cjs +0 -16
  372. package/web/admin/actors.js +0 -145
  373. package/web/admin/bar.css +0 -126
  374. package/web/admin/bar.js +0 -99
  375. package/web/admin/client/client.js +0 -66
  376. package/web/admin/client/index.html +0 -69
  377. package/web/admin/client-pick.js +0 -79
  378. package/web/admin/common.js +0 -23
  379. package/web/admin/connections.js +0 -112
  380. package/web/admin/gateway.js +0 -133
  381. package/web/admin/group.js +0 -258
  382. package/web/admin/index.html +0 -603
  383. package/web/admin/notices-bar.js +0 -90
  384. package/web/admin/oauth-signin.mjs +0 -37
  385. package/web/admin/record.js +0 -390
  386. package/web/admin/setup/index.html +0 -241
  387. package/web/admin/setup/setup.js +0 -326
  388. package/web/admin/tokens.css +0 -68
  389. package/web/admin/upkeep.js +0 -177
  390. package/web/admin/window.css +0 -55
  391. package/web/admin/window.js +0 -136
  392. package/web/app/README.md +0 -81
  393. package/web/app/admin-facade.mjs +0 -588
  394. package/web/app/agent.mjs +0 -663
  395. package/web/app/atproto-browser.mjs +0 -86
  396. package/web/app/authorize_interaction.html +0 -56
  397. package/web/app/authorize_interaction.js +0 -69
  398. package/web/app/boot.mjs +0 -576
  399. package/web/app/deliver-relay.mjs +0 -129
  400. package/web/app/dist/boot.js +0 -34218
  401. package/web/app/dist/boot.js.map +0 -7
  402. package/web/app/dist/sw.js +0 -72810
  403. package/web/app/dist/sw.js.map +0 -7
  404. package/web/app/fediacct-browser.mjs +0 -146
  405. package/web/app/gateway-move.mjs +0 -60
  406. package/web/app/idb-kv.mjs +0 -35
  407. package/web/app/index.html +0 -242
  408. package/web/app/keys-browser.mjs +0 -71
  409. package/web/app/keystore.mjs +0 -82
  410. package/web/app/oidc-session.mjs +0 -6
  411. package/web/app/pod-auth.mjs +0 -248
  412. package/web/app/pod-remote.mjs +0 -84
  413. package/web/app/shims/_globals.mjs +0 -2
  414. package/web/app/shims/fedify-sig.mjs +0 -77
  415. package/web/app/shims/node-crypto.mjs +0 -113
  416. package/web/app/shims/node-fs.mjs +0 -17
  417. package/web/app/shims/node-path.mjs +0 -19
  418. package/web/app/shims/node-url.mjs +0 -7
  419. package/web/app/shims/prelude.js +0 -58
  420. package/web/app/shims/safefetch.mjs +0 -58
  421. package/web/app/shims/shapes-text.mjs +0 -8
  422. package/web/app/shims/web-push.mjs +0 -14
  423. package/web/app/signup.mjs +0 -318
  424. package/web/app/sw-src.mjs +0 -220
  425. package/web/app/update.js +0 -70
  426. package/web/front/admin.html +0 -55
  427. package/web/front/admin.js +0 -89
  428. package/web/front/install.sh +0 -69
  429. package/web/front/new-account.html +0 -35
  430. package/web/front/new-account.js +0 -13
  431. package/web/front/notices.html +0 -69
  432. package/web/front/notices.js +0 -107
  433. package/web/front/run.html +0 -58
  434. package/web/front/run.js +0 -195
  435. package/web/front/solid-oidc-client.js +0 -6
  436. package/web/icons/forum.svg +0 -11
  437. package/web/icons/gateway.svg +0 -14
  438. package/web/icons/local.svg +0 -11
@@ -1,288 +0,0 @@
1
- // context.mjs — what every command starts from: the arguments, which
2
- // identity (HOME) and port (PORT) a command means, and the helpers that ask,
3
- // probe and finish. HOME, PORT and DEFAULT_ISSUE are live bindings: useProfile()
4
- // reassigns them and every command module sees the new value.
5
-
6
- import fs from 'node:fs';
7
- import { localFetch } from '../../../lib/client/localapi.mjs';
8
- import os from 'node:os';
9
- import path from 'node:path';
10
- import net from 'node:net';
11
- import readline from 'node:readline';
12
- import { spawn } from 'node:child_process';
13
- import { fileURLToPath, pathToFileURL } from 'node:url';
14
- import { apRoot, profilesDir, identityHomes, isLegacyRoot, CURRENT_ROOT, tildify, rootOf,
15
- readRoot, writeRoot, defaultProfile, profileHome, rootHoldsIdentity, ROOT_FILE,
16
- recordLastUsed, writeJsonAtomic } from '../../../lib/device/home.mjs';
17
- import { insecureUrlReason } from '../../../lib/shared/safefetch.mjs';
18
- import { portFree, freePortFrom } from '../../../lib/device/ports.mjs';
19
-
20
- export const args = process.argv.slice(2);
21
- export const cmd = args[0];
22
- export const flag = (name, dflt) => {
23
- const i = args.indexOf('--' + name);
24
- return i >= 0 ? args[i + 1] : dflt;
25
- };
26
- export const has = (name) => args.includes('--' + name);
27
- // The port can also be given bare — `npm start 8081` reaches us as `up 8081`,
28
- // because npm passes positionals through but eats `--port`. Bare form only for
29
- // the start-style commands, where a lone number cannot mean anything else.
30
- export const barePort = () => {
31
- if (!['up', 'start', 'run'].includes(cmd)) return null;
32
- for (let i = 1; i < args.length; i++) {
33
- if (/^\d+$/.test(args[i]) && !args[i - 1].startsWith('--')) return args[i];
34
- }
35
- return null;
36
- };
37
- export const portFlag = () => flag('port', null) || barePort();
38
- // One identity per home, and EVERY identity is `<root>/profiles/<name>/`. There
39
- // is no privileged unnamed one: `root.json` names which you get when you do not
40
- // say, and that is a pointer you can change rather than a directory you have to
41
- // move a private key out of. lib/home.mjs decides the root.
42
- //
43
- // An explicit --home / AP_HOME still wins and is taken literally: you named a
44
- // directory, so that directory is the identity, root.json unread. That is what
45
- // `rootOf` has always documented for a custom home.
46
- export const PROFILE = flag('profile', process.env.AP_PROFILE || null);
47
- export const AP_ROOT = apRoot();
48
- export const PROFILES_DIR = profilesDir(AP_ROOT);
49
-
50
- // `let`, because setup does not know which identity it is until it has asked for
51
- // the handle — the home is named after it. Everything below reads HOME at call
52
- // time, so reassigning it once, early, is enough; PORT is the exception and is
53
- // recomputed with it.
54
- export let DEFAULT_ISSUE = null; // set when the pointer is unusable
55
- export let HOME = flag('home', process.env.AP_HOME || (() => {
56
- if (PROFILE) return profileHome(AP_ROOT, PROFILE);
57
- const d = defaultProfile(AP_ROOT);
58
- if (typeof d === 'string') return profileHome(AP_ROOT, d);
59
- DEFAULT_ISSUE = d?.missing
60
- ? `${ROOT_FILE} names "${d.missing}", which is not an identity here`
61
- : 'there is more than one identity here and none is the default';
62
- return profileHome(AP_ROOT, d?.missing || '');
63
- })());
64
-
65
- // The port chosen at setup is remembered, so `start`/`stop`/`status` need no
66
- // flags afterwards. Precedence: --port (or a bare port number, `npm start
67
- // 8081`) > AP_PORT > the recorded choice > 8030.
68
- // The handle is remembered alongside it, for the named origin: the agent also
69
- // answers at <handle>.localhost:<port>, and that has to work from the first
70
- // request, before pod state has been read.
71
- export function recordedAgent() {
72
- try { return JSON.parse(fs.readFileSync(path.join(HOME, 'agent.json'), 'utf8')) || {}; }
73
- catch { return {}; }
74
- }
75
- export function recordedPort() { return Number(recordedAgent().port) || null; }
76
- export function recordAgent(fields) {
77
- try {
78
- fs.mkdirSync(HOME, { recursive: true, mode: 0o700 });
79
- const rec = { ...recordedAgent(), ...fields };
80
- writeJsonAtomic(path.join(HOME, 'agent.json'), rec, { mode: 0o644 });
81
- } catch { /* the flag still works, it just isn't remembered */ }
82
- }
83
- export let PORT = Number(portFlag() || process.env.AP_PORT || recordedPort() || 8030);
84
-
85
- // Setup is the one command that cannot know its home in advance: the identity is
86
- // named after the handle, and the handle is the first thing it asks. Everything
87
- // that reads HOME does so at call time, so pointing it at the right directory as
88
- // soon as the name exists is enough — PORT is recomputed because it was read
89
- // from the old home's agent.json.
90
- export function useProfile(name) {
91
- HOME = flag('home', process.env.AP_HOME || profileHome(AP_ROOT, name));
92
- PORT = Number(portFlag() || process.env.AP_PORT || recordedPort() || 8030);
93
- DEFAULT_ISSUE = null;
94
- return HOME;
95
- }
96
-
97
- // A handle becomes a directory name, so it is checked before it is one. Same
98
- // rule the admin API applies before creating an actor (admin.mjs) — without it
99
- // a handle containing a slash or `..` climbs out of profiles/.
100
- const HANDLE_RE = /^[a-z0-9][a-z0-9_-]{0,30}$/;
101
- export function requireHandle(handle) {
102
- if (HANDLE_RE.test(handle)) return handle;
103
- console.error(`"${handle}" cannot be a handle: letters, digits, hyphens and underscores,`);
104
- console.error('starting with a letter or digit, at most 31 characters.');
105
- process.exit(2);
106
- }
107
-
108
- // Commands that act on an identity need one decided. Says which of the three
109
- // ways it failed, because "no identity" and "which identity" are different
110
- // problems with different fixes.
111
- export function requireIdentity() {
112
- // An explicit AP_HOME / --home is an explicit identity directory. Nothing
113
- // about the machine's root applies to it — including whether that root has
114
- // been restructured, which is somebody else's install's problem.
115
- if (process.env.AP_HOME || flag('home')) return;
116
- if (rootHoldsIdentity(AP_ROOT)) {
117
- console.error(`${tildify(AP_ROOT)} still keeps an identity at its top level.`);
118
- console.error('Every identity lives in profiles/<name>/ now. Move this one down with:\n');
119
- console.error(` ${process.argv[1]} home --restructure\n`);
120
- process.exit(2);
121
- }
122
- if (!DEFAULT_ISSUE) return;
123
- const homes = identityHomes(AP_ROOT).filter(h => fs.existsSync(path.join(h.dir, 'credential.json')));
124
- console.error(DEFAULT_ISSUE + '.');
125
- if (homes.length) {
126
- console.error(`\n ${process.argv[1]} --profile <name> start\n`);
127
- console.error('Whichever you start is remembered, so plain commands mean that one afterwards.');
128
- console.error(`here: ${homes.map(h => h.name).join(', ')}`);
129
- } else {
130
- console.error(`\nThere are no identities yet — ${process.argv[1]} setup`);
131
- }
132
- process.exit(2);
133
- }
134
-
135
- export function askHidden(prompt) {
136
- return new Promise((resolve) => {
137
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
138
- const onData = (c) => { if (String(c) !== '\n' && String(c) !== '\r') readline.moveCursor(process.stdout, -1, 0), process.stdout.write('*'); };
139
- process.stdin.on('data', onData);
140
- rl.question(prompt, (answer) => { process.stdin.off('data', onData); rl.close(); process.stdout.write('\n'); resolve(answer); });
141
- });
142
- }
143
-
144
- // Plain prompt with a default: Enter accepts it. Non-interactive runs
145
- // (scripts, CI) take the default silently, so flags remain sufficient.
146
- let sharedRl = null; // one interface: a new one per
147
- export function ask(prompt, dflt = '') { // question would drop buffered input
148
- if (!process.stdin.isTTY) return Promise.resolve(dflt);
149
- sharedRl ||= readline.createInterface({ input: process.stdin, output: process.stdout });
150
- return new Promise((resolve) => {
151
- sharedRl.question(dflt ? `${prompt} [${dflt}]: ` : `${prompt}: `, (answer) => {
152
- resolve(String(answer).trim() || dflt);
153
- });
154
- });
155
- }
156
- export function endAsking() { sharedRl?.close(); sharedRl = null; }
157
-
158
- // "Occupied" means "cannot be bound", not "does not answer HTTP": something
159
- // holding a port without speaking HTTP reads as free to a GET, and then the
160
- // agent dies on EADDRINUSE.
161
-
162
- // The first port from `first` upward that binds. Walking always ends in one,
163
- // so this is a step rather than a condition.
164
-
165
- // Is anything at all on this port? For the operations that MOVE data, "it did
166
- // not answer as one of ours" is not the same as "nothing is there": an agent
167
- // started with AP_GATE_TOKEN answers 401 to an un-tokened /status, so agentOn
168
- // reads a perfectly live agent as stopped — and a sweep that trusted it would
169
- // copy the state out from under one, which the next write then overwrites.
170
- // Bind to find out, and fail closed.
171
- export async function somethingOn(port) {
172
- const mine = await agentOn(port);
173
- if (mine) return 'running';
174
- return (await portFree(port)) ? null : 'something is on the port and did not answer as ours';
175
- }
176
-
177
- // Whatever is on the port — is it one of ours?
178
- export async function agentOn(port) {
179
- try {
180
- const res = await localFetch(HOME, port, `/status`, { signal: AbortSignal.timeout(2000) });
181
- const body = await res.json();
182
- return typeof body?.configured === 'boolean' ? body : null;
183
- } catch { return null; }
184
- }
185
-
186
- export const isInside = (root, p) => {
187
- const rel = path.relative(root, p);
188
- return !!rel && !rel.startsWith('..') && !path.isAbsolute(rel);
189
- };
190
-
191
- export function openBrowser(url) {
192
- try {
193
- const win = process.platform === 'win32';
194
- const cmd = win ? 'cmd' : process.platform === 'darwin' ? 'open' : 'xdg-open';
195
- const child = spawn(cmd, win ? ['/c', 'start', '', url] : [url], { detached: true, stdio: 'ignore' });
196
- // A box with no opener at all (a server, a bare container) emits this
197
- // asynchronously, where the try/catch cannot reach it — and an unhandled
198
- // 'error' event on a child process ends the agent.
199
- child.on('error', () => {});
200
- child.unref();
201
- } catch { /* best-effort — the URL is printed anyway */ }
202
- }
203
-
204
- // A one-shot command holds the lease only for its own duration: exiting without
205
- // releasing it leaves the next `start` as a read-only viewer until the lease
206
- // expires, which is 5 minutes of doing nothing.
207
- export async function finish(agent, code = 0) {
208
- await agent.lease?.release().catch(() => {});
209
- await agent.store?.flush?.().catch(() => {});
210
- process.exit(code);
211
- }
212
-
213
- // Anything that decides the identity. Given even one of these, setup stays on
214
- // the command line exactly as it always did — scripts, CI and the tarball's
215
- // unpack-and-go line depend on that. At a terminal with none of them, setup
216
- // asks the two things it needs to open a browser and asks the rest there.
217
- export const IDENTITY_FLAGS = ['new-account', 'pod', 'issuer', 'email', 'name', 'pod-name',
218
- 'group', 'approve-joins', 'summary', 'icon', 'root', 'keys', 'rotate-key'];
219
-
220
- // Refuse before anything is asked, let alone typed: setup used to overwrite
221
- // credential.json in place, and a minted credential is only shown once — so
222
- // the identity it belonged to could not be recovered afterwards.
223
- export function refuseExistingIdentity() {
224
- const credPath = path.join(HOME, 'credential.json');
225
- if (!fs.existsSync(credPath) || has('force')) return;
226
- let held = '(unreadable)';
227
- try { held = JSON.parse(fs.readFileSync(credPath, 'utf8')).remotePod; } catch {}
228
- console.error(`${HOME} already holds an identity: ${held}`);
229
- console.error('For another identity: fedipod setup --profile <name>');
230
- console.error('To list what exists: fedipod profiles');
231
- console.error('To replace this one: add --force (the old credential is lost)');
232
- console.error('');
233
- console.error('If a setup died half-way, do NOT re-run it — the credential it already');
234
- console.error('minted cannot be minted twice. Run `fedipod start` and');
235
- console.error('finish at /admin/setup/ in the browser.');
236
- process.exit(2);
237
- }
238
-
239
- // Ask the handle (permanent, and it names the origin) and the port, start
240
- // serving, and hand over to the page at /admin/setup/. Nothing is created here: the
241
- // agent's own POST /setup does all of it, so a closed tab cannot lose a
242
- // credential that only exists in an HTTP response.
243
- export async function runBrowserSetup() {
244
- const handle = flag('handle') || await ask('handle (the name in your address; permanent)');
245
- if (!handle) { console.error('a handle is required'); process.exit(2); }
246
- // The handle names the home, so nothing can be decided before it — including
247
- // which identity would be overwritten, and which port was remembered.
248
- requireHandle(handle);
249
- useProfile(PROFILE || handle);
250
- refuseExistingIdentity();
251
- const port = portFlag() ? PORT : (Number(await ask('port', String(PORT))) || PORT);
252
- endAsking();
253
-
254
- // Recorded before the server starts, so `stop`/`status` work while the
255
- // browser flow is still open — it used to be written only after the mint.
256
- recordAgent({ port, handle });
257
-
258
- const { Agent } = await import(new URL('../../../run-agent.mjs', import.meta.url));
259
- const { startAdmin } = await import(new URL('../../../lib/device/admin/index.mjs', import.meta.url));
260
- const { hostLabel } = await import(new URL('../../../lib/shared/guard.mjs', import.meta.url));
261
- const agent = new Agent({ home: HOME, log: (...a) => console.log('[ap]', ...a) });
262
- startAdmin({
263
- port, handle, agent,
264
- gateToken: process.env.AP_GATE_TOKEN || '',
265
- log: (...a) => console.log('[ap]', ...a),
266
- });
267
- const shutdown = () => {
268
- setTimeout(() => process.exit(0), 1500).unref();
269
- try { fs.rmSync(path.join(HOME, 'agent.pid'), { force: true }); } catch {}
270
- Promise.allSettled([agent.store.flush(), agent.lease?.release()]).finally(() => process.exit(0));
271
- };
272
- process.on('SIGINT', shutdown);
273
- process.on('SIGTERM', shutdown);
274
-
275
- const label = hostLabel(handle);
276
- const named = label ? `https://${label}.localhost:${port}/` : null;
277
- const plain = `https://localhost:${port}/`;
278
- const pad = Math.max(named?.length || 0, plain.length);
279
- console.log('');
280
- if (named) {
281
- console.log(` ${named.padEnd(pad)} <- opening this`);
282
- console.log(` ${plain.padEnd(pad)} <- the same agent, if your browser cannot find that name`);
283
- } else {
284
- console.log(` ${plain}`);
285
- }
286
- console.log('\nsetup continues in the browser — Ctrl-C to stop\n');
287
- openBrowser(named || plain);
288
- }
@@ -1,161 +0,0 @@
1
- // export-collections.mjs — the account's collections as paged Turtle AS2
2
- // collections: `as:Collection` / `as:OrderedCollectionPage` documents whose
3
- // pages carry `as:items` arcs plus the activity's own triples. Produced ON
4
- // DEMAND — for a migration, or for any AS2/RDF reader — so the live pod pays
5
- // nothing to keep this shape fresh. The layout matches the one kept by
6
- // https://github.com/jg10-mastodon-social/solid-activitypub-netlify.
7
- //
8
- // Fidelity: their skeleton plus AS2-subset activity triples (type, actor,
9
- // object, published, to/cc, content, inReplyTo, attachment). Media blobs,
10
- // DMs, pins and standalone note documents have no place in that layout and
11
- // are not carried.
12
- //
13
- // Serialised by rdflib, never by hand.
14
-
15
- import * as $rdf from 'rdflib';
16
-
17
- const AS = $rdf.Namespace('https://www.w3.org/ns/activitystreams#');
18
- const RDF = $rdf.Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#');
19
- const XSD = $rdf.Namespace('http://www.w3.org/2001/XMLSchema#');
20
- const TURTLE = 'text/turtle';
21
- const PAGE_SIZE = 20;
22
-
23
- // Doc IRIs need a base even when the target is a directory; links between the
24
- // export's own documents relativise against it, so the files stay portable.
25
- export const DIR_BASE = 'https://fedipod-export.invalid/';
26
-
27
- const sym = (v) => { try { return typeof v === 'string' && /^[a-z][a-z0-9+.-]*:/i.test(v) ? $rdf.sym(v) : null; } catch { return null; } };
28
- const typeNode = (t) => (typeof t === 'string' && /^[A-Za-z]+$/.test(t) ? AS(t) : null);
29
-
30
- // The object-ish AS2-subset fields, shared by activities, embedded objects,
31
- // and bare Notes an outbox names by IRI.
32
- function addObjectFields(g, doc, s, o) {
33
- const t = typeNode(o.type);
34
- if (t) g.add(s, RDF('type'), t, doc);
35
- const by = sym(typeof o.attributedTo === 'string' ? o.attributedTo : o.attributedTo?.id);
36
- if (by) g.add(s, AS('attributedTo'), by, doc);
37
- if (o.published) g.add(s, AS('published'), $rdf.literal(o.published, XSD('dateTime')), doc);
38
- if (typeof o.content === 'string') g.add(s, AS('content'), $rdf.literal(o.content), doc);
39
- const irt = sym(typeof o.inReplyTo === 'string' ? o.inReplyTo : o.inReplyTo?.id);
40
- if (irt) g.add(s, AS('inReplyTo'), irt, doc);
41
- for (const at of [].concat(o.attachment || [])) {
42
- const au = sym(at?.url);
43
- if (!au) continue;
44
- g.add(s, AS('attachment'), au, doc);
45
- g.add(au, RDF('type'), AS('Document'), doc);
46
- if (at.mediaType) g.add(au, AS('mediaType'), $rdf.literal(at.mediaType), doc);
47
- if (at.name) g.add(au, AS('name'), $rdf.literal(at.name), doc);
48
- }
49
- }
50
-
51
- // One activity's (or bare object's) AS2-subset triples into the page document.
52
- function addActivity(g, doc, a) {
53
- const s = sym(a.id);
54
- if (!s) return false;
55
- addObjectFields(g, doc, s, a);
56
- const actor = sym(typeof a.actor === 'string' ? a.actor : a.actor?.id);
57
- if (actor) g.add(s, AS('actor'), actor, doc);
58
- for (const key of ['to', 'cc']) {
59
- for (const addr of [].concat(a[key] || [])) {
60
- const n = sym(addr);
61
- if (n) g.add(s, AS(key), n, doc);
62
- }
63
- }
64
- const o = a.object;
65
- if (typeof o === 'string') {
66
- const n = sym(o);
67
- if (n) g.add(s, AS('object'), n, doc);
68
- } else if (o && typeof o === 'object' && sym(o.id)) {
69
- const n = sym(o.id);
70
- g.add(s, AS('object'), n, doc);
71
- addObjectFields(g, doc, n, o);
72
- }
73
- return true;
74
- }
75
-
76
- // A collection into documents: a head at <name>/collection.ttl pointing
77
- // as:first at the newest page, pages at <name>/pages/<slot>.ttl chained
78
- // as:next toward the older ones — the direction their layout walks. Items:
79
- // activity objects (triples added) or bare IRIs (followers).
80
- export function collectionDocs(name, items, base) {
81
- const headUrl = `${base}${name}/collection.ttl`;
82
- const slots = [];
83
- const seen = new Set();
84
- const pages = [];
85
- for (let i = 0; i < items.length; i += PAGE_SIZE) pages.push(items.slice(i, i + PAGE_SIZE));
86
- if (!pages.length) pages.push([]);
87
- for (const page of pages) {
88
- const first = page.find(it => typeof it === 'object' && it?.published);
89
- let slot = String(first ? Date.parse(first.published) || 0 : 0);
90
- while (seen.has(slot)) slot += 'x';
91
- seen.add(slot);
92
- slots.push(slot);
93
- }
94
- const pageUrl = (i) => `${base}${name}/pages/${slots[i]}.ttl`;
95
- const docs = [];
96
-
97
- const hg = $rdf.graph();
98
- const head = $rdf.sym(headUrl);
99
- hg.add(head, RDF('type'), AS('Collection'), head);
100
- hg.add(head, AS('first'), $rdf.sym(pageUrl(0)), head);
101
- docs.push({ path: `${name}/collection.ttl`, turtle: $rdf.serialize(head, hg, headUrl, TURTLE) });
102
-
103
- let carried = 0;
104
- pages.forEach((page, i) => {
105
- const url = pageUrl(i);
106
- const g = $rdf.graph();
107
- const doc = $rdf.sym(url);
108
- g.add(doc, RDF('type'), AS('OrderedCollectionPage'), doc);
109
- if (i + 1 < pages.length) g.add(doc, AS('next'), $rdf.sym(pageUrl(i + 1)), doc);
110
- for (const item of page) {
111
- if (typeof item === 'string') {
112
- const n = sym(item);
113
- if (n) { g.add(doc, AS('items'), n, doc); carried++; }
114
- } else if (item && addActivity(g, doc, item)) {
115
- g.add(doc, AS('items'), $rdf.sym(item.id), doc);
116
- carried++;
117
- }
118
- }
119
- docs.push({ path: `${name}/pages/${slots[i]}.ttl`, turtle: $rdf.serialize(doc, g, url, TURTLE) });
120
- });
121
- return { docs, carried, pages: pages.length };
122
- }
123
-
124
- // The whole export. Inputs arrive as plain data so the CLI and the tests
125
- // assemble them the same way; `storage` is a lib/storage.mjs container.
126
- export async function exportCollections({ outboxItems = [], followers = [], inboxEntries = [], storage, base = DIR_BASE, log = console.log, resolve = null }) {
127
- const out = { written: 0 };
128
- // A published outbox may hold bare note IRIs rather than embedded
129
- // activities; with a resolver those are fetched once each so their triples
130
- // travel in the page instead of a pointer to a pod that may be retiring.
131
- if (resolve) {
132
- const resolved = [];
133
- for (const it of outboxItems) {
134
- if (typeof it !== 'string') { resolved.push(it); continue; }
135
- const doc = await resolve(it).catch(() => null);
136
- resolved.push(doc && doc.id ? doc : it);
137
- }
138
- outboxItems = resolved;
139
- }
140
- const write = async (name, items) => {
141
- const { docs, carried, pages } = collectionDocs(name, items, base);
142
- for (const d of docs) {
143
- const w = await storage.write(d.path, d.turtle, TURTLE);
144
- if (!w.ok) throw new Error(`write ${d.path}: ${w.why || 'failed'}`);
145
- out.written++;
146
- }
147
- out[name] = { items: carried, pages };
148
- };
149
-
150
- await write('outbox', outboxItems);
151
- await write('followers', followers);
152
- // Newest first, like the outbox — receivedAt rides in each archive entry.
153
- const inbox = [...inboxEntries]
154
- .sort((a, b) => String(b.receivedAt || '').localeCompare(String(a.receivedAt || '')))
155
- .map(e => { try { return { published: e.receivedAt, ...JSON.parse(e.raw) }; } catch { return null; } })
156
- .filter(Boolean);
157
- await write('inbox', inbox);
158
- if (!inbox.length) log('inbox: no archived mail yet — history begins when the archive does');
159
- log('carries what the collection layout can hold — media blobs, DMs, pins and standalone notes are not representable and were not exported');
160
- return out;
161
- }
@@ -1,58 +0,0 @@
1
- // gateway-move.mjs — the second half of a DeviceAgent moving an address from
2
- // one gateway to another (lib/device/setup.mjs does the first, when a pod
3
- // that already holds an account at another gateway is set up with an address
4
- // at this one). The browser build has the same two halves in
5
- // web/app/gateway-move.mjs; this is the Node one, which signs and delivers
6
- // itself instead of going through a relay.
7
- //
8
- // 1. The old gateway is told the address moved (POST /api/move, proved with
9
- // the pod session as attach was). From then on it serves the old actor
10
- // as a moved stub — same key, old id, `movedTo` the new one.
11
- // 2. A Move goes to every follower, FROM the old actor, signed under the
12
- // old key id: the only signature a follower's server can verify against
13
- // the old actor. Same key material; only the key id differs.
14
- //
15
- // Runs when the agent starts acting, and is safe to run again: a move left
16
- // pending (the old gateway unreachable) is tried at the next start.
17
- import { Deliverer } from '../core/deliver.mjs';
18
- import { moveActivity } from '../core/wire.mjs';
19
-
20
- export async function completeGatewayMove(agent, { makeDeliverer = (o) => new Deliverer(o) } = {}) {
21
- const cfg = agent.store.getConfig();
22
- const mv = cfg?.movedFrom;
23
- if (!mv || mv.completedAt) return null;
24
- const log = agent.log || (() => {});
25
- const newActor = agent.urls.actor;
26
-
27
- // 1. the old gateway
28
- let told;
29
- try {
30
- told = await agent.remote.session.fetch(`${mv.gateway}/api/move`, {
31
- method: 'POST', headers: { 'content-type': 'application/json' },
32
- body: JSON.stringify({ handle: mv.handle, movedTo: newActor }),
33
- });
34
- } catch (e) { told = { status: 0, statusText: e.message }; }
35
- if (told.status !== 200) {
36
- log(`gateway move: ${mv.gateway} did not mark @${mv.handle} as moved (${told.status || told.statusText}) — will retry at the next start`);
37
- return { told: false };
38
- }
39
-
40
- // 2. the Move, from the old address
41
- const contacts = agent.store.getContacts();
42
- const inboxes = [...new Set(contacts.followers.map((f) => f.sharedInbox || f.inbox).filter(Boolean))];
43
- const activity = moveActivity({ actor: mv.actor }, newActor, Date.now());
44
- const sender = makeDeliverer({
45
- store: agent.store, rsaPrivate: agent.deliverer.rsaPrivate,
46
- keyId: `${mv.actor}#main-key`, actorId: mv.actor, log, passive: true,
47
- });
48
- let sent = 0; let failed = 0;
49
- for (const inbox of inboxes) {
50
- try { await sender.deliverNow(inbox, activity); sent++; }
51
- catch (e) { failed++; log(`gateway move: Move to ${inbox} failed: ${e.message}`); }
52
- }
53
- const done = { ...mv, completedAt: new Date().toISOString(), moveSent: sent, moveFailed: failed };
54
- agent.store.setConfig({ ...agent.store.getConfig(), movedFrom: done });
55
- await agent.store.flush?.();
56
- log(`moved from ${mv.actor} to ${newActor}: Move sent to ${sent} inbox(es)${failed ? `, ${failed} failed` : ''}`);
57
- return done;
58
- }
@@ -1,161 +0,0 @@
1
- // Where an install keeps its credential, signing keys, pidfile and log.
2
- //
3
- // The root was `~/.activitypod`, then `~/.solid-activitypub`, before the
4
- // rename to fedipod. An install that already has one keeps using it: that
5
- // directory holds the credential and the private key, and moving those is the
6
- // owner's decision rather than an upgrade's side effect. `fedipod home
7
- // --to <dir>` is how you take the new name when you want it.
8
- //
9
- // Resolve ONCE and derive `profiles/` from the same answer. Deciding the two
10
- // separately is how `--profile solo` ends up looking in a different tree from
11
- // the default agent.
12
-
13
- import fs from 'node:fs';
14
- import os from 'node:os';
15
- import path from 'node:path';
16
- import { fileURLToPath } from 'node:url';
17
-
18
- export const CURRENT_ROOT = '.fedipod';
19
- export const LEGACY_ROOTS = ['.solid-activitypub', '.activitypod']; // most recent first
20
-
21
- // Existing install wins over the new name; a fresh one gets the new name.
22
- export function apRoot(homedir = os.homedir()) {
23
- const current = path.join(homedir, CURRENT_ROOT);
24
- if (fs.existsSync(current)) return current;
25
- for (const name of LEGACY_ROOTS) {
26
- const legacy = path.join(homedir, name);
27
- if (fs.existsSync(legacy)) return legacy;
28
- }
29
- return current;
30
- }
31
-
32
- export const isLegacyRoot = (root) => LEGACY_ROOTS.includes(path.basename(root));
33
-
34
- // Write one of this home's files without a window in which it is half there.
35
- //
36
- // lib/storage.mjs goes to the trouble of tmp+rename for state documents that
37
- // its own header calls rebuildable from the pod. The files here are the ones
38
- // that are NOT: keys.json is the private key remote servers have cached, and
39
- // credential.json holds a secret a Solid server mints once and will not mint
40
- // again. A plain writeFileSync truncates first, so a crash, a power loss or a
41
- // full disk between truncate and write leaves an empty or half-written file
42
- // where the identity used to be.
43
- //
44
- // rename(2) is atomic on POSIX, so a reader — or a backup running at the wrong
45
- // moment — sees either the old file or the new one. fsync before it, so the
46
- // content is on the platter and not merely in the page cache when the rename
47
- // lands. Windows has no atomic rename over an existing file; there the copy
48
- // path is still better than a truncate, and this is a best effort by design.
49
- export function writeFileAtomic(file, body, { mode = 0o600 } = {}) {
50
- const tmp = `${file}.${process.pid}.tmp`;
51
- fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
52
- const fd = fs.openSync(tmp, 'w', mode);
53
- try {
54
- fs.writeFileSync(fd, body);
55
- fs.fsyncSync(fd);
56
- } finally {
57
- fs.closeSync(fd);
58
- }
59
- fs.renameSync(tmp, file);
60
- }
61
-
62
- // The same, for the JSON these files all happen to be.
63
- export function writeJsonAtomic(file, obj, opts) {
64
- writeFileAtomic(file, JSON.stringify(obj, null, 2) + '\n', opts);
65
- }
66
-
67
- export const profilesDir = (root) => path.join(root, 'profiles');
68
-
69
- // The root an arbitrary home belongs to. `<root>/profiles/<name>` is a profile;
70
- // anything else is its own root — so a custom AP_HOME reports no neighbours,
71
- // which is the truth rather than a special case.
72
- export function rootOf(home) {
73
- const resolved = path.resolve(home);
74
- const parent = path.dirname(resolved);
75
- return path.basename(parent) === 'profiles' ? path.dirname(parent) : resolved;
76
- }
77
-
78
- // Every identity under a root — all of them under `profiles/`, none of them the
79
- // root itself. Callers read `agent.json` from these — a port and a handle.
80
- // Nothing here, and nothing that uses it, opens a sibling's credential or keys.
81
- //
82
- // The root used to BE one of these, and had no name, so this function invented
83
- // `(default)` for it at display time. That was the tell: a thing you have to
84
- // name when you show it does not have an identity, it has a position. It also
85
- // meant one identity's home contained all the others — back it up and you
86
- // backed up everyone; delete it and you deleted everyone.
87
- export function identityHomes(root) {
88
- const homes = [];
89
- try {
90
- for (const name of fs.readdirSync(profilesDir(root)).sort()) {
91
- const dir = path.join(profilesDir(root), name);
92
- if (fs.statSync(dir).isDirectory()) homes.push({ name, dir });
93
- }
94
- } catch { /* no identities yet */ }
95
- return homes;
96
- }
97
-
98
- // The root's own record. Today it holds one thing: which identity was last
99
- // started, which is what a plain command means afterwards. Nobody sets it —
100
- // using an identity IS setting it, so there is no default to configure and no
101
- // way for the configured answer to drift from the one you actually work in.
102
- export const ROOT_FILE = 'root.json';
103
-
104
- export function readRoot(root) {
105
- try { return JSON.parse(fs.readFileSync(path.join(root, ROOT_FILE), 'utf8')) || {}; }
106
- catch { return {}; }
107
- }
108
-
109
- export function writeRoot(root, fields) {
110
- fs.mkdirSync(root, { recursive: true, mode: 0o700 });
111
- const rec = { ...readRoot(root), ...fields };
112
- writeJsonAtomic(path.join(root, ROOT_FILE), rec);
113
- return rec;
114
- }
115
-
116
- // Which identity you get with no `--profile`: the last one started. Failing
117
- // that, one identity is unambiguous and needs no ceremony. Two, neither ever
118
- // started, is a genuine question — and the answer is to ask rather than pick,
119
- // because picking silently would be picking someone's fediverse account.
120
- export function defaultProfile(root) {
121
- const named = readRoot(root).default;
122
- // Only a home holding a credential counts. A setup that was abandoned leaves a
123
- // directory behind, and letting that become the default would answer "which
124
- // identity" with one that does not exist yet.
125
- const real = identityHomes(root).filter(h => fs.existsSync(path.join(h.dir, 'credential.json')));
126
- if (named && real.some(h => h.name === named)) return named;
127
- if (named) return { missing: named };
128
- return real.length === 1 ? real[0].name : null;
129
- }
130
-
131
- export const profileHome = (root, name) => path.join(profilesDir(root), name);
132
-
133
- // A root from before every identity moved under profiles/. Its presence is what
134
- // every command checks to tell you to migrate, rather than quietly doing it —
135
- // this directory holds a private key.
136
- export const rootHoldsIdentity = (root) => fs.existsSync(path.join(root, 'credential.json'));
137
-
138
-
139
- // For DISPLAY only: `~/.fedipod` reads at a glance where
140
- // `/home/jeff/.fedipod` has to be parsed, and the home directory is
141
- // the least interesting part of every path this prints. A `file:` URL is a path
142
- // wearing a scheme, so it is shown as the path — which is also what you would
143
- // type, since `state --to` takes either.
144
- //
145
- // Never used to build a path. `~` is the shell's, not the filesystem's, and
146
- // anything that resolves one must expand it first.
147
- export function tildify(p, homedir = os.homedir()) {
148
- if (!p) return p;
149
- let s = String(p);
150
- if (s.startsWith('file://')) { try { s = fileURLToPath(s); } catch { return s; } }
151
- if (s === homedir) return '~';
152
- return s.startsWith(homedir + path.sep) ? '~' + s.slice(homedir.length) : s;
153
- }
154
-
155
- // Using an identity is what makes it the default. Called when an agent starts
156
- // for one — not on every read, or `--profile other status` would quietly move
157
- // the machine's idea of "you" while only asking a question.
158
- export function recordLastUsed(root, name) {
159
- if (!root || !name || readRoot(root).default === name) return;
160
- try { writeRoot(root, { default: name, at: new Date().toISOString() }); } catch { /* not fatal */ }
161
- }