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,496 +0,0 @@
1
- // setup.mjs — the setup flow itself, lifted out of the CLI so a browser page
2
- // can drive it. Same order, same decisions as `fedipod setup` always had:
3
- // create the account and pod (or use one you already have), mint a revocable
4
- // credential, provision the pod, publish the actor, check it is really public.
5
- //
6
- // The caller owns the run record and polls it; runSetup only fills it in. That
7
- // is deliberate. The credential a CSS server mints is shown once and cannot be
8
- // recovered, so the durable record of a run has to be the credential file on
9
- // disk, never an HTTP response a closed tab can take with it.
10
-
11
- import fs from 'node:fs';
12
- import path from 'node:path';
13
- import { pathToFileURL } from 'node:url';
14
- import * as $rdf from 'rdflib';
15
-
16
- import { createAccountWithPod as realCreateAccount } from './account.mjs';
17
- import { mintCredential as realMint, RemotePod } from './remote.mjs';
18
- import { hashPassword } from '../client/masto/index.mjs';
19
- import { webfingerHost, apUrls, DEFAULT_ROOT } from '../core/wire.mjs';
20
- import { rootOf, recordLastUsed, writeJsonAtomic } from './home.mjs';
21
- import { insecureUrlReason } from '../shared/safefetch.mjs';
22
- import { resourceExists } from '../pod/root.mjs';
23
- import { CURRENT_LAYOUT, isCurrent } from './migrate.mjs';
24
- import { completeGatewayMove } from './gateway-move.mjs';
25
- import { chosenRoot, chosenRootInNewPod, publicIndexKnown, recordPlace, needsIndex } from '../core/place.mjs';
26
-
27
- const SOLID = $rdf.Namespace('http://www.w3.org/ns/solid/terms#');
28
-
29
- export const STEPS = ['account', 'credential', 'bootstrap', 'connect', 'publish', 'verify'];
30
-
31
- // Read-only pre-check on the pod behind an existing-pod setup, before a
32
- // credential is minted or the first write is attempted. Two failures it turns
33
- // from a bare "PUT … → 401" into a plain sentence:
34
- // 1. the pod host is unreachable — no account should be built on a pod that
35
- // is not there;
36
- // 2. the pod's WebID document declares no OIDC issuer. A pod verifies a token
37
- // by dereferencing its WebID and looking for solid:oidcIssuer; an empty or
38
- // issuer-less profile makes it reject every write with 401, so setup would
39
- // stall on the first one. Only judged when the document is publicly
40
- // readable — a protected one cannot be read here and is left to bootstrap.
41
- export async function checkPodUsable(pod, { webId, fetch: doFetch = globalThis.fetch } = {}) {
42
- const base = pod.endsWith('/') ? pod : pod + '/';
43
- const wid = webId || new URL('profile/card#me', base).href;
44
- const cardUrl = wid.split('#')[0];
45
-
46
- let root;
47
- try { root = await doFetch(base, { headers: { accept: 'text/turtle' } }); }
48
- catch (e) { return { ok: false, error: `${base} could not be reached (${e.message}). Check the address and that the server is running.` }; }
49
- if (root.status === 404) return { ok: false, error: `there is no pod at ${base} — the server answered 404.` };
50
- if (root.status >= 500) return { ok: false, error: `the pod host at ${base} is not responding (HTTP ${root.status}).` };
51
-
52
- let card;
53
- try { card = await doFetch(cardUrl, { headers: { accept: 'text/turtle' } }); }
54
- catch (e) { return { ok: false, error: `the pod's WebID document ${cardUrl} could not be read (${e.message}).` }; }
55
- if (card.status === 404) return { ok: false, error: `the pod has no WebID document at ${cardUrl} — the identity it needs is missing.` };
56
- if (card.status >= 500) return { ok: false, error: `the pod host is not serving ${cardUrl} (HTTP ${card.status}).` };
57
- if (card.status === 401 || card.status === 403) return { ok: true }; // cannot read unauthenticated; leave it to bootstrap
58
-
59
- const body = await card.text().catch(() => '');
60
- const g = $rdf.graph();
61
- try { $rdf.parse(body, g, cardUrl, (card.headers.get('content-type') || 'text/turtle').split(';')[0].trim()); }
62
- catch { return { ok: false, error: `the pod's WebID document ${cardUrl} could not be parsed as RDF.` }; }
63
- if (!g.each($rdf.sym(wid), SOLID('oidcIssuer'), null).length) {
64
- return { ok: false, error: `the pod's WebID document ${cardUrl} declares no OIDC issuer, so the pod will reject every write. It looks empty or incomplete — restore it, or set up with a fresh pod.` };
65
- }
66
- return { ok: true };
67
- }
68
-
69
- export const credentialPath = (home) => path.join(home, 'credential.json');
70
- export const hasCredential = (home) => fs.existsSync(credentialPath(home));
71
-
72
- export function newRun() {
73
- return {
74
- phase: 'running',
75
- startedAt: new Date().toISOString(),
76
- steps: STEPS.map(key => ({ key, state: 'waiting', note: null })),
77
- error: null,
78
- result: null,
79
- };
80
- }
81
-
82
- // What must be answered before a run can start. `resuming` is a run that
83
- // already has its credential: the account and the pod are settled, and only
84
- // the actor's own details are still open.
85
- export function setupInputError(a, resuming = false) {
86
- if (!a.handle) return 'a handle is required';
87
- if (a.kind && a.kind !== 'person' && a.kind !== 'group') return 'kind must be person or group';
88
- if (a.privateRoot) {
89
- try { new URL(a.privateRoot); } catch { return `"${a.privateRoot}" is not a container address`; }
90
- // A pod one, at least. A file: private root is a directory and has no
91
- // transport to secure.
92
- if (/^https?:/i.test(a.privateRoot)) {
93
- const bad = insecureUrlReason(a.privateRoot, 'private-data address');
94
- if (bad) return bad;
95
- }
96
- }
97
- if (a.gateway) {
98
- if (typeof a.gateway.url !== 'string') return 'a gateway needs its door URL';
99
- const badGw = insecureUrlReason(a.gateway.url, 'gateway address');
100
- if (badGw) return badGw;
101
- }
102
- if (a.shape && a.shape !== 'pod' && a.shape !== 'front') return 'shape must be "pod" or "front"';
103
- if (a.gatewayOrigin) {
104
- const badO = insecureUrlReason(a.gatewayOrigin, 'gateway address');
105
- if (badO) return badO;
106
- }
107
- if (resuming) return null;
108
- if (a.mode !== 'new' && a.mode !== 'existing') return 'mode must be "new" or "existing"';
109
- if (!a.issuer) return 'an identity provider is required';
110
- // Checked BEFORE the password is asked for, let alone sent: the issuer is
111
- // where it goes, and the pod is where the credential it buys is used.
112
- const badIssuer = insecureUrlReason(a.issuer, 'identity provider address');
113
- if (badIssuer) return badIssuer;
114
- if (!a.email) return 'an account email is required';
115
- if (!a.password) return 'the account password is required';
116
- if (a.mode === 'existing' && !a.pod) return 'a pod address is required';
117
- const badPod = insecureUrlReason(a.pod, 'pod address');
118
- if (badPod) return badPod;
119
- return null;
120
- }
121
-
122
- // Where an identity's address lives. A pod on a suffix-based host cannot
123
- // answer WebFinger for a handle, so its address must live at the Gateway
124
- // whatever was asked; a pod at its own host root takes the shape chosen.
125
- export function frontedAddress({ pod, shape }) {
126
- const pathPod = pod ? !webfingerHost(pod) : false;
127
- return pathPod || shape === 'front';
128
- }
129
-
130
- // The account a pod already holds, read as its owner: the config and the key
131
- // record in its state container. Both null when there is none, or when the
132
- // credential is not the owner's. Injected for tests.
133
- export async function readPodAccount({ home, credential, pod, root, log = () => {} }) {
134
- const remote = new RemotePod(credential, { home, log });
135
- await remote.warmup?.();
136
- const urls = apUrls(pod, root || DEFAULT_ROOT);
137
- const config = await remote.getJson(urls.state + 'config.json').catch(() => null);
138
- const keys = await remote.getJson(urls.state + 'keys.json').catch(() => null);
139
- return { config, keys };
140
- }
141
-
142
- // Take an address at a Gateway: attach the pod to it, fronted, and return the
143
- // gateway config bootstrap writes and connect reads. The pod session proves
144
- // the pod — no password reaches the Gateway. Injected for tests.
145
- export async function takeGatewayAddress({ home, credential, gatewayOrigin, handle, podHome, actorUrl, kind, log = () => {} }) {
146
- const remote = new RemotePod(credential, { home, log });
147
- await remote.warmup?.();
148
- const origin = String(gatewayOrigin).replace(/\/$/, '');
149
- const res = await remote.session.fetch(`${origin}/api/attach`, {
150
- method: 'POST', headers: { 'content-type': 'application/json' },
151
- body: JSON.stringify({ handle, podHome, actorUrl, kind: kind === 'group' ? 'group' : 'person', fronted: true }),
152
- });
153
- const d = await res.json().catch(() => ({}));
154
- if (res.status !== 201 || !d.hmacSecret) {
155
- throw new Error(`could not take a gateway address at ${new URL(origin).host} (HTTP ${res.status})${d.error ? ': ' + d.error : ''}`);
156
- }
157
- return {
158
- url: `${origin}/u/${handle}/ap/inbox/`,
159
- frontActor: String(d.frontActor || `${origin}/u/${handle}/ap/actor`),
160
- hmacSecret: String(d.hmacSecret), mode: 'trust',
161
- };
162
- }
163
-
164
- // What the CLI printed before asking "create pod and fediverse account?"
165
- // (bin/fedipod.mjs, the address preview) — as data, so the page can show
166
- // the same warnings. Pure: no network, so it can answer while you type.
167
- export function preflight({ mode, pod, issuer, podName, handle, kind, shape = 'pod', gatewayOrigin = 'https://fedipod.net' }) {
168
- const warnings = [];
169
- if (!handle) return { ok: false, error: 'a handle is required' };
170
- let issuerHost;
171
- try { issuerHost = new URL(issuer || 'https://solidcommunity.net').host; }
172
- catch { return { ok: false, error: `"${issuer}" is not a URL` }; }
173
-
174
- let gwHost; try { gwHost = new URL(gatewayOrigin).host; } catch { gwHost = 'fedipod.net'; }
175
-
176
- if (mode === 'new') {
177
- // Whether the provider puts the pod on its own subdomain or on a path is
178
- // the provider's call, learned only once the pod is made. If the address
179
- // was asked to live at the Gateway, it does. Otherwise the pod's own host
180
- // is the address, and the run moves it to the Gateway if the provider
181
- // turned out to use paths.
182
- if (shape === 'front') {
183
- if (kind === 'group') return { ok: false, mode, handle, kind, error: 'group-needs-host-root', refusal: 'group-needs-host-root', warnings };
184
- return { ok: true, mode, handle, kind, fronted: true, forced: false, gatewayHost: gwHost, shape: 'front',
185
- address: `@${handle}@${gwHost}`, webfingerHost: null, resolvable: true, warnings, refusal: null };
186
- }
187
- return {
188
- ok: true, mode, handle, kind, fronted: false, shape: 'pod',
189
- address: `@${handle}@${podName || handle}.${issuerHost}`,
190
- webfingerHost: null, resolvable: null, warnings, refusal: null,
191
- };
192
- }
193
-
194
- let podUrl;
195
- try { podUrl = new URL(pod); }
196
- catch { return { ok: false, error: `"${pod}" is not a pod address` }; }
197
- // A handle resolves through <host>/.well-known/webfinger, so it only works
198
- // when the pod owns the root of its host. A pod that does not can still be
199
- // an account, with its address at the Gateway.
200
- const wfHost = webfingerHost(podUrl.href);
201
- const fronted = !wfHost || shape === 'front';
202
- if (fronted) {
203
- // A person's address moves to the Gateway; a group cannot, yet — a group
204
- // needs a pod at its own host until fronted groups are proven.
205
- if (kind === 'group') {
206
- return { ok: false, mode: 'existing', handle, kind, refusal: 'group-needs-host-root', warnings,
207
- address: `@${handle}@${podUrl.host}`, webfingerHost: null, resolvable: false };
208
- }
209
- return {
210
- ok: true, mode: 'existing', handle, kind, fronted: true, forced: !wfHost, gatewayHost: gwHost, shape: 'front',
211
- address: `@${handle}@${gwHost}`, webfingerHost: null, resolvable: true, warnings, refusal: null,
212
- };
213
- }
214
- return {
215
- ok: true, mode: 'existing', handle, kind, fronted: false, shape: 'pod',
216
- address: `@${handle}@${wfHost}`,
217
- webfingerHost: wfHost, resolvable: true, warnings, refusal: null,
218
- };
219
- }
220
-
221
- // Fills `run` in as it goes. Never throws: a failure lands in run.error, so a
222
- // page that polls sees it. `deps` is for tests — the real functions otherwise.
223
- export async function runSetup({ home, agent, answers, run, deps = {}, log = () => {} }) {
224
- const createAccount = deps.createAccountWithPod || realCreateAccount;
225
- const mint = deps.mintCredential || realMint;
226
- const checkPod = deps.checkPodUsable || checkPodUsable;
227
- const attachGateway = deps.attachGateway || takeGatewayAddress;
228
-
229
- const at = (key) => run.steps.find(s => s.key === key);
230
- const begin = (key) => { at(key).state = 'running'; };
231
- const done = (key, note = null) => { at(key).state = 'ok'; at(key).note = note; };
232
- const skip = (key, note = null) => { at(key).state = 'skipped'; at(key).note = note; };
233
-
234
- const {
235
- mode, issuer, email, password, handle, name, podName,
236
- kind = 'person', approveJoins = false, summary, icon, keys, uiPassword,
237
- gateway = null, shape = 'pod', gatewayOrigin = 'https://fedipod.net',
238
- // The container that holds `fedipod/` (blank: the pod's root), and the
239
- // person's yes to a new public type index when their profile names none.
240
- container = '', createIndex = false,
241
- } = answers;
242
- let { pod, root } = answers;
243
- const rootGiven = !!root;
244
- if (!root) root = 'fedipod/'; // until the pod is known; a resuming run
245
- // overwrites this with the credential's own root below.
246
- let accountWebId = null; // what createAccountWithPod reported, when it ran
247
- // The private half always starts here, beside the credential and the keys —
248
- // not on the pod. Every activity you receive would otherwise cost the pod
249
- // several writes, and that pod is a server somebody runs. `state --to` moves
250
- // it afterwards; starting on the pod and moving later is strictly worse,
251
- // because the copy left behind was on the pod the whole time.
252
- let privateRoot = answers.privateRoot
253
- || pathToFileURL(path.join(home, 'private')).href + '/';
254
- // A pod that already holds an account at ANOTHER gateway, set up with an
255
- // address at this one: not a second account but the same one moving in.
256
- // Its state and key are on the pod, and stay there.
257
- let movingIn = false;
258
- let movedFrom = null;
259
- // Everything that leaves this function — notes, errors, the log — goes
260
- // through here. Nothing today echoes a password back, but /setup/progress is
261
- // polled repeatedly and would re-serve one forever if anything ever did.
262
- const scrub = (s) => (password ? String(s).split(password).join('••••••') : String(s));
263
-
264
- const credPath = credentialPath(home);
265
- const resuming = fs.existsSync(credPath);
266
-
267
- try {
268
- // --- account: create it, or use the pod you already have ---
269
- if (resuming) {
270
- skip('account', 'the credential is already on disk');
271
- } else if (mode === 'new') {
272
- begin('account');
273
- // A new pod has no public type index: without a yes to making one,
274
- // nothing is created at all.
275
- if (!createIndex) throw needsIndex('A new pod has no public type index.');
276
- const made = await createAccount({ issuer, email, password, podName: podName || handle });
277
- pod = made.pod;
278
- accountWebId = made.webId || null;
279
- log(`account + pod created: ${pod}`);
280
- // The server put the pod on a path rather than its own subdomain, so
281
- // nobody could ever find this group. A person was warned before we got
282
- // here and chose to continue; a group cannot.
283
- if (kind === 'group' && !webfingerHost(pod)) {
284
- throw new Error(`${issuer} created the pod at ${pod} — a suffixed pod. `
285
- + 'WebFinger is only answered for a subdomained pod, so nobody '
286
- + 'could find this group. The pod exists; no actor was published.');
287
- }
288
- if (!rootGiven) {
289
- const place = chosenRootInNewPod(pod.endsWith('/') ? pod : pod + '/', container);
290
- if (place.problem) throw new Error(`Where to store it: ${place.problem}.`);
291
- root = place.root;
292
- }
293
- done('account', pod);
294
- } else {
295
- // A pod you bring must be there and carry a usable WebID before a
296
- // credential is minted against it — no account on a pod that is not
297
- // reachable, and no silent 401 later on a pod whose profile is empty.
298
- const usable = await checkPod(pod);
299
- if (!usable.ok) throw new Error(usable.error);
300
- const podBase = pod.endsWith('/') ? pod : pod + '/';
301
- if (!rootGiven) {
302
- const place = chosenRoot(podBase, container);
303
- if (place.problem) throw new Error(`Where to store it: ${place.problem}.`);
304
- root = place.root;
305
- }
306
- // An account at the chosen place, or an older one where accounts used to go.
307
- const exists = (r) => (deps.resourceExists || resourceExists)(deps.fetch || fetch, apUrls(pod, r).actor);
308
- const held = await exists(root) || (root !== DEFAULT_ROOT && await exists(DEFAULT_ROOT));
309
- if (held && !frontedAddress({ pod, shape })) {
310
- throw new Error('The pod already hosts a FediPod account. If you want a second account, put it on a different pod. '
311
- + 'To move an account whose address is at another gateway to this one, ask for an address at this gateway.');
312
- }
313
- if (held && kind === 'group') throw new Error('The pod already hosts a FediPod account, and a group cannot move between gateways.');
314
- movingIn = held;
315
- if (movingIn) { privateRoot = null; }
316
- // Asked before anything is minted: a profile with no public type index
317
- // gets one only on its person's yes.
318
- if (!movingIn && !createIndex
319
- && await (deps.publicIndexKnown || publicIndexKnown)(deps.fetch || fetch, podBase) !== true) {
320
- throw needsIndex('Your profile names no public type index.');
321
- }
322
- skip('account', movingIn ? 'the pod already holds the account — its address moves here' : 'using the pod you already have');
323
- }
324
-
325
- // --- credential: the point of no return, and the durability boundary ---
326
- let resumeWebId = null;
327
- if (resuming) {
328
- const rec = JSON.parse(fs.readFileSync(credPath, 'utf8'));
329
- pod = rec.remotePod;
330
- root = rec.root;
331
- resumeWebId = rec.webId || null;
332
- skip('credential', `already minted — ${credPath}`);
333
- } else {
334
- begin('credential');
335
- // The WebID matters as much as the pod: an account with more than one
336
- // pod has more than one, and a credential bound to the wrong one 403s
337
- // every write. Account creation knows which; otherwise the pod's origin
338
- // picks it out.
339
- const credential = await mint({
340
- origin: issuer, email, password, name: 'fedipod',
341
- webId: accountWebId || undefined, podUrl: pod,
342
- });
343
- const rec = {
344
- ...credential,
345
- remotePod: pod.endsWith('/') ? pod : pod + '/',
346
- createdAt: new Date().toISOString(),
347
- ...(root ? { root } : {}),
348
- ...(keys === 'pod' || movingIn ? { keysMode: 'pod' } : {}),
349
- // Where the private half lives. Per-machine, like keysMode. A move-in
350
- // keeps it on the pod, where the account already is, and says so.
351
- ...(privateRoot ? { privateRoot } : {}),
352
- ...(movingIn ? { stateOnPod: true } : {}),
353
- // What shape this install is, so `upgrade` can tell an old one from a
354
- // new one without guessing from the fields.
355
- ...(isCurrent({ privateRoot, stateOnPod: movingIn }) ? { layout: CURRENT_LAYOUT } : {}),
356
- };
357
- fs.mkdirSync(home, { recursive: true, mode: 0o700 });
358
- writeJsonAtomic(credPath, rec);
359
- // The identity you just made is the one you are using, so it becomes what
360
- // a plain command means. Here rather than earlier: the credential landing
361
- // is what makes this an identity at all.
362
- // NOT `root` — that name is already taken by the answers' AP container
363
- // root, destructured above, and shadowing it is a temporal dead zone.
364
- const apHomeRoot = rootOf(home);
365
- if (apHomeRoot !== home) recordLastUsed(apHomeRoot, path.basename(home));
366
- pod = rec.remotePod;
367
- log(`credential minted and saved to ${credPath}`);
368
- done('credential', credPath);
369
- }
370
-
371
- // --- a move-in: the account on the pod, read with the credential just
372
- // minted, has to be one whose address lives at another gateway ---
373
- if (movingIn) {
374
- const cred = JSON.parse(fs.readFileSync(credPath, 'utf8'));
375
- const account = await (deps.readPodAccount || readPodAccount)({ home, credential: cred, pod, root: root || DEFAULT_ROOT, log });
376
- if (!account?.config) throw new Error('the pod holds an account, but its record could not be read with this credential — is this account the pod\'s owner?');
377
- const frontActor = account.config.gateway?.frontActor || null;
378
- const gwHost = new URL(gatewayOrigin).host;
379
- if (!frontActor) throw new Error('The pod already hosts a FediPod account whose address lives on the pod: nothing to move. Sign in to it instead.');
380
- if (new URL(frontActor).host === gwHost) throw new Error(`The pod already hosts a FediPod account at ${gwHost}: sign in to it instead of setting up again.`);
381
- if ((account.config.kind || 'person') === 'group') throw new Error('a group cannot move between gateways');
382
- if (!account.keys?.rsa || account.keys.ct) {
383
- throw new Error(`this account's key is still under a password from an earlier version — sign in once at ${new URL(frontActor).host} first, then set up here`);
384
- }
385
- movedFrom = { actor: frontActor, gateway: new URL(frontActor).origin, handle: account.config.handle, at: new Date().toISOString() };
386
- log(`moving @${account.config.handle}@${new URL(frontActor).host} here, as @${handle}@${gwHost}`);
387
- }
388
-
389
- // --- take an address at the Gateway, if this pod needs one or asked for
390
- // one --- before bootstrap, so the config it writes carries the Gateway
391
- // ids and the key connect mints below is stamped to the Gateway actor from
392
- // the start. A signup-arranged gateway (the installer carry-over) wins.
393
- let gatewayCfg = gateway;
394
- if (!gatewayCfg && frontedAddress({ pod, shape })) {
395
- if (kind === 'group') {
396
- throw new Error(`a group needs a subdomained pod — a Gateway address for a group is not supported yet`
397
- + (webfingerHost(pod) ? '' : `; ${pod} is suffixed`) + '.');
398
- }
399
- const urls = apUrls(pod, root || DEFAULT_ROOT);
400
- const cred = JSON.parse(fs.readFileSync(credPath, 'utf8'));
401
- log(`taking a gateway address at ${new URL(gatewayOrigin).host}`);
402
- gatewayCfg = await attachGateway({
403
- home, credential: cred, gatewayOrigin, handle,
404
- podHome: urls.home, actorUrl: urls.actor, kind, log,
405
- });
406
- log(`gateway address @${handle}@${new URL(gatewayOrigin).host}`);
407
- }
408
-
409
- // --- provision the pod and bring federation up ---
410
- begin('bootstrap');
411
- // Resuming skipped the checks the fresh paths ran, and the credential it
412
- // carries may be the one bound to a pod whose profile is empty — the write
413
- // below would 401. Catch it here, as this step, with a sentence.
414
- if (resuming) {
415
- const ready = await checkPod(pod, { webId: resumeWebId || undefined });
416
- if (!ready.ok) throw new Error(ready.error);
417
- }
418
- await agent.bootstrap({ handle, name: name || handle, root, kind, approveJoins, summary, icon, gateway: gatewayCfg });
419
- if (movingIn && movedFrom) {
420
- // The old actor becomes an alias, which is what a server checks on the
421
- // new actor before it honours a Move; the Move itself is pending until
422
- // the new actor is published (completeGatewayMove, below and at every
423
- // start). The key stays; its stamp follows the actor.
424
- const cfg = agent.store.getConfig() || {};
425
- agent.store.setConfig({ ...cfg, aliases: [...new Set([...(cfg.aliases || []), movedFrom.actor])], movedFrom });
426
- const keyRec = agent.store.read?.('keys.json', null);
427
- if (keyRec?.mintedFor && gatewayCfg?.frontActor) agent.store.write?.('keys.json', { ...keyRec, mintedFor: gatewayCfg.frontActor });
428
- await agent.store.flush();
429
- }
430
- done('bootstrap');
431
-
432
- begin('connect');
433
- // Direct, not connectWithRetry: setup wants to hear about a failure now,
434
- // not back off for an hour with a browser tab waiting on it.
435
- await agent.connect({ repair: false }); // publish below is the publish
436
- done('connect');
437
-
438
- begin('publish');
439
- if (uiPassword) {
440
- agent.store.setConfig({ ...agent.store.getConfig(), uiPassword: hashPassword(uiPassword) });
441
- }
442
- const published = await agent.publisher.publishProfile();
443
- await agent.store.flush();
444
- // Where the account lives, in the owner's public type index — made first
445
- // if they said yes to one.
446
- if (!movingIn) {
447
- const urlsAt = apUrls(pod, root);
448
- try {
449
- await (deps.recordPlace || recordPlace)(agent.publisher?.remote || agent.remote, urlsAt.base, urlsAt.home + 'ap/actor', { create: !!createIndex });
450
- } catch (e) {
451
- throw new Error(`could not record where the account lives in your type index (${e.message})`);
452
- }
453
- }
454
- if (movingIn) {
455
- // Tell the old gateway and the followers. Not fatal: left pending, it
456
- // is tried again when the agent next starts acting.
457
- const moved = await (deps.completeGatewayMove || completeGatewayMove)(agent).catch((e) => { log(`gateway move: ${e.message}`); return null; });
458
- if (moved?.completedAt) log(`Move sent from ${movedFrom.actor} to ${moved.moveSent} inbox(es)`);
459
- }
460
- done('publish');
461
-
462
- // --- and say plainly whether the world can actually see it ---
463
- begin('verify');
464
- const unreachable = published?.unreachable || [];
465
- const wfHost = webfingerHost(pod);
466
- done('verify', unreachable.length
467
- ? `not readable without credentials: ${unreachable.join(', ')}`
468
- : 'the public surface is reachable');
469
-
470
- // A fronted identity resolves at the Gateway, not the pod host.
471
- const frontActor = gatewayCfg?.frontActor || agent.store.getConfig()?.gateway?.frontActor || null;
472
- const gwHost = frontActor ? new URL(frontActor).host : null;
473
- run.result = {
474
- kind,
475
- pod,
476
- handle,
477
- actor: agent.urls?.actor || null,
478
- fronted: !!frontActor,
479
- webfingerHost: gwHost || wfHost,
480
- resolvable: !!(gwHost || wfHost),
481
- address: gwHost ? `@${handle}@${gwHost}` : (wfHost ? `@${handle}@${wfHost}` : null),
482
- unreachable,
483
- };
484
- run.phase = 'done';
485
- log(wfHost
486
- ? `${kind === 'group' ? 'group' : 'actor'} published: @${handle}@${wfHost}`
487
- : `${kind === 'group' ? 'group' : 'actor'} published, but not reachable as a handle — `
488
- + `${pod} is a suffixed pod`);
489
- } catch (e) {
490
- for (const s of run.steps) if (s.state === 'running') s.state = 'error';
491
- run.error = scrub(e.message);
492
- run.phase = 'error';
493
- log(`setup failed: ${run.error}`);
494
- }
495
- return run;
496
- }
@@ -1,96 +0,0 @@
1
- // update.mjs — is a newer FediPod published, and the update itself.
2
- //
3
- // "Latest" is the version field of package.json on the repo's main branch —
4
- // the same file a clone reads to know what it is running. The check is one
5
- // GET of that file; nothing else leaves the machine, and AP_UPDATE_CHECK=0
6
- // turns it off. The update is what re-running the installer does: fast-forward
7
- // the checkout, reinstall dependencies, restart the agents.
8
-
9
- import fs from 'node:fs';
10
- import path from 'node:path';
11
- import { execFileSync, spawn } from 'node:child_process';
12
- import { fileURLToPath } from 'node:url';
13
-
14
- export const LATEST_URL = 'https://raw.githubusercontent.com/jeff-zucker/FediPod/main/package.json';
15
-
16
- export const repoRoot = () => path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
17
-
18
- export const localVersion = (root = repoRoot()) => {
19
- try { return JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')).version || null; }
20
- catch { return null; }
21
- };
22
-
23
- // a newer than b, for dotted numeric versions.
24
- export const newerThan = (a, b) => {
25
- const pa = String(a).split('.').map(Number);
26
- const pb = String(b).split('.').map(Number);
27
- for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
28
- const d = (pa[i] || 0) - (pb[i] || 0);
29
- if (d) return d > 0;
30
- }
31
- return false;
32
- };
33
-
34
- export async function checkLatest({ current = localVersion(), fetchImpl = fetch } = {}) {
35
- if (process.env.AP_UPDATE_CHECK === '0') return null;
36
- try {
37
- const res = await fetchImpl(LATEST_URL, { signal: AbortSignal.timeout(10_000) });
38
- if (!res.ok) return null;
39
- const latest = (await res.json()).version || null;
40
- if (!latest || !current) return null;
41
- return { current, latest, available: newerThan(latest, current), checkedAt: new Date().toISOString() };
42
- } catch { return null; }
43
- }
44
-
45
- // The npm half, injectable — a test asking what runUpdate DOES must never be
46
- // able to install software on the machine running it.
47
- const npmInstallLatest = () =>
48
- execFileSync('npm', ['install', '-g', 'fedipod@latest'], { stdio: 'pipe' });
49
-
50
- // Fast-forward only: a checkout with local changes is somebody's work, and an
51
- // update must refuse rather than eat it.
52
- export function runUpdate({ root = repoRoot(), log = () => {}, install = npmInstallLatest } = {}) {
53
- // The ordinary install comes from npm, where updating is npm's job and the
54
- // files under us are not ours to move. A checkout is somebody working on it,
55
- // and gets the fast-forward below.
56
- if (!fs.existsSync(path.join(root, '.git'))) {
57
- try {
58
- log('updating from npm…');
59
- install();
60
- return { ok: true, note: 'updated from npm — restart the agent to serve it' };
61
- } catch (e) {
62
- return { ok: false,
63
- note: `npm install -g fedipod@latest failed: ${String(e.stderr || e.message).slice(0, 300).trim()}` };
64
- }
65
- }
66
- try {
67
- execFileSync('git', ['-C', root, 'pull', '--ff-only'], { stdio: 'pipe' });
68
- } catch (e) {
69
- return { ok: false, note: `git pull refused: ${String(e.stderr || e.message).slice(0, 300).trim()}` };
70
- }
71
- try {
72
- execFileSync('npm', ['install', '--omit=dev', '--no-audit', '--no-fund'], { cwd: root, stdio: 'pipe' });
73
- } catch (e) {
74
- return { ok: false, note: `npm install failed: ${String(e.stderr || e.message).slice(0, 300).trim()}` };
75
- }
76
- const version = localVersion(root);
77
- log(`updated the checkout to ${version}`);
78
- return { ok: true, note: `updated to ${version}`, version };
79
- }
80
-
81
- // New code runs only after a restart. Where systemd units exist they are all
82
- // restarted by name; otherwise the caller re-execs its own process.
83
- export function restartAgents({ log = () => {} } = {}) {
84
- try {
85
- const list = execFileSync('systemctl',
86
- ['--user', 'list-units', '--plain', '--no-legend', 'fedipod-*'], { stdio: 'pipe' })
87
- .toString().trim();
88
- if (list) {
89
- const child = spawn('systemctl', ['--user', 'restart', 'fedipod-*'], { detached: true, stdio: 'ignore' });
90
- child.unref();
91
- log('restarting the fedipod units');
92
- return 'units';
93
- }
94
- } catch { /* no systemd here */ }
95
- return 'self';
96
- }
@@ -1,36 +0,0 @@
1
- // caches.mjs — what one warm gateway process keeps between requests: the
2
- // pod-token verifier, and the public keys of the servers that deliver here.
3
- // Built per request, each costs round trips to somebody else's server for
4
- // every call; built once, a process pays them once.
5
-
6
- // The Solid-OIDC verifier remembers the issuers' key sets it has seen. A
7
- // fresh one per call re-read the caller's WebID document, the issuer's
8
- // discovery document and its keys on every signed-in call.
9
- let verifier = null;
10
- export async function podTokenVerifier() {
11
- if (!verifier) verifier = (await import('@solid/access-token-verifier')).createSolidTokenVerifier();
12
- return verifier;
13
- }
14
-
15
- // The keys deliveries are signed with, by key id, in the shape Fedify's
16
- // verifier asks for. A key is held an hour; a key that could not be fetched
17
- // is held five minutes, so a server that was down is asked again soon.
18
- // Fedify re-fetches on its own when a held key no longer verifies, so a
19
- // rotated key costs one failed check, not an hour of refused mail.
20
- const KEY_TTL_MS = 60 * 60_000;
21
- const MISS_TTL_MS = 5 * 60_000;
22
- const KEY_CACHE_MAX = 500;
23
- const keys = new Map(); // key id → { key, until }
24
- export const senderKeys = {
25
- async get(keyId) {
26
- const hit = keys.get(keyId.href);
27
- if (!hit) return undefined;
28
- if (hit.until < Date.now()) { keys.delete(keyId.href); return undefined; }
29
- return hit.key;
30
- },
31
- async set(keyId, key) {
32
- if (keys.size >= KEY_CACHE_MAX) keys.delete(keys.keys().next().value);
33
- keys.set(keyId.href, { key, until: Date.now() + (key ? KEY_TTL_MS : MISS_TTL_MS) });
34
- },
35
- size: () => keys.size,
36
- };