fedipod-server 0.29.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (440) hide show
  1. package/README.md +11 -6
  2. package/dist/door.d.ts +4 -0
  3. package/dist/door.js +31 -0
  4. package/dist/fedipod.d.ts +16 -0
  5. package/dist/fedipod.js +13 -0
  6. package/dist/front.d.ts +3 -0
  7. package/dist/front.js +94 -0
  8. package/dist/handler.d.ts +36 -101
  9. package/dist/handler.js +85 -645
  10. package/dist/handler.jsonld +2 -30
  11. package/dist/identities.d.ts +62 -0
  12. package/dist/identities.js +236 -0
  13. package/dist/mounts.d.ts +43 -0
  14. package/dist/mounts.js +123 -0
  15. package/dist/opt-in.d.ts +46 -0
  16. package/dist/opt-in.js +176 -0
  17. package/package.json +10 -18
  18. package/lib/client/c2s.mjs +0 -636
  19. package/lib/client/localapi.mjs +0 -87
  20. package/lib/client/masto/accounts.mjs +0 -310
  21. package/lib/client/masto/body.mjs +0 -156
  22. package/lib/client/masto/index.mjs +0 -206
  23. package/lib/client/masto/instance.mjs +0 -112
  24. package/lib/client/masto/media.mjs +0 -79
  25. package/lib/client/masto/oauth.mjs +0 -656
  26. package/lib/client/masto/render.mjs +0 -518
  27. package/lib/client/masto/statuses.mjs +0 -372
  28. package/lib/client/masto/timelines.mjs +0 -438
  29. package/lib/client/oidc-auth.mjs +0 -62
  30. package/lib/client/streaming.mjs +0 -154
  31. package/lib/client/webpush.mjs +0 -98
  32. package/lib/connections/acctfeed.mjs +0 -257
  33. package/lib/connections/atproto.mjs +0 -309
  34. package/lib/connections/bskyfeed.mjs +0 -243
  35. package/lib/connections/bskygroup.mjs +0 -162
  36. package/lib/connections/fediacct.mjs +0 -253
  37. package/lib/connections/import.mjs +0 -357
  38. package/lib/connections/tagfeed.mjs +0 -212
  39. package/lib/connections/vault.mjs +0 -114
  40. package/lib/core/as2.mjs +0 -206
  41. package/lib/core/contexts/activitystreams.json +0 -379
  42. package/lib/core/contexts/anno.json +0 -126
  43. package/lib/core/contexts/did-v1.json +0 -57
  44. package/lib/core/contexts/fep-5711.json +0 -36
  45. package/lib/core/contexts/gotosocial.json +0 -86
  46. package/lib/core/contexts/identity-v1.json +0 -152
  47. package/lib/core/contexts/index.mjs +0 -63
  48. package/lib/core/contexts/join-lemmy.json +0 -33
  49. package/lib/core/contexts/joinmastodon.json +0 -28
  50. package/lib/core/contexts/litepub-0.1.json +0 -60
  51. package/lib/core/contexts/map.json +0 -19
  52. package/lib/core/contexts/miscellany.json +0 -19
  53. package/lib/core/contexts/quotes.json +0 -18
  54. package/lib/core/contexts/schemaorg.json +0 -8845
  55. package/lib/core/contexts/security-data-integrity-v1.json +0 -78
  56. package/lib/core/contexts/security-data-integrity-v2.json +0 -81
  57. package/lib/core/contexts/security-multikey-v1.json +0 -35
  58. package/lib/core/contexts/security-v1.json +0 -74
  59. package/lib/core/contexts/webfinger.json +0 -10
  60. package/lib/core/deliver.mjs +0 -387
  61. package/lib/core/graphview.mjs +0 -327
  62. package/lib/core/intake/activities.mjs +0 -649
  63. package/lib/core/intake/activity.mjs +0 -318
  64. package/lib/core/intake/channel.mjs +0 -144
  65. package/lib/core/intake/group.mjs +0 -258
  66. package/lib/core/intake/index.mjs +0 -732
  67. package/lib/core/intake/notes.mjs +0 -367
  68. package/lib/core/intake/verify.mjs +0 -142
  69. package/lib/core/keys.mjs +0 -153
  70. package/lib/core/lease.mjs +0 -206
  71. package/lib/core/place.mjs +0 -82
  72. package/lib/core/polls.mjs +0 -105
  73. package/lib/core/profile-page.mjs +0 -104
  74. package/lib/core/proof.mjs +0 -79
  75. package/lib/core/publisher/collections.mjs +0 -272
  76. package/lib/core/publisher/index.mjs +0 -522
  77. package/lib/core/publisher/notes.mjs +0 -519
  78. package/lib/core/publisher/own.mjs +0 -143
  79. package/lib/core/publisher/questions.mjs +0 -241
  80. package/lib/core/publisher/restore.mjs +0 -224
  81. package/lib/core/shapes/activitystreams.ttl +0 -157
  82. package/lib/core/shapes/index.mjs +0 -132
  83. package/lib/core/shapes/shapes-text.mjs +0 -13
  84. package/lib/core/social.mjs +0 -561
  85. package/lib/core/storage.mjs +0 -176
  86. package/lib/core/store.mjs +0 -578
  87. package/lib/core/wire-quotes.mjs +0 -71
  88. package/lib/core/wire.mjs +0 -925
  89. package/lib/device/account.mjs +0 -87
  90. package/lib/device/admin/index.mjs +0 -13
  91. package/lib/device/admin/origins.mjs +0 -35
  92. package/lib/device/admin/routes/connections.mjs +0 -144
  93. package/lib/device/admin/routes/gateway.mjs +0 -199
  94. package/lib/device/admin/routes/lifecycle.mjs +0 -200
  95. package/lib/device/admin/routes/owner.mjs +0 -322
  96. package/lib/device/admin/routes/setup.mjs +0 -428
  97. package/lib/device/admin/routes/social.mjs +0 -188
  98. package/lib/device/admin/server.mjs +0 -95
  99. package/lib/device/admin/static.mjs +0 -247
  100. package/lib/device/admin/surface.mjs +0 -315
  101. package/lib/device/certs.mjs +0 -281
  102. package/lib/device/cli/commands/account.mjs +0 -586
  103. package/lib/device/cli/commands/run.mjs +0 -278
  104. package/lib/device/cli/commands/service.mjs +0 -221
  105. package/lib/device/cli/commands/setup.mjs +0 -489
  106. package/lib/device/cli/commands/state.mjs +0 -561
  107. package/lib/device/cli/context.mjs +0 -288
  108. package/lib/device/export-collections.mjs +0 -161
  109. package/lib/device/gateway-move.mjs +0 -58
  110. package/lib/device/home.mjs +0 -161
  111. package/lib/device/migrate.mjs +0 -115
  112. package/lib/device/ports.mjs +0 -27
  113. package/lib/device/remote.mjs +0 -54
  114. package/lib/device/setup.mjs +0 -496
  115. package/lib/device/update.mjs +0 -96
  116. package/lib/gateway/caches.mjs +0 -36
  117. package/lib/gateway/directory.mjs +0 -90
  118. package/lib/gateway/front-core.mjs +0 -966
  119. package/lib/gateway/gateway-core.mjs +0 -244
  120. package/lib/gateway/headers.mjs +0 -49
  121. package/lib/gateway/httpsig.mjs +0 -159
  122. package/lib/gateway/notices.mjs +0 -84
  123. package/lib/gateway/quiet.mjs +0 -189
  124. package/lib/gateway/relay-extras.mjs +0 -89
  125. package/lib/gateway/token-claims.mjs +0 -16
  126. package/lib/pod/README.md +0 -61
  127. package/lib/pod/actor.mjs +0 -96
  128. package/lib/pod/collection.mjs +0 -77
  129. package/lib/pod/containers.mjs +0 -140
  130. package/lib/pod/discovery.mjs +0 -46
  131. package/lib/pod/featured.mjs +0 -18
  132. package/lib/pod/followers.mjs +0 -24
  133. package/lib/pod/following.mjs +0 -10
  134. package/lib/pod/http.mjs +0 -74
  135. package/lib/pod/inbox.mjs +0 -166
  136. package/lib/pod/links.mjs +0 -35
  137. package/lib/pod/location.mjs +0 -52
  138. package/lib/pod/media.mjs +0 -27
  139. package/lib/pod/notes.mjs +0 -78
  140. package/lib/pod/notifications.mjs +0 -89
  141. package/lib/pod/outbox.mjs +0 -18
  142. package/lib/pod/package.json +0 -19
  143. package/lib/pod/policy.mjs +0 -58
  144. package/lib/pod/private.mjs +0 -19
  145. package/lib/pod/root.mjs +0 -104
  146. package/lib/pod/state.mjs +0 -40
  147. package/lib/pod/transport.mjs +0 -674
  148. package/lib/pod/type-index.mjs +0 -101
  149. package/lib/pod/urls.mjs +0 -91
  150. package/lib/server/embed.mjs +0 -424
  151. package/lib/session/README.md +0 -137
  152. package/lib/session/demo.html +0 -94
  153. package/lib/session/fedi-account.mjs +0 -417
  154. package/lib/session/fedi-login.mjs +0 -123
  155. package/lib/session/oidc-session.mjs +0 -233
  156. package/lib/session/package.json +0 -49
  157. package/lib/shared/guard.mjs +0 -213
  158. package/lib/shared/links.mjs +0 -9
  159. package/lib/shared/safefetch.mjs +0 -235
  160. package/lib/shared/ua.mjs +0 -29
  161. package/phanpy/dist/404.html +0 -40
  162. package/phanpy/dist/_headers +0 -2
  163. package/phanpy/dist/apple-touch-icon.png +0 -0
  164. package/phanpy/dist/assets/ICONS-DIPJeU0C.js +0 -2
  165. package/phanpy/dist/assets/ICONS-DIPJeU0C.js.map +0 -1
  166. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js +0 -183
  167. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js.map +0 -1
  168. package/phanpy/dist/assets/Temml-CCjoacWt.woff2 +0 -0
  169. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js +0 -2
  170. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js.map +0 -1
  171. package/phanpy/dist/assets/boosts-carousel-BiOaNdMT.jpg +0 -0
  172. package/phanpy/dist/assets/catch-up-O5q5C75Z.png +0 -0
  173. package/phanpy/dist/assets/chunk-aKtaBQYM.js +0 -1
  174. package/phanpy/dist/assets/compose-CFEx7wb4.js +0 -2
  175. package/phanpy/dist/assets/compose-CFEx7wb4.js.map +0 -1
  176. package/phanpy/dist/assets/compose-ZJN5xSb4.js +0 -35
  177. package/phanpy/dist/assets/compose-ZJN5xSb4.js.map +0 -1
  178. package/phanpy/dist/assets/debug.module-YFQgwnIr.js +0 -52
  179. package/phanpy/dist/assets/debug.module-YFQgwnIr.js.map +0 -1
  180. package/phanpy/dist/assets/dom-p1YcJ5Rw.js +0 -2
  181. package/phanpy/dist/assets/dom-p1YcJ5Rw.js.map +0 -1
  182. package/phanpy/dist/assets/home-mobile-dark@2x-Dc-J8-SM.png +0 -0
  183. package/phanpy/dist/assets/home-mobile-light@2x-Bd3fod8m.png +0 -0
  184. package/phanpy/dist/assets/home-tablet-dark@2x-BgcNI8le.png +0 -0
  185. package/phanpy/dist/assets/home-tablet-light@2x-BW2RV9T6.png +0 -0
  186. package/phanpy/dist/assets/icons/add-circle-line-WD0mwORD.js +0 -1
  187. package/phanpy/dist/assets/icons/alert-line-CpFUMf9s.js +0 -1
  188. package/phanpy/dist/assets/icons/android-2-line-Bzxnrd3S.js +0 -1
  189. package/phanpy/dist/assets/icons/announcement-line-5nwaJFJm.js +0 -1
  190. package/phanpy/dist/assets/icons/arrow-down-circle-line-a7Id9-Iv.js +0 -1
  191. package/phanpy/dist/assets/icons/arrow-down-line-B8uzXzq6.js +0 -1
  192. package/phanpy/dist/assets/icons/arrow-left-line-CGrGT9C-.js +0 -1
  193. package/phanpy/dist/assets/icons/arrow-right-line-CE-HERfX.js +0 -1
  194. package/phanpy/dist/assets/icons/arrow-to-up-line-CvdQjmcy.js +0 -1
  195. package/phanpy/dist/assets/icons/arrow-up-circle-line-DEparSNF.js +0 -1
  196. package/phanpy/dist/assets/icons/arrow-up-line-C7yBeugc.js +0 -1
  197. package/phanpy/dist/assets/icons/arrows-right-line-BtbXmJGP.js +0 -1
  198. package/phanpy/dist/assets/icons/at-line-CF66Bznk.js +0 -1
  199. package/phanpy/dist/assets/icons/attachment-line-BY8It-l9.js +0 -1
  200. package/phanpy/dist/assets/icons/blockquote-line-BS6pU_hm.js +0 -1
  201. package/phanpy/dist/assets/icons/board-line-C0UWXyA6.js +0 -1
  202. package/phanpy/dist/assets/icons/bookmark-line-1CtX5JLF.js +0 -1
  203. package/phanpy/dist/assets/icons/building-5-line-Dd59MzbO.js +0 -1
  204. package/phanpy/dist/assets/icons/bus-2-line-6_dvA0GG.js +0 -1
  205. package/phanpy/dist/assets/icons/calendar-day-line-Crpl_fmu.js +0 -1
  206. package/phanpy/dist/assets/icons/calendar-month-line-vommts2C.js +0 -1
  207. package/phanpy/dist/assets/icons/calendar-time-add-line-BU_DTlQk.js +0 -1
  208. package/phanpy/dist/assets/icons/camera-line-Cv69MEei.js +0 -1
  209. package/phanpy/dist/assets/icons/celebrate-line-B8DvIoi0.js +0 -1
  210. package/phanpy/dist/assets/icons/chart-bar-line-FK-QOmtF.js +0 -1
  211. package/phanpy/dist/assets/icons/chart-line-line-BGcJAFWw.js +0 -1
  212. package/phanpy/dist/assets/icons/chat-3-line-YFK2-hwz.js +0 -1
  213. package/phanpy/dist/assets/icons/check-circle-line-DsAxFr5-.js +0 -1
  214. package/phanpy/dist/assets/icons/clipboard-line-BBp364gJ.js +0 -1
  215. package/phanpy/dist/assets/icons/close-circle-line-CICdiuGz.js +0 -1
  216. package/phanpy/dist/assets/icons/close-line-DYrFWcjv.js +0 -1
  217. package/phanpy/dist/assets/icons/cloud-line-tiQAbah8.js +0 -1
  218. package/phanpy/dist/assets/icons/code-line-fAl8iiV3.js +0 -1
  219. package/phanpy/dist/assets/icons/comment-2-line-CR3g7WeB.js +0 -1
  220. package/phanpy/dist/assets/icons/copy-2-line-CLW69yF5.js +0 -1
  221. package/phanpy/dist/assets/icons/delete-2-line-B8xmbr4n.js +0 -1
  222. package/phanpy/dist/assets/icons/document-3-line-DBGNhAg2.js +0 -1
  223. package/phanpy/dist/assets/icons/document-line-C7mb9sb7.js +0 -1
  224. package/phanpy/dist/assets/icons/down-line-BGqSSThd.js +0 -1
  225. package/phanpy/dist/assets/icons/edit-4-line-DcgGaEhx.js +0 -1
  226. package/phanpy/dist/assets/icons/emoji-2-line-D8YgnM-y.js +0 -1
  227. package/phanpy/dist/assets/icons/exit-line-Dc07BS-x.js +0 -1
  228. package/phanpy/dist/assets/icons/external-link-line-BvpSkmjO.js +0 -1
  229. package/phanpy/dist/assets/icons/eye-2-line-CiWXx-f_.js +0 -1
  230. package/phanpy/dist/assets/icons/eye-close-line-BgTaSJ4P.js +0 -1
  231. package/phanpy/dist/assets/icons/filter-2-line-B_mR2usy.js +0 -1
  232. package/phanpy/dist/assets/icons/filter-line-C_nm-3cU.js +0 -1
  233. package/phanpy/dist/assets/icons/flag-1-line-C2HB05I0.js +0 -1
  234. package/phanpy/dist/assets/icons/forbid-circle-line-D3LTT9yd.js +0 -1
  235. package/phanpy/dist/assets/icons/formula-line-DLrt2d6j.js +0 -1
  236. package/phanpy/dist/assets/icons/grid-line-CgUmEikf.js +0 -1
  237. package/phanpy/dist/assets/icons/group-line-C5fnX0wU.js +0 -1
  238. package/phanpy/dist/assets/icons/hand-finger-2-line-BGgxbuL9.js +0 -1
  239. package/phanpy/dist/assets/icons/hashtag-line-CyTEEXBb.js +0 -1
  240. package/phanpy/dist/assets/icons/heart-crack-line-BZddbO2C.js +0 -1
  241. package/phanpy/dist/assets/icons/heart-line-CJ7K47J4.js +0 -1
  242. package/phanpy/dist/assets/icons/history-2-line-kWWvFzqv.js +0 -1
  243. package/phanpy/dist/assets/icons/history-line-bGQiwbTH.js +0 -1
  244. package/phanpy/dist/assets/icons/home-3-line-fRU1zeLG.js +0 -1
  245. package/phanpy/dist/assets/icons/information-line-iNk6-sOY.js +0 -1
  246. package/phanpy/dist/assets/icons/keyboard-line-DsCyuQNz.js +0 -1
  247. package/phanpy/dist/assets/icons/layout-4-line-CZkOX52Z.js +0 -1
  248. package/phanpy/dist/assets/icons/layout-5-line-B_znt5wO.js +0 -1
  249. package/phanpy/dist/assets/icons/left-line-eUw0tya4.js +0 -1
  250. package/phanpy/dist/assets/icons/lightning-line-DaKoDdix.js +0 -1
  251. package/phanpy/dist/assets/icons/link-2-line-DCqLmMA7.js +0 -1
  252. package/phanpy/dist/assets/icons/list-check-line-BAxosBh9.js +0 -1
  253. package/phanpy/dist/assets/icons/lock-line-CPoaXeUW.js +0 -1
  254. package/phanpy/dist/assets/icons/mail-line-B0P8aa1L.js +0 -1
  255. package/phanpy/dist/assets/icons/moon-line-CEqNAToP.js +0 -1
  256. package/phanpy/dist/assets/icons/more-1-fill-Dw2e5xab.js +0 -1
  257. package/phanpy/dist/assets/icons/more-3-line-BIiVjYTz.js +0 -1
  258. package/phanpy/dist/assets/icons/notification-line-BZZq2Gtu.js +0 -1
  259. package/phanpy/dist/assets/icons/pencil-line-CKh8-A1v.js +0 -1
  260. package/phanpy/dist/assets/icons/photo-album-line-Bnfg2u40.js +0 -1
  261. package/phanpy/dist/assets/icons/pin-line-DpTolyhs.js +0 -1
  262. package/phanpy/dist/assets/icons/play-fill-B0-G_8lX.js +0 -1
  263. package/phanpy/dist/assets/icons/qrcode-2-line-B6SPCaHn.js +0 -1
  264. package/phanpy/dist/assets/icons/quill-pen-line-B6LUrnCP.js +0 -1
  265. package/phanpy/dist/assets/icons/quote-left-fill-hQZ1cj_6.js +0 -1
  266. package/phanpy/dist/assets/icons/radar-line-CKyroTth.js +0 -1
  267. package/phanpy/dist/assets/icons/react-line-CoIKhhtK.js +0 -1
  268. package/phanpy/dist/assets/icons/refresh-2-line-D0mTF97S.js +0 -1
  269. package/phanpy/dist/assets/icons/right-line-B3KWJaqc.js +0 -1
  270. package/phanpy/dist/assets/icons/rocket-line-4KZl537D.js +0 -1
  271. package/phanpy/dist/assets/icons/round-fill-C69NTrZ0.js +0 -1
  272. package/phanpy/dist/assets/icons/round-line-B9k_1uo-.js +0 -1
  273. package/phanpy/dist/assets/icons/route-line-B28ReHcE.js +0 -1
  274. package/phanpy/dist/assets/icons/rows-4-line-CrBniagM.js +0 -1
  275. package/phanpy/dist/assets/icons/scan-line-DSf74YdP.js +0 -1
  276. package/phanpy/dist/assets/icons/search-2-line-B6geIU1z.js +0 -1
  277. package/phanpy/dist/assets/icons/settings-3-line-azJwK47w.js +0 -1
  278. package/phanpy/dist/assets/icons/settings-6-line-C_5zc5YR.js +0 -1
  279. package/phanpy/dist/assets/icons/share-2-line-D5MxWjrm.js +0 -1
  280. package/phanpy/dist/assets/icons/share-forward-line-Cp61fZzZ.js +0 -1
  281. package/phanpy/dist/assets/icons/sparkles-2-line-DYYyXTaW.js +0 -1
  282. package/phanpy/dist/assets/icons/sparkles-line-C2hY1s6I.js +0 -1
  283. package/phanpy/dist/assets/icons/time-line-BF3eet1v.js +0 -1
  284. package/phanpy/dist/assets/icons/transfer-4-line-oisfvTBw.js +0 -1
  285. package/phanpy/dist/assets/icons/translate-line-BFWol2Ce.js +0 -1
  286. package/phanpy/dist/assets/icons/unlock-line-X_x5vwv3.js +0 -1
  287. package/phanpy/dist/assets/icons/upload-3-line-DgzwUJeW.js +0 -1
  288. package/phanpy/dist/assets/icons/user-4-line-BVSynZCp.js +0 -1
  289. package/phanpy/dist/assets/icons/user-add-2-line-BlGS5Q8q.js +0 -1
  290. package/phanpy/dist/assets/icons/user-add-line-BbXdHG4z.js +0 -1
  291. package/phanpy/dist/assets/icons/user-edit-line-BFAHOV0X.js +0 -1
  292. package/phanpy/dist/assets/icons/user-follow-line-BXux0wSd.js +0 -1
  293. package/phanpy/dist/assets/icons/user-star-line-DdYlpHLU.js +0 -1
  294. package/phanpy/dist/assets/icons/user-warning-line-Cj43j0_E.js +0 -1
  295. package/phanpy/dist/assets/icons/user-x-line-DIDgNlPH.js +0 -1
  296. package/phanpy/dist/assets/icons/volume-line-Bs390KQt.js +0 -1
  297. package/phanpy/dist/assets/icons/volume-mute-line-DzlzIqFZ.js +0 -1
  298. package/phanpy/dist/assets/icons/walk-line-yNXfB-md.js +0 -1
  299. package/phanpy/dist/assets/icons/world-2-line-CenkGIwj.js +0 -1
  300. package/phanpy/dist/assets/icons/zoom-in-line-CaENUphf.js +0 -1
  301. package/phanpy/dist/assets/icons/zoom-out-line-BDNk0EWo.js +0 -1
  302. package/phanpy/dist/assets/instances-BNPptnn-.json +0 -333
  303. package/phanpy/dist/assets/locales/ar-SA-CfheRbCu.js +0 -1
  304. package/phanpy/dist/assets/locales/ca-ES-DHRW86Tz.js +0 -1
  305. package/phanpy/dist/assets/locales/cs-CZ-CKoqEuA1.js +0 -1
  306. package/phanpy/dist/assets/locales/de-DE-ByRPMRFy.js +0 -1
  307. package/phanpy/dist/assets/locales/eo-UY-CPC7wLCS.js +0 -1
  308. package/phanpy/dist/assets/locales/es-ES-dJa0Fd9t.js +0 -1
  309. package/phanpy/dist/assets/locales/eu-ES-C3djlPR2.js +0 -1
  310. package/phanpy/dist/assets/locales/fa-IR-DTT490Ck.js +0 -1
  311. package/phanpy/dist/assets/locales/fi-FI-B23MCPuz.js +0 -1
  312. package/phanpy/dist/assets/locales/fr-FR-BcaQsO5C.js +0 -1
  313. package/phanpy/dist/assets/locales/gl-ES-BR-CVKBN.js +0 -1
  314. package/phanpy/dist/assets/locales/he-IL-CfheRbCu.js +0 -1
  315. package/phanpy/dist/assets/locales/hu-HU-CfheRbCu.js +0 -1
  316. package/phanpy/dist/assets/locales/it-IT-C1136UFV.js +0 -1
  317. package/phanpy/dist/assets/locales/ja-JP-CRZmRAhD.js +0 -1
  318. package/phanpy/dist/assets/locales/kab-Cz8xH_TT.js +0 -1
  319. package/phanpy/dist/assets/locales/ko-KR-CG9UiY4o.js +0 -1
  320. package/phanpy/dist/assets/locales/lt-LT-CJcI6sHZ.js +0 -1
  321. package/phanpy/dist/assets/locales/nb-NO-CfheRbCu.js +0 -1
  322. package/phanpy/dist/assets/locales/nl-NL-DxN4Yc1t.js +0 -1
  323. package/phanpy/dist/assets/locales/oc-FR-CfheRbCu.js +0 -1
  324. package/phanpy/dist/assets/locales/pl-PL-DkwGXf6P.js +0 -1
  325. package/phanpy/dist/assets/locales/pseudo-LOCALE-CQ4XxkQ0.js +0 -1
  326. package/phanpy/dist/assets/locales/pt-BR-nGL0HdFS.js +0 -1
  327. package/phanpy/dist/assets/locales/pt-PT-Cp17aj2z.js +0 -1
  328. package/phanpy/dist/assets/locales/ru-RU-0Y8cIoaK.js +0 -1
  329. package/phanpy/dist/assets/locales/th-TH-CfheRbCu.js +0 -1
  330. package/phanpy/dist/assets/locales/tok-CfheRbCu.js +0 -1
  331. package/phanpy/dist/assets/locales/tr-TR-CfheRbCu.js +0 -1
  332. package/phanpy/dist/assets/locales/uk-UA-C5E3dFBf.js +0 -1
  333. package/phanpy/dist/assets/locales/zh-CN-BHJi7_et.js +0 -1
  334. package/phanpy/dist/assets/locales/zh-TW-CfheRbCu.js +0 -1
  335. package/phanpy/dist/assets/main-BdqNbG-a.js +0 -26
  336. package/phanpy/dist/assets/main-BdqNbG-a.js.map +0 -1
  337. package/phanpy/dist/assets/mock-home-DGhR__He.js +0 -2
  338. package/phanpy/dist/assets/mock-home-DGhR__He.js.map +0 -1
  339. package/phanpy/dist/assets/multi-column-ROck0NVt.jpg +0 -0
  340. package/phanpy/dist/assets/multi-hashtag-timeline-DH5INVHi.jpg +0 -0
  341. package/phanpy/dist/assets/nested-comments-thread-hv59kZLc.jpg +0 -0
  342. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js +0 -2
  343. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js.map +0 -1
  344. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js +0 -20
  345. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js.map +0 -1
  346. package/phanpy/dist/assets/style-B1iLPTPR.css +0 -2
  347. package/phanpy/dist/assets/temml-DuyIQMei.js +0 -97
  348. package/phanpy/dist/assets/temml-DuyIQMei.js.map +0 -1
  349. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js +0 -2
  350. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js.map +0 -1
  351. package/phanpy/dist/assets/year-in-posts-B2lywqdx.png +0 -0
  352. package/phanpy/dist/assets/year-in-posts-DJv_star.js +0 -3
  353. package/phanpy/dist/assets/year-in-posts-DJv_star.js.map +0 -1
  354. package/phanpy/dist/compose/index.html +0 -20
  355. package/phanpy/dist/favicon.ico +0 -0
  356. package/phanpy/dist/index.html +0 -73
  357. package/phanpy/dist/logo-192.png +0 -0
  358. package/phanpy/dist/logo-512.png +0 -0
  359. package/phanpy/dist/logo-badge-72.png +0 -0
  360. package/phanpy/dist/logo-maskable-512.png +0 -0
  361. package/phanpy/dist/logo-monochrome-512.png +0 -0
  362. package/phanpy/dist/logo-monochrome-maskable-512.png +0 -0
  363. package/phanpy/dist/manifest.webmanifest +0 -1
  364. package/phanpy/dist/og-image-2.jpg +0 -0
  365. package/phanpy/dist/og-image.png +0 -0
  366. package/phanpy/dist/robots.txt +0 -2
  367. package/phanpy/dist/sw.js +0 -2
  368. package/phanpy/dist/sw.js.map +0 -1
  369. package/phanpy/dist/version.json +0 -1
  370. package/run-agent.mjs +0 -899
  371. package/vendor/gate.cjs +0 -138
  372. package/vendor/idp-grant.cjs +0 -394
  373. package/vendor/jfetch.cjs +0 -16
  374. package/web/admin/actors.js +0 -147
  375. package/web/admin/bar.css +0 -126
  376. package/web/admin/bar.js +0 -99
  377. package/web/admin/client/client.js +0 -66
  378. package/web/admin/client/index.html +0 -69
  379. package/web/admin/client-pick.js +0 -79
  380. package/web/admin/common.js +0 -23
  381. package/web/admin/connections.js +0 -112
  382. package/web/admin/gateway.js +0 -133
  383. package/web/admin/group.js +0 -258
  384. package/web/admin/index.html +0 -612
  385. package/web/admin/notices-bar.js +0 -90
  386. package/web/admin/oauth-signin.mjs +0 -37
  387. package/web/admin/record.js +0 -393
  388. package/web/admin/setup/index.html +0 -257
  389. package/web/admin/setup/setup.js +0 -339
  390. package/web/admin/tokens.css +0 -68
  391. package/web/admin/upkeep.js +0 -177
  392. package/web/admin/window.css +0 -55
  393. package/web/admin/window.js +0 -136
  394. package/web/app/README.md +0 -81
  395. package/web/app/admin-facade.mjs +0 -588
  396. package/web/app/agent.mjs +0 -672
  397. package/web/app/atproto-browser.mjs +0 -86
  398. package/web/app/authorize_interaction.html +0 -56
  399. package/web/app/authorize_interaction.js +0 -69
  400. package/web/app/boot.mjs +0 -616
  401. package/web/app/deliver-relay.mjs +0 -129
  402. package/web/app/dist/boot.js +0 -34562
  403. package/web/app/dist/boot.js.map +0 -7
  404. package/web/app/dist/sw.js +0 -73456
  405. package/web/app/dist/sw.js.map +0 -7
  406. package/web/app/fediacct-browser.mjs +0 -146
  407. package/web/app/gateway-move.mjs +0 -60
  408. package/web/app/idb-kv.mjs +0 -35
  409. package/web/app/index.html +0 -258
  410. package/web/app/keys-browser.mjs +0 -71
  411. package/web/app/keystore.mjs +0 -82
  412. package/web/app/oidc-session.mjs +0 -6
  413. package/web/app/pod-auth.mjs +0 -248
  414. package/web/app/pod-remote.mjs +0 -84
  415. package/web/app/shims/_globals.mjs +0 -2
  416. package/web/app/shims/fedify-sig.mjs +0 -77
  417. package/web/app/shims/node-crypto.mjs +0 -113
  418. package/web/app/shims/node-fs.mjs +0 -17
  419. package/web/app/shims/node-path.mjs +0 -19
  420. package/web/app/shims/node-url.mjs +0 -7
  421. package/web/app/shims/prelude.js +0 -58
  422. package/web/app/shims/safefetch.mjs +0 -58
  423. package/web/app/shims/shapes-text.mjs +0 -8
  424. package/web/app/shims/web-push.mjs +0 -14
  425. package/web/app/signup.mjs +0 -357
  426. package/web/app/sw-src.mjs +0 -220
  427. package/web/app/update.js +0 -70
  428. package/web/front/admin.html +0 -55
  429. package/web/front/admin.js +0 -89
  430. package/web/front/install.sh +0 -69
  431. package/web/front/new-account.html +0 -35
  432. package/web/front/new-account.js +0 -13
  433. package/web/front/notices.html +0 -69
  434. package/web/front/notices.js +0 -107
  435. package/web/front/run.html +0 -64
  436. package/web/front/run.js +0 -221
  437. package/web/front/solid-oidc-client.js +0 -6
  438. package/web/icons/forum.svg +0 -11
  439. package/web/icons/gateway.svg +0 -14
  440. package/web/icons/local.svg +0 -11
@@ -1,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
- };