fedipod-server 0.28.1 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (438) hide show
  1. package/README.md +38 -34
  2. package/config/server.json +22 -0
  3. package/dist/claims.js +3 -2
  4. package/dist/directory.d.ts +2 -0
  5. package/dist/door.d.ts +4 -0
  6. package/dist/door.js +31 -0
  7. package/dist/fedipod.d.ts +16 -0
  8. package/dist/fedipod.js +13 -0
  9. package/dist/front.d.ts +3 -0
  10. package/dist/front.js +94 -0
  11. package/dist/handler.d.ts +39 -101
  12. package/dist/handler.js +86 -617
  13. package/dist/handler.jsonld +6 -30
  14. package/dist/identities.d.ts +62 -0
  15. package/dist/identities.js +236 -0
  16. package/dist/mounts.d.ts +43 -0
  17. package/dist/mounts.js +123 -0
  18. package/dist/opt-in.d.ts +46 -0
  19. package/dist/opt-in.js +176 -0
  20. package/dist/store-pod.js +37 -0
  21. package/package.json +10 -18
  22. package/lib/client/c2s.mjs +0 -582
  23. package/lib/client/localapi.mjs +0 -87
  24. package/lib/client/masto/accounts.mjs +0 -309
  25. package/lib/client/masto/body.mjs +0 -156
  26. package/lib/client/masto/index.mjs +0 -206
  27. package/lib/client/masto/instance.mjs +0 -112
  28. package/lib/client/masto/media.mjs +0 -79
  29. package/lib/client/masto/oauth.mjs +0 -656
  30. package/lib/client/masto/render.mjs +0 -518
  31. package/lib/client/masto/statuses.mjs +0 -372
  32. package/lib/client/masto/timelines.mjs +0 -438
  33. package/lib/client/oidc-auth.mjs +0 -62
  34. package/lib/client/streaming.mjs +0 -154
  35. package/lib/client/webpush.mjs +0 -98
  36. package/lib/connections/acctfeed.mjs +0 -257
  37. package/lib/connections/atproto.mjs +0 -309
  38. package/lib/connections/bskyfeed.mjs +0 -243
  39. package/lib/connections/bskygroup.mjs +0 -162
  40. package/lib/connections/fediacct.mjs +0 -253
  41. package/lib/connections/import.mjs +0 -357
  42. package/lib/connections/tagfeed.mjs +0 -212
  43. package/lib/connections/vault.mjs +0 -114
  44. package/lib/core/as2.mjs +0 -206
  45. package/lib/core/contexts/activitystreams.json +0 -379
  46. package/lib/core/contexts/anno.json +0 -126
  47. package/lib/core/contexts/did-v1.json +0 -57
  48. package/lib/core/contexts/fep-5711.json +0 -36
  49. package/lib/core/contexts/gotosocial.json +0 -86
  50. package/lib/core/contexts/identity-v1.json +0 -152
  51. package/lib/core/contexts/index.mjs +0 -63
  52. package/lib/core/contexts/join-lemmy.json +0 -33
  53. package/lib/core/contexts/joinmastodon.json +0 -28
  54. package/lib/core/contexts/litepub-0.1.json +0 -60
  55. package/lib/core/contexts/map.json +0 -19
  56. package/lib/core/contexts/miscellany.json +0 -19
  57. package/lib/core/contexts/quotes.json +0 -18
  58. package/lib/core/contexts/schemaorg.json +0 -8845
  59. package/lib/core/contexts/security-data-integrity-v1.json +0 -78
  60. package/lib/core/contexts/security-data-integrity-v2.json +0 -81
  61. package/lib/core/contexts/security-multikey-v1.json +0 -35
  62. package/lib/core/contexts/security-v1.json +0 -74
  63. package/lib/core/contexts/webfinger.json +0 -10
  64. package/lib/core/deliver.mjs +0 -371
  65. package/lib/core/graphview.mjs +0 -327
  66. package/lib/core/intake/activities.mjs +0 -633
  67. package/lib/core/intake/activity.mjs +0 -318
  68. package/lib/core/intake/channel.mjs +0 -144
  69. package/lib/core/intake/group.mjs +0 -256
  70. package/lib/core/intake/index.mjs +0 -701
  71. package/lib/core/intake/notes.mjs +0 -360
  72. package/lib/core/intake/verify.mjs +0 -142
  73. package/lib/core/keys.mjs +0 -153
  74. package/lib/core/lease.mjs +0 -206
  75. package/lib/core/polls.mjs +0 -105
  76. package/lib/core/profile-page.mjs +0 -104
  77. package/lib/core/proof.mjs +0 -79
  78. package/lib/core/publisher/collections.mjs +0 -237
  79. package/lib/core/publisher/index.mjs +0 -500
  80. package/lib/core/publisher/notes.mjs +0 -453
  81. package/lib/core/publisher/questions.mjs +0 -239
  82. package/lib/core/publisher/restore.mjs +0 -224
  83. package/lib/core/shapes/activitystreams.ttl +0 -157
  84. package/lib/core/shapes/index.mjs +0 -132
  85. package/lib/core/shapes/shapes-text.mjs +0 -13
  86. package/lib/core/social.mjs +0 -531
  87. package/lib/core/storage.mjs +0 -176
  88. package/lib/core/store.mjs +0 -568
  89. package/lib/core/wire-quotes.mjs +0 -71
  90. package/lib/core/wire.mjs +0 -889
  91. package/lib/device/account.mjs +0 -87
  92. package/lib/device/admin/index.mjs +0 -13
  93. package/lib/device/admin/origins.mjs +0 -35
  94. package/lib/device/admin/routes/connections.mjs +0 -144
  95. package/lib/device/admin/routes/gateway.mjs +0 -199
  96. package/lib/device/admin/routes/lifecycle.mjs +0 -200
  97. package/lib/device/admin/routes/owner.mjs +0 -322
  98. package/lib/device/admin/routes/setup.mjs +0 -412
  99. package/lib/device/admin/routes/social.mjs +0 -188
  100. package/lib/device/admin/server.mjs +0 -95
  101. package/lib/device/admin/static.mjs +0 -247
  102. package/lib/device/admin/surface.mjs +0 -315
  103. package/lib/device/certs.mjs +0 -281
  104. package/lib/device/cli/commands/account.mjs +0 -586
  105. package/lib/device/cli/commands/run.mjs +0 -278
  106. package/lib/device/cli/commands/service.mjs +0 -221
  107. package/lib/device/cli/commands/setup.mjs +0 -447
  108. package/lib/device/cli/commands/state.mjs +0 -561
  109. package/lib/device/cli/context.mjs +0 -288
  110. package/lib/device/export-collections.mjs +0 -161
  111. package/lib/device/gateway-move.mjs +0 -58
  112. package/lib/device/home.mjs +0 -161
  113. package/lib/device/migrate.mjs +0 -115
  114. package/lib/device/ports.mjs +0 -27
  115. package/lib/device/remote.mjs +0 -54
  116. package/lib/device/setup.mjs +0 -459
  117. package/lib/device/update.mjs +0 -96
  118. package/lib/gateway/caches.mjs +0 -36
  119. package/lib/gateway/directory.mjs +0 -90
  120. package/lib/gateway/front-core.mjs +0 -970
  121. package/lib/gateway/gateway-core.mjs +0 -165
  122. package/lib/gateway/headers.mjs +0 -49
  123. package/lib/gateway/httpsig.mjs +0 -159
  124. package/lib/gateway/notices.mjs +0 -84
  125. package/lib/gateway/quiet.mjs +0 -189
  126. package/lib/pod/README.md +0 -61
  127. package/lib/pod/actor.mjs +0 -96
  128. package/lib/pod/collection.mjs +0 -77
  129. package/lib/pod/containers.mjs +0 -140
  130. package/lib/pod/discovery.mjs +0 -46
  131. package/lib/pod/featured.mjs +0 -18
  132. package/lib/pod/followers.mjs +0 -24
  133. package/lib/pod/following.mjs +0 -10
  134. package/lib/pod/http.mjs +0 -74
  135. package/lib/pod/inbox.mjs +0 -166
  136. package/lib/pod/links.mjs +0 -35
  137. package/lib/pod/media.mjs +0 -27
  138. package/lib/pod/notes.mjs +0 -80
  139. package/lib/pod/notifications.mjs +0 -89
  140. package/lib/pod/outbox.mjs +0 -18
  141. package/lib/pod/package.json +0 -19
  142. package/lib/pod/policy.mjs +0 -58
  143. package/lib/pod/private.mjs +0 -19
  144. package/lib/pod/root.mjs +0 -104
  145. package/lib/pod/state.mjs +0 -40
  146. package/lib/pod/transport.mjs +0 -525
  147. package/lib/pod/urls.mjs +0 -85
  148. package/lib/server/embed.mjs +0 -423
  149. package/lib/session/README.md +0 -137
  150. package/lib/session/demo.html +0 -94
  151. package/lib/session/fedi-account.mjs +0 -408
  152. package/lib/session/fedi-login.mjs +0 -123
  153. package/lib/session/oidc-session.mjs +0 -233
  154. package/lib/session/package.json +0 -49
  155. package/lib/shared/guard.mjs +0 -213
  156. package/lib/shared/links.mjs +0 -9
  157. package/lib/shared/safefetch.mjs +0 -235
  158. package/lib/shared/ua.mjs +0 -29
  159. package/phanpy/dist/404.html +0 -40
  160. package/phanpy/dist/_headers +0 -2
  161. package/phanpy/dist/apple-touch-icon.png +0 -0
  162. package/phanpy/dist/assets/ICONS-DIPJeU0C.js +0 -2
  163. package/phanpy/dist/assets/ICONS-DIPJeU0C.js.map +0 -1
  164. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js +0 -183
  165. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js.map +0 -1
  166. package/phanpy/dist/assets/Temml-CCjoacWt.woff2 +0 -0
  167. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js +0 -2
  168. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js.map +0 -1
  169. package/phanpy/dist/assets/boosts-carousel-BiOaNdMT.jpg +0 -0
  170. package/phanpy/dist/assets/catch-up-O5q5C75Z.png +0 -0
  171. package/phanpy/dist/assets/chunk-aKtaBQYM.js +0 -1
  172. package/phanpy/dist/assets/compose-CFEx7wb4.js +0 -2
  173. package/phanpy/dist/assets/compose-CFEx7wb4.js.map +0 -1
  174. package/phanpy/dist/assets/compose-ZJN5xSb4.js +0 -35
  175. package/phanpy/dist/assets/compose-ZJN5xSb4.js.map +0 -1
  176. package/phanpy/dist/assets/debug.module-YFQgwnIr.js +0 -52
  177. package/phanpy/dist/assets/debug.module-YFQgwnIr.js.map +0 -1
  178. package/phanpy/dist/assets/dom-p1YcJ5Rw.js +0 -2
  179. package/phanpy/dist/assets/dom-p1YcJ5Rw.js.map +0 -1
  180. package/phanpy/dist/assets/home-mobile-dark@2x-Dc-J8-SM.png +0 -0
  181. package/phanpy/dist/assets/home-mobile-light@2x-Bd3fod8m.png +0 -0
  182. package/phanpy/dist/assets/home-tablet-dark@2x-BgcNI8le.png +0 -0
  183. package/phanpy/dist/assets/home-tablet-light@2x-BW2RV9T6.png +0 -0
  184. package/phanpy/dist/assets/icons/add-circle-line-WD0mwORD.js +0 -1
  185. package/phanpy/dist/assets/icons/alert-line-CpFUMf9s.js +0 -1
  186. package/phanpy/dist/assets/icons/android-2-line-Bzxnrd3S.js +0 -1
  187. package/phanpy/dist/assets/icons/announcement-line-5nwaJFJm.js +0 -1
  188. package/phanpy/dist/assets/icons/arrow-down-circle-line-a7Id9-Iv.js +0 -1
  189. package/phanpy/dist/assets/icons/arrow-down-line-B8uzXzq6.js +0 -1
  190. package/phanpy/dist/assets/icons/arrow-left-line-CGrGT9C-.js +0 -1
  191. package/phanpy/dist/assets/icons/arrow-right-line-CE-HERfX.js +0 -1
  192. package/phanpy/dist/assets/icons/arrow-to-up-line-CvdQjmcy.js +0 -1
  193. package/phanpy/dist/assets/icons/arrow-up-circle-line-DEparSNF.js +0 -1
  194. package/phanpy/dist/assets/icons/arrow-up-line-C7yBeugc.js +0 -1
  195. package/phanpy/dist/assets/icons/arrows-right-line-BtbXmJGP.js +0 -1
  196. package/phanpy/dist/assets/icons/at-line-CF66Bznk.js +0 -1
  197. package/phanpy/dist/assets/icons/attachment-line-BY8It-l9.js +0 -1
  198. package/phanpy/dist/assets/icons/blockquote-line-BS6pU_hm.js +0 -1
  199. package/phanpy/dist/assets/icons/board-line-C0UWXyA6.js +0 -1
  200. package/phanpy/dist/assets/icons/bookmark-line-1CtX5JLF.js +0 -1
  201. package/phanpy/dist/assets/icons/building-5-line-Dd59MzbO.js +0 -1
  202. package/phanpy/dist/assets/icons/bus-2-line-6_dvA0GG.js +0 -1
  203. package/phanpy/dist/assets/icons/calendar-day-line-Crpl_fmu.js +0 -1
  204. package/phanpy/dist/assets/icons/calendar-month-line-vommts2C.js +0 -1
  205. package/phanpy/dist/assets/icons/calendar-time-add-line-BU_DTlQk.js +0 -1
  206. package/phanpy/dist/assets/icons/camera-line-Cv69MEei.js +0 -1
  207. package/phanpy/dist/assets/icons/celebrate-line-B8DvIoi0.js +0 -1
  208. package/phanpy/dist/assets/icons/chart-bar-line-FK-QOmtF.js +0 -1
  209. package/phanpy/dist/assets/icons/chart-line-line-BGcJAFWw.js +0 -1
  210. package/phanpy/dist/assets/icons/chat-3-line-YFK2-hwz.js +0 -1
  211. package/phanpy/dist/assets/icons/check-circle-line-DsAxFr5-.js +0 -1
  212. package/phanpy/dist/assets/icons/clipboard-line-BBp364gJ.js +0 -1
  213. package/phanpy/dist/assets/icons/close-circle-line-CICdiuGz.js +0 -1
  214. package/phanpy/dist/assets/icons/close-line-DYrFWcjv.js +0 -1
  215. package/phanpy/dist/assets/icons/cloud-line-tiQAbah8.js +0 -1
  216. package/phanpy/dist/assets/icons/code-line-fAl8iiV3.js +0 -1
  217. package/phanpy/dist/assets/icons/comment-2-line-CR3g7WeB.js +0 -1
  218. package/phanpy/dist/assets/icons/copy-2-line-CLW69yF5.js +0 -1
  219. package/phanpy/dist/assets/icons/delete-2-line-B8xmbr4n.js +0 -1
  220. package/phanpy/dist/assets/icons/document-3-line-DBGNhAg2.js +0 -1
  221. package/phanpy/dist/assets/icons/document-line-C7mb9sb7.js +0 -1
  222. package/phanpy/dist/assets/icons/down-line-BGqSSThd.js +0 -1
  223. package/phanpy/dist/assets/icons/edit-4-line-DcgGaEhx.js +0 -1
  224. package/phanpy/dist/assets/icons/emoji-2-line-D8YgnM-y.js +0 -1
  225. package/phanpy/dist/assets/icons/exit-line-Dc07BS-x.js +0 -1
  226. package/phanpy/dist/assets/icons/external-link-line-BvpSkmjO.js +0 -1
  227. package/phanpy/dist/assets/icons/eye-2-line-CiWXx-f_.js +0 -1
  228. package/phanpy/dist/assets/icons/eye-close-line-BgTaSJ4P.js +0 -1
  229. package/phanpy/dist/assets/icons/filter-2-line-B_mR2usy.js +0 -1
  230. package/phanpy/dist/assets/icons/filter-line-C_nm-3cU.js +0 -1
  231. package/phanpy/dist/assets/icons/flag-1-line-C2HB05I0.js +0 -1
  232. package/phanpy/dist/assets/icons/forbid-circle-line-D3LTT9yd.js +0 -1
  233. package/phanpy/dist/assets/icons/formula-line-DLrt2d6j.js +0 -1
  234. package/phanpy/dist/assets/icons/grid-line-CgUmEikf.js +0 -1
  235. package/phanpy/dist/assets/icons/group-line-C5fnX0wU.js +0 -1
  236. package/phanpy/dist/assets/icons/hand-finger-2-line-BGgxbuL9.js +0 -1
  237. package/phanpy/dist/assets/icons/hashtag-line-CyTEEXBb.js +0 -1
  238. package/phanpy/dist/assets/icons/heart-crack-line-BZddbO2C.js +0 -1
  239. package/phanpy/dist/assets/icons/heart-line-CJ7K47J4.js +0 -1
  240. package/phanpy/dist/assets/icons/history-2-line-kWWvFzqv.js +0 -1
  241. package/phanpy/dist/assets/icons/history-line-bGQiwbTH.js +0 -1
  242. package/phanpy/dist/assets/icons/home-3-line-fRU1zeLG.js +0 -1
  243. package/phanpy/dist/assets/icons/information-line-iNk6-sOY.js +0 -1
  244. package/phanpy/dist/assets/icons/keyboard-line-DsCyuQNz.js +0 -1
  245. package/phanpy/dist/assets/icons/layout-4-line-CZkOX52Z.js +0 -1
  246. package/phanpy/dist/assets/icons/layout-5-line-B_znt5wO.js +0 -1
  247. package/phanpy/dist/assets/icons/left-line-eUw0tya4.js +0 -1
  248. package/phanpy/dist/assets/icons/lightning-line-DaKoDdix.js +0 -1
  249. package/phanpy/dist/assets/icons/link-2-line-DCqLmMA7.js +0 -1
  250. package/phanpy/dist/assets/icons/list-check-line-BAxosBh9.js +0 -1
  251. package/phanpy/dist/assets/icons/lock-line-CPoaXeUW.js +0 -1
  252. package/phanpy/dist/assets/icons/mail-line-B0P8aa1L.js +0 -1
  253. package/phanpy/dist/assets/icons/moon-line-CEqNAToP.js +0 -1
  254. package/phanpy/dist/assets/icons/more-1-fill-Dw2e5xab.js +0 -1
  255. package/phanpy/dist/assets/icons/more-3-line-BIiVjYTz.js +0 -1
  256. package/phanpy/dist/assets/icons/notification-line-BZZq2Gtu.js +0 -1
  257. package/phanpy/dist/assets/icons/pencil-line-CKh8-A1v.js +0 -1
  258. package/phanpy/dist/assets/icons/photo-album-line-Bnfg2u40.js +0 -1
  259. package/phanpy/dist/assets/icons/pin-line-DpTolyhs.js +0 -1
  260. package/phanpy/dist/assets/icons/play-fill-B0-G_8lX.js +0 -1
  261. package/phanpy/dist/assets/icons/qrcode-2-line-B6SPCaHn.js +0 -1
  262. package/phanpy/dist/assets/icons/quill-pen-line-B6LUrnCP.js +0 -1
  263. package/phanpy/dist/assets/icons/quote-left-fill-hQZ1cj_6.js +0 -1
  264. package/phanpy/dist/assets/icons/radar-line-CKyroTth.js +0 -1
  265. package/phanpy/dist/assets/icons/react-line-CoIKhhtK.js +0 -1
  266. package/phanpy/dist/assets/icons/refresh-2-line-D0mTF97S.js +0 -1
  267. package/phanpy/dist/assets/icons/right-line-B3KWJaqc.js +0 -1
  268. package/phanpy/dist/assets/icons/rocket-line-4KZl537D.js +0 -1
  269. package/phanpy/dist/assets/icons/round-fill-C69NTrZ0.js +0 -1
  270. package/phanpy/dist/assets/icons/round-line-B9k_1uo-.js +0 -1
  271. package/phanpy/dist/assets/icons/route-line-B28ReHcE.js +0 -1
  272. package/phanpy/dist/assets/icons/rows-4-line-CrBniagM.js +0 -1
  273. package/phanpy/dist/assets/icons/scan-line-DSf74YdP.js +0 -1
  274. package/phanpy/dist/assets/icons/search-2-line-B6geIU1z.js +0 -1
  275. package/phanpy/dist/assets/icons/settings-3-line-azJwK47w.js +0 -1
  276. package/phanpy/dist/assets/icons/settings-6-line-C_5zc5YR.js +0 -1
  277. package/phanpy/dist/assets/icons/share-2-line-D5MxWjrm.js +0 -1
  278. package/phanpy/dist/assets/icons/share-forward-line-Cp61fZzZ.js +0 -1
  279. package/phanpy/dist/assets/icons/sparkles-2-line-DYYyXTaW.js +0 -1
  280. package/phanpy/dist/assets/icons/sparkles-line-C2hY1s6I.js +0 -1
  281. package/phanpy/dist/assets/icons/time-line-BF3eet1v.js +0 -1
  282. package/phanpy/dist/assets/icons/transfer-4-line-oisfvTBw.js +0 -1
  283. package/phanpy/dist/assets/icons/translate-line-BFWol2Ce.js +0 -1
  284. package/phanpy/dist/assets/icons/unlock-line-X_x5vwv3.js +0 -1
  285. package/phanpy/dist/assets/icons/upload-3-line-DgzwUJeW.js +0 -1
  286. package/phanpy/dist/assets/icons/user-4-line-BVSynZCp.js +0 -1
  287. package/phanpy/dist/assets/icons/user-add-2-line-BlGS5Q8q.js +0 -1
  288. package/phanpy/dist/assets/icons/user-add-line-BbXdHG4z.js +0 -1
  289. package/phanpy/dist/assets/icons/user-edit-line-BFAHOV0X.js +0 -1
  290. package/phanpy/dist/assets/icons/user-follow-line-BXux0wSd.js +0 -1
  291. package/phanpy/dist/assets/icons/user-star-line-DdYlpHLU.js +0 -1
  292. package/phanpy/dist/assets/icons/user-warning-line-Cj43j0_E.js +0 -1
  293. package/phanpy/dist/assets/icons/user-x-line-DIDgNlPH.js +0 -1
  294. package/phanpy/dist/assets/icons/volume-line-Bs390KQt.js +0 -1
  295. package/phanpy/dist/assets/icons/volume-mute-line-DzlzIqFZ.js +0 -1
  296. package/phanpy/dist/assets/icons/walk-line-yNXfB-md.js +0 -1
  297. package/phanpy/dist/assets/icons/world-2-line-CenkGIwj.js +0 -1
  298. package/phanpy/dist/assets/icons/zoom-in-line-CaENUphf.js +0 -1
  299. package/phanpy/dist/assets/icons/zoom-out-line-BDNk0EWo.js +0 -1
  300. package/phanpy/dist/assets/instances-BNPptnn-.json +0 -333
  301. package/phanpy/dist/assets/locales/ar-SA-CfheRbCu.js +0 -1
  302. package/phanpy/dist/assets/locales/ca-ES-DHRW86Tz.js +0 -1
  303. package/phanpy/dist/assets/locales/cs-CZ-CKoqEuA1.js +0 -1
  304. package/phanpy/dist/assets/locales/de-DE-ByRPMRFy.js +0 -1
  305. package/phanpy/dist/assets/locales/eo-UY-CPC7wLCS.js +0 -1
  306. package/phanpy/dist/assets/locales/es-ES-dJa0Fd9t.js +0 -1
  307. package/phanpy/dist/assets/locales/eu-ES-C3djlPR2.js +0 -1
  308. package/phanpy/dist/assets/locales/fa-IR-DTT490Ck.js +0 -1
  309. package/phanpy/dist/assets/locales/fi-FI-B23MCPuz.js +0 -1
  310. package/phanpy/dist/assets/locales/fr-FR-BcaQsO5C.js +0 -1
  311. package/phanpy/dist/assets/locales/gl-ES-BR-CVKBN.js +0 -1
  312. package/phanpy/dist/assets/locales/he-IL-CfheRbCu.js +0 -1
  313. package/phanpy/dist/assets/locales/hu-HU-CfheRbCu.js +0 -1
  314. package/phanpy/dist/assets/locales/it-IT-C1136UFV.js +0 -1
  315. package/phanpy/dist/assets/locales/ja-JP-CRZmRAhD.js +0 -1
  316. package/phanpy/dist/assets/locales/kab-Cz8xH_TT.js +0 -1
  317. package/phanpy/dist/assets/locales/ko-KR-CG9UiY4o.js +0 -1
  318. package/phanpy/dist/assets/locales/lt-LT-CJcI6sHZ.js +0 -1
  319. package/phanpy/dist/assets/locales/nb-NO-CfheRbCu.js +0 -1
  320. package/phanpy/dist/assets/locales/nl-NL-DxN4Yc1t.js +0 -1
  321. package/phanpy/dist/assets/locales/oc-FR-CfheRbCu.js +0 -1
  322. package/phanpy/dist/assets/locales/pl-PL-DkwGXf6P.js +0 -1
  323. package/phanpy/dist/assets/locales/pseudo-LOCALE-CQ4XxkQ0.js +0 -1
  324. package/phanpy/dist/assets/locales/pt-BR-nGL0HdFS.js +0 -1
  325. package/phanpy/dist/assets/locales/pt-PT-Cp17aj2z.js +0 -1
  326. package/phanpy/dist/assets/locales/ru-RU-0Y8cIoaK.js +0 -1
  327. package/phanpy/dist/assets/locales/th-TH-CfheRbCu.js +0 -1
  328. package/phanpy/dist/assets/locales/tok-CfheRbCu.js +0 -1
  329. package/phanpy/dist/assets/locales/tr-TR-CfheRbCu.js +0 -1
  330. package/phanpy/dist/assets/locales/uk-UA-C5E3dFBf.js +0 -1
  331. package/phanpy/dist/assets/locales/zh-CN-BHJi7_et.js +0 -1
  332. package/phanpy/dist/assets/locales/zh-TW-CfheRbCu.js +0 -1
  333. package/phanpy/dist/assets/main-BdqNbG-a.js +0 -26
  334. package/phanpy/dist/assets/main-BdqNbG-a.js.map +0 -1
  335. package/phanpy/dist/assets/mock-home-DGhR__He.js +0 -2
  336. package/phanpy/dist/assets/mock-home-DGhR__He.js.map +0 -1
  337. package/phanpy/dist/assets/multi-column-ROck0NVt.jpg +0 -0
  338. package/phanpy/dist/assets/multi-hashtag-timeline-DH5INVHi.jpg +0 -0
  339. package/phanpy/dist/assets/nested-comments-thread-hv59kZLc.jpg +0 -0
  340. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js +0 -2
  341. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js.map +0 -1
  342. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js +0 -20
  343. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js.map +0 -1
  344. package/phanpy/dist/assets/style-B1iLPTPR.css +0 -2
  345. package/phanpy/dist/assets/temml-DuyIQMei.js +0 -97
  346. package/phanpy/dist/assets/temml-DuyIQMei.js.map +0 -1
  347. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js +0 -2
  348. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js.map +0 -1
  349. package/phanpy/dist/assets/year-in-posts-B2lywqdx.png +0 -0
  350. package/phanpy/dist/assets/year-in-posts-DJv_star.js +0 -3
  351. package/phanpy/dist/assets/year-in-posts-DJv_star.js.map +0 -1
  352. package/phanpy/dist/compose/index.html +0 -20
  353. package/phanpy/dist/favicon.ico +0 -0
  354. package/phanpy/dist/index.html +0 -73
  355. package/phanpy/dist/logo-192.png +0 -0
  356. package/phanpy/dist/logo-512.png +0 -0
  357. package/phanpy/dist/logo-badge-72.png +0 -0
  358. package/phanpy/dist/logo-maskable-512.png +0 -0
  359. package/phanpy/dist/logo-monochrome-512.png +0 -0
  360. package/phanpy/dist/logo-monochrome-maskable-512.png +0 -0
  361. package/phanpy/dist/manifest.webmanifest +0 -1
  362. package/phanpy/dist/og-image-2.jpg +0 -0
  363. package/phanpy/dist/og-image.png +0 -0
  364. package/phanpy/dist/robots.txt +0 -2
  365. package/phanpy/dist/sw.js +0 -2
  366. package/phanpy/dist/sw.js.map +0 -1
  367. package/phanpy/dist/version.json +0 -1
  368. package/run-agent.mjs +0 -897
  369. package/vendor/gate.cjs +0 -138
  370. package/vendor/idp-grant.cjs +0 -394
  371. package/vendor/jfetch.cjs +0 -16
  372. package/web/admin/actors.js +0 -145
  373. package/web/admin/bar.css +0 -126
  374. package/web/admin/bar.js +0 -99
  375. package/web/admin/client/client.js +0 -66
  376. package/web/admin/client/index.html +0 -69
  377. package/web/admin/client-pick.js +0 -79
  378. package/web/admin/common.js +0 -23
  379. package/web/admin/connections.js +0 -112
  380. package/web/admin/gateway.js +0 -133
  381. package/web/admin/group.js +0 -258
  382. package/web/admin/index.html +0 -603
  383. package/web/admin/notices-bar.js +0 -90
  384. package/web/admin/oauth-signin.mjs +0 -37
  385. package/web/admin/record.js +0 -390
  386. package/web/admin/setup/index.html +0 -241
  387. package/web/admin/setup/setup.js +0 -326
  388. package/web/admin/tokens.css +0 -68
  389. package/web/admin/upkeep.js +0 -177
  390. package/web/admin/window.css +0 -55
  391. package/web/admin/window.js +0 -136
  392. package/web/app/README.md +0 -81
  393. package/web/app/admin-facade.mjs +0 -588
  394. package/web/app/agent.mjs +0 -663
  395. package/web/app/atproto-browser.mjs +0 -86
  396. package/web/app/authorize_interaction.html +0 -56
  397. package/web/app/authorize_interaction.js +0 -69
  398. package/web/app/boot.mjs +0 -576
  399. package/web/app/deliver-relay.mjs +0 -129
  400. package/web/app/dist/boot.js +0 -34218
  401. package/web/app/dist/boot.js.map +0 -7
  402. package/web/app/dist/sw.js +0 -72810
  403. package/web/app/dist/sw.js.map +0 -7
  404. package/web/app/fediacct-browser.mjs +0 -146
  405. package/web/app/gateway-move.mjs +0 -60
  406. package/web/app/idb-kv.mjs +0 -35
  407. package/web/app/index.html +0 -242
  408. package/web/app/keys-browser.mjs +0 -71
  409. package/web/app/keystore.mjs +0 -82
  410. package/web/app/oidc-session.mjs +0 -6
  411. package/web/app/pod-auth.mjs +0 -248
  412. package/web/app/pod-remote.mjs +0 -84
  413. package/web/app/shims/_globals.mjs +0 -2
  414. package/web/app/shims/fedify-sig.mjs +0 -77
  415. package/web/app/shims/node-crypto.mjs +0 -113
  416. package/web/app/shims/node-fs.mjs +0 -17
  417. package/web/app/shims/node-path.mjs +0 -19
  418. package/web/app/shims/node-url.mjs +0 -7
  419. package/web/app/shims/prelude.js +0 -58
  420. package/web/app/shims/safefetch.mjs +0 -58
  421. package/web/app/shims/shapes-text.mjs +0 -8
  422. package/web/app/shims/web-push.mjs +0 -14
  423. package/web/app/signup.mjs +0 -318
  424. package/web/app/sw-src.mjs +0 -220
  425. package/web/app/update.js +0 -70
  426. package/web/front/admin.html +0 -55
  427. package/web/front/admin.js +0 -89
  428. package/web/front/install.sh +0 -69
  429. package/web/front/new-account.html +0 -35
  430. package/web/front/new-account.js +0 -13
  431. package/web/front/notices.html +0 -69
  432. package/web/front/notices.js +0 -107
  433. package/web/front/run.html +0 -58
  434. package/web/front/run.js +0 -195
  435. package/web/front/solid-oidc-client.js +0 -6
  436. package/web/icons/forum.svg +0 -11
  437. package/web/icons/gateway.svg +0 -14
  438. package/web/icons/local.svg +0 -11
@@ -1,87 +0,0 @@
1
- // account.mjs — create a brand-new account + pod on a CSS server (v7 account
2
- // API), the `setup --new-account` path. Public-server sibling of
3
- // data-kitchen's seed-account.cjs, but simpler: the pod.create control makes
4
- // the pod AND its WebID in one step — no ownership challenge, because the
5
- // server authors the WebID itself.
6
- //
7
- // Flow: POST .account/account/ (or login when the email already exists) →
8
- // password.create → account.pod {name} → { pod, webId }.
9
-
10
- async function jfetch(url, { method = 'GET', body, cookie } = {}) {
11
- const headers = { accept: 'application/json' };
12
- if (body !== undefined) headers['content-type'] = 'application/json';
13
- if (cookie) headers.cookie = cookie;
14
- const res = await fetch(url, { method, headers, body: body === undefined ? undefined : JSON.stringify(body) });
15
- let json = null;
16
- try { json = await res.json(); } catch { /* non-JSON */ }
17
- return { status: res.status, json };
18
- }
19
-
20
- export async function createAccountWithPod({ issuer, email, password, podName }) {
21
- const origin = issuer.replace(/\/+$/, '');
22
- const accountRoot = `${origin}/.account/`;
23
-
24
- // Authenticate: log in when the email is already registered (idempotent
25
- // re-runs), otherwise create the account and set its password.
26
- let cookie;
27
- const login = await jfetch(`${accountRoot}login/password/`, { method: 'POST', body: { email, password } });
28
- if (login.status < 400 && login.json?.authorization) {
29
- cookie = `css-account=${login.json.authorization}`;
30
- } else {
31
- const create = await jfetch(`${accountRoot}account/`, { method: 'POST' });
32
- if (!create.json?.authorization) {
33
- throw new Error(`account create failed (HTTP ${create.status}): ${create.json?.message || 'is this a CSS server with signup enabled?'}`);
34
- }
35
- cookie = `css-account=${create.json.authorization}`;
36
- const pwCreate = (await jfetch(accountRoot, { cookie })).json?.controls?.password?.create;
37
- if (!pwCreate) throw new Error('password.create control missing — not a CSS v7 account API');
38
- const pw = await jfetch(pwCreate, { method: 'POST', cookie, body: { email, password } });
39
- if (pw.status >= 400) throw new Error(`password create failed (HTTP ${pw.status}): ${pw.json?.message || ''}`);
40
- }
41
-
42
- // Create the pod (server picks root-path or subdomain layout). When the
43
- // name is already taken BY THIS ACCOUNT — a setup re-run, or a pod made
44
- // earlier by hand — reuse it; taken by someone else stays a hard error.
45
- const controls = (await jfetch(accountRoot, { cookie })).json?.controls;
46
- const podCreate = controls?.account?.pod;
47
- if (!podCreate) throw new Error('pod create control missing — not a CSS v7 account API');
48
- // Scheme-agnostic on purpose: matching `https://name.` missed every pod on an
49
- // http server, so a re-run after a crashed setup always tried to create again
50
- // and died on "already registered to this account".
51
- const findOwn = async () => {
52
- const pods = (await jfetch(podCreate, { cookie })).json?.pods || {};
53
- return Object.entries(pods).find(([url]) => {
54
- try {
55
- const u = new URL(url);
56
- return u.hostname === podName || u.hostname.startsWith(`${podName}.`)
57
- || u.pathname.split('/').filter(Boolean).includes(podName);
58
- } catch { return false; }
59
- }) || null;
60
- };
61
- // One pod per account, refused BEFORE anything is created. A second pod gives
62
- // the account a second WebID, and a credential can only be bound to one of
63
- // them — so the second actor authenticates and then 403s every write to its
64
- // own pod. Reusing a pod of the same name is still fine: that is a re-run of
65
- // a setup, not a second identity.
66
- const owned = Object.keys((await jfetch(podCreate, { cookie })).json?.pods || {});
67
- if (owned.length && !await findOwn()) {
68
- throw new Error(`${email} already has a pod on ${new URL(origin).host}: ${owned[0]} — `
69
- + 'one account, one pod. A second actor needs its own account and email. '
70
- + 'Nothing was created.');
71
- }
72
- const made = await jfetch(podCreate, { method: 'POST', cookie, body: { name: podName } });
73
- let pod = made.json?.pod || made.json?.podBaseUrl || null;
74
- let webId = made.json?.webId || null;
75
- if (made.status >= 400 || !pod) {
76
- const own = await findOwn();
77
- if (own) {
78
- pod = own[0];
79
- webId = webId || own[1]?.webId || null;
80
- } else if (made.status >= 400) {
81
- throw new Error(`pod create failed (HTTP ${made.status}): ${made.json?.message || `is the name "${podName}" taken by another account?`}`);
82
- }
83
- }
84
- if (!pod) throw new Error('pod created but its URL was not reported — check the account dashboard');
85
- pod = pod.endsWith('/') ? pod : pod + '/';
86
- return { pod, webId: webId || new URL('profile/card#me', pod).href };
87
- }
@@ -1,13 +0,0 @@
1
- // admin.mjs — loopback HTTP front: admin API + Mastodon client-API facade +
2
- // the bundled Phanpy UI served same-origin (no CORS, no mixed content — the
3
- // role data-kitchen's router plays for the in-app pane). Loopback-bound; the
4
- // gate (vendor/gate.cjs) engages only when a token is configured, exactly
5
- // its standalone behavior.
6
- //
7
- // The surface is surface.mjs, its routes are the modules under routes/, the
8
- // static serving is static.mjs, the listener is server.mjs. This file is the
9
- // door the rest of the agent imports through.
10
-
11
- export { buildAdminSurface } from './surface.mjs';
12
- export { startAdmin } from './server.mjs';
13
- export { namedOrigin, secureOrigin, wsOrigins } from './origins.mjs';
@@ -1,35 +0,0 @@
1
- // origins.mjs — the addresses an identity answers on, as a browser must be
2
- // sent to them.
3
-
4
- import { allowedAuthorities, hostLabel } from '../../shared/guard.mjs';
5
-
6
- // The origin a browser should be sent to for an identity. A browser keys
7
- // storage per ORIGIN, so linking every identity at localhost:<port> files them
8
- // all in one bucket — which is how a client ends up holding one actor's login
9
- // and showing it on another's page. Named whenever the handle is a legal host
10
- // label; bare loopback when it is not, because a mangled name would be an
11
- // origin the other agent's own guard refuses.
12
- export function namedOrigin(handle, port) {
13
- const label = hostLabel(handle);
14
- return `http://${label ? label + '.' : ''}localhost:${port}`;
15
- }
16
-
17
- // The https origin for an identity, on the one port it was given.
18
- // This is the advertised default — what gets printed, opened and linked; the
19
- // http listener stays served beside it for anything that needs cleartext.
20
- export function secureOrigin(handle, httpsPort) {
21
- const label = hostLabel(handle);
22
- return `https://${label ? label + '.' : ''}localhost:${httpsPort}`;
23
- }
24
-
25
- export function wsOrigins(port, labels = []) {
26
- const out = new Set();
27
- for (const a of allowedAuthorities(port, labels)) {
28
- // No IPv6 at all. Bare `::1` cannot carry a port, and Chrome rejects the
29
- // bracketed form inside a CSP source expression — one invalid source makes
30
- // it drop the whole directive, which is worse than not listing the socket.
31
- if (a.startsWith('::') || a.startsWith('[')) continue;
32
- out.add(`wss://${/:\d+$/.test(a) ? a : `${a}:${port}`}`);
33
- }
34
- return [...out];
35
- }
@@ -1,144 +0,0 @@
1
- // connections.mjs — the accounts held elsewhere: a Bluesky account and
2
- // accounts on other fediverse servers, connected, adjusted, disconnected;
3
- // and the page the other server's sign-in comes back to.
4
-
5
-
6
-
7
- // The page the other server's redirect lands on. Self-contained on purpose:
8
- // the browser arrives here from somewhere else, and nothing may load from
9
- // that somewhere.
10
- function callbackPage(ok, msg) {
11
- const esc = (s) => String(s).replace(/[&<>"]/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]));
12
- const head = ok ? 'Account connected' : 'Not connected';
13
- return `<!doctype html>
14
- <html lang="en"><head><meta charset="utf-8">
15
- <meta name="viewport" content="width=device-width, initial-scale=1">
16
- <title>${head}</title>
17
- <style>
18
- :root { color-scheme: light dark; }
19
- body { font: 16px/1.7 system-ui, -apple-system, sans-serif; margin: 0;
20
- padding: 2.5rem 2rem; background: #ffffff; color: #1a1a1a; }
21
- main { max-width: 32rem; margin: 0 auto; }
22
- h1 { font-size: 1.375rem; font-weight: 500; margin: 0 0 1rem; }
23
- p { margin: 0 0 1rem; }
24
- @media (prefers-color-scheme: dark) {
25
- body { background: #16161a; color: #ececf0; }
26
- }
27
- </style></head>
28
- <body><main>
29
- <h1>${head}</h1>
30
- <p>${esc(msg)}</p>
31
- <p>You can close this tab and go back to FediPod.</p>
32
- </main></body></html>
33
- `;
34
- }
35
-
36
- export async function get(p, ctx, req, res, url) { // eslint-disable-line no-unused-vars
37
- const { agent, log, allowed, embedded, port, publicOrigin, versionOnDisk, isGroup } = ctx; // eslint-disable-line no-unused-vars
38
- const json = (res, status, obj) => { ctx.json(res, status, obj); return true; };
39
-
40
- if (req.method === 'GET' && p === '/fediacct') {
41
- return json(res, 200, { accounts: agent.fediaccts?.status() || [] });
42
- }
43
- // Where the other server sends the browser back. A GET, so it gets none
44
- // of the POST branch's local-only protection for free and asks for its
45
- // own — a code arriving from anywhere else is not the owner's.
46
- if (req.method === 'GET' && p === '/fediacct/callback') {
47
- if (!embedded && !allowed.isLocalRequest(req)) {
48
- return json(res, 403, { error: 'connecting an account is available on this machine only' });
49
- }
50
- const q = new URL(req.url, 'https://x.invalid').searchParams;
51
- const done = (ok, msg) => {
52
- res.writeHead(ok ? 200 : 400, { 'content-type': 'text/html; charset=utf-8' });
53
- res.end(callbackPage(ok, msg));
54
- return true;
55
- };
56
- if (q.get('error')) return done(false, q.get('error_description') || q.get('error'));
57
- if (!q.get('code') || !q.get('state')) return done(false, 'that sign-in came back incomplete');
58
- try {
59
- const row = await agent.fediaccts.complete({ state: q.get('state'), code: q.get('code') });
60
- const cfg = agent.store.getConfig();
61
- agent.store.setConfig({ ...cfg, fediAccounts: agent.fediaccts.roster() });
62
- await agent.store.flush();
63
- agent.restartAccts?.();
64
- return done(true, `${row.handle} is connected.`);
65
- } catch (e) { return done(false, e.message); }
66
- }
67
-
68
- return false;
69
- }
70
-
71
- export async function post(p, body, ctx, req, res) { // eslint-disable-line no-unused-vars
72
- const { agent, log, allowed, embedded, port, publicOrigin, versionOnDisk, isGroup } = ctx; // eslint-disable-line no-unused-vars
73
- const json = (res, status, obj) => { ctx.json(res, status, obj); return true; };
74
- switch (p) {
75
- case '/atproto/connect': {
76
- // The one endpoint that ever sees the app password; loopback-only.
77
- if (!body.identifier || !body.appPassword) {
78
- return json(res, 400, { error: 'identifier and appPassword required' });
79
- }
80
- const conn = await agent.atproto.connect({
81
- service: body.service, identifier: body.identifier, appPassword: body.appPassword,
82
- });
83
- const cfg = agent.store.getConfig();
84
- agent.store.setConfig({
85
- ...cfg,
86
- atproto: { ...conn, crossPost: cfg.atproto?.crossPost ?? true },
87
- });
88
- await agent.store.flush();
89
- agent.startBsky?.();
90
- return json(res, 200, { ok: true, ...agent.atproto.status() });
91
- }
92
- case '/atproto/disconnect': {
93
- agent.stopBsky?.();
94
- await agent.atproto.disconnect();
95
- const { atproto, ...rest } = agent.store.getConfig();
96
- agent.store.setConfig(rest);
97
- await agent.store.flush();
98
- return json(res, 200, { ok: true });
99
- }
100
- case '/atproto': {
101
- // Non-secret settings only — today that is the cross-post toggle.
102
- const cfg = agent.store.getConfig();
103
- if (!cfg.atproto) return json(res, 400, { error: 'no bluesky account connected' });
104
- agent.store.setConfig({
105
- ...cfg, atproto: { ...cfg.atproto, crossPost: !!body.crossPost },
106
- });
107
- await agent.store.flush();
108
- return json(res, 200, { ok: true, atproto: { ...cfg.atproto, crossPost: !!body.crossPost } });
109
- }
110
- case '/fediacct/connect': {
111
- // Starts the sign-in at the other server. Loopback-only, and the
112
- // redirect returns to the origin the owner is actually using, not a
113
- // guess — a client reaches this agent by several names.
114
- if (!body.host) return json(res, 400, { error: 'the address of the server is required' });
115
- try {
116
- const { url } = await agent.fediaccts.begin({
117
- host: body.host, redirectUri: `https://${req.headers.host}/fediacct/callback`,
118
- });
119
- return json(res, 200, { ok: true, authorize: url });
120
- } catch (e) { return json(res, 400, { error: e.message }); }
121
- }
122
- case '/fediacct/disconnect': {
123
- if (!body.id) return json(res, 400, { error: 'id required' });
124
- if (!await agent.fediaccts.remove(body.id)) return json(res, 404, { error: 'no such account' });
125
- const cfg = agent.store.getConfig();
126
- agent.store.setConfig({ ...cfg, fediAccounts: agent.fediaccts.roster() });
127
- await agent.store.flush();
128
- agent.restartAccts?.();
129
- return json(res, 200, { ok: true });
130
- }
131
- case '/fediacct': {
132
- // Non-secret settings only — today that is whether it is polled.
133
- if (!body.id) return json(res, 400, { error: 'id required' });
134
- const row = agent.fediaccts.setEnabled(body.id, !!body.enabled);
135
- if (!row) return json(res, 404, { error: 'no such account' });
136
- const cfg = agent.store.getConfig();
137
- agent.store.setConfig({ ...cfg, fediAccounts: agent.fediaccts.roster() });
138
- await agent.store.flush();
139
- agent.restartAccts?.();
140
- return json(res, 200, { ok: true, account: row });
141
- }
142
- default: return false;
143
- }
144
- }
@@ -1,199 +0,0 @@
1
- // gateway.mjs — the inbox gateway lifecycle: configure, mode, check, attach
2
- // through a front, forget.
3
-
4
- import crypto from 'node:crypto';
5
- import fs from 'node:fs';
6
- import path from 'node:path';
7
- import { spawn } from 'node:child_process';
8
-
9
- export async function post(p, body, ctx, req, res) { // eslint-disable-line no-unused-vars
10
- const { agent, log, allowed, embedded, port, publicOrigin, versionOnDisk, isGroup } = ctx; // eslint-disable-line no-unused-vars
11
- const json = (res, status, obj) => { ctx.json(res, status, obj); return true; };
12
- switch (p) {
13
- // The inbox gateway lifecycle (opt-in). `configure` points at a
14
- // deployed gateway (and reveals the HMAC secret once, to paste into
15
- // its env); `mode` walks off→shadow→trust→locked and back, each step
16
- // reversible; `forget` clears it and restores the pod inbox.
17
- case '/gateway': {
18
- const cfg = { ...agent.store.getConfig() };
19
- const g = { ...(cfg.gateway || {}) };
20
- const inboxUrl = agent.publisher?.urls?.inbox;
21
- // Availability is a read: answered before the lease takeover below,
22
- // which every real gateway change does want.
23
- if (body.action === 'check') {
24
- const front = String(body.front || '').replace(/\/+$/, '');
25
- try { new URL(front); } catch { return json(res, 400, { error: 'front must be a gateway origin URL' }); }
26
- const chk = await fetch(`${front}/api/handle?handle=${encodeURIComponent(String(body.handle || '').toLowerCase())}`,
27
- { headers: { accept: 'application/json' } }).then((r) => r.json()).catch(() => null);
28
- if (!chk) return json(res, 502, { error: `${front} did not answer its handle check` });
29
- return json(res, 200, { available: !!chk.available, reason: chk.reason || null });
30
- }
31
- await agent.requestTakeover?.();
32
- const persist = async () => {
33
- cfg.gateway = g; agent.store.setConfig(cfg);
34
- if (agent.publisher) agent.publisher.config.gateway = g;
35
- await agent.store.flush();
36
- };
37
- // Fronting renames the actor's ids; the signing key is the same
38
- // identity's and moves with it, wherever the key record lives.
39
- const restampKeys = async (actorId) => {
40
- try {
41
- const kp = path.join(agent.home, 'keys.json');
42
- const rec = JSON.parse(fs.readFileSync(kp, 'utf8'));
43
- if (rec.mintedFor) { rec.mintedFor = actorId; fs.writeFileSync(kp, JSON.stringify(rec)); return; }
44
- } catch { /* not local — try pod state */ }
45
- const podRec = agent.store.read('keys.json', null);
46
- if (podRec?.mintedFor) { podRec.mintedFor = actorId; agent.store.write('keys.json', podRec); await agent.store.flush(); }
47
- };
48
- const podActorId = () => {
49
- const base = cfg.remotePod.endsWith('/') ? cfg.remotePod : `${cfg.remotePod}/`;
50
- const root = cfg.root ? (cfg.root.endsWith('/') ? cfg.root : `${cfg.root}/`) : 'fedipod/';
51
- return `${base}${root}ap/actor`;
52
- };
53
- // The reply first, the restart a beat later — same shape as /update.
54
- const selfRestart = (why) => setTimeout(() => {
55
- log(why);
56
- if (process.env.INVOCATION_ID) { process.exit(1); return; } // systemd: Restart=on-failure respawns
57
- const child = spawn(process.execPath, process.argv.slice(1),
58
- { detached: true, stdio: 'ignore', env: process.env });
59
- child.unref();
60
- setTimeout(() => process.exit(0), 300);
61
- }, 200);
62
- if (body.action === 'configure') {
63
- if (!/^https:\/\/\S+$/.test(String(body.url || ''))) return json(res, 400, { error: 'gateway url must be https' });
64
- if (!/^https?:\/\/\S+$/.test(String(body.webId || ''))) return json(res, 400, { error: 'gateway webId must be a URL' });
65
- g.url = String(body.url); g.webId = String(body.webId);
66
- g.hmacSecret = g.hmacSecret || crypto.randomBytes(32).toString('base64');
67
- g.mode = g.mode || 'off';
68
- // The fronted actor URL, for a multi-user front that gives this
69
- // identity a @name@front handle: the agent then publishes and signs
70
- // under it. Optional; setting it on a published identity renames
71
- // every id (a Move), so it belongs at setup or a fresh identity.
72
- if ('frontActor' in body) {
73
- const fa = String(body.frontActor || '');
74
- if (fa && !/^https:\/\/\S+\/ap\/actor$/.test(fa)) {
75
- return json(res, 400, { error: 'frontActor must be an https …/ap/actor URL' });
76
- }
77
- g.frontActor = fa || undefined;
78
- }
79
- await persist();
80
- // The one time the secret is returned: the operator pastes it into
81
- // the gateway's deploy env. /gateway GET never reveals it again.
82
- return json(res, 200, { ok: true, mode: g.mode, url: g.url, webId: g.webId, hmacSecret: g.hmacSecret });
83
- }
84
- if (body.action === 'mode') {
85
- const target = body.mode;
86
- if (!['off', 'shadow', 'trust', 'locked'].includes(target)) {
87
- return json(res, 400, { error: 'mode must be off, shadow, trust or locked' });
88
- }
89
- if (target !== 'off' && !g.url) return json(res, 400, { error: 'point at a gateway first (action: configure)' });
90
- // Locking needs the door's own WebID to name in the ACL. Without it
91
- // the mode used to persist and the ACL be written for an undefined
92
- // agent, leaving config and pod disagreeing about who may write.
93
- if (target === 'locked' && !g.webId) {
94
- return json(res, 400, {
95
- error: 'locked needs the gateway\'s WebID — set it with action: configure, webId: <door-webid>',
96
- });
97
- }
98
- const prev = g.mode || 'off';
99
- // The ACL first: a lock that fails must not leave the mode recorded
100
- // as locked while the pod still accepts anyone's writes.
101
- if (target === 'locked') await agent.publisher?.lockInboxToGateway(g.webId);
102
- else if (prev === 'locked' && inboxUrl) await agent.remote.setAcl(inboxUrl, ['Append']);
103
- g.mode = target;
104
- await persist();
105
- // Advertisement flips only when crossing the off boundary (the actor
106
- // doc's inbox changes → publishProfile republishes, digest-gated).
107
- if ((prev === 'off') !== (target === 'off')) await agent.publisher?.publishProfile();
108
- else if (target !== 'off') await agent.publisher?.publishGatewayPolicy().catch(() => {});
109
- return json(res, 200, { ok: true, mode: g.mode });
110
- }
111
- // Attach through a multi-user front (fedipod.net and kin): the agent
112
- // proves the pod with its own credential — no browser, no password —
113
- // and the front answers with the door and the receipt secret.
114
- if (body.action === 'attach') {
115
- const front = String(body.front || '').replace(/\/+$/, '');
116
- let fu;
117
- try { fu = new URL(front); } catch { return json(res, 400, { error: 'front must be the gateway origin, like https://fedipod.net' }); }
118
- if (fu.protocol !== 'https:' && !/^(localhost|127\.0\.0\.1)$|\.localhost$/.test(fu.hostname)) {
119
- return json(res, 400, { error: 'front must be https' });
120
- }
121
- if (agent.embedded) {
122
- return json(res, 400, { error: 'this identity runs inside its pod server and has no portable credential — attach from a standalone agent' });
123
- }
124
- const named = !!String(body.handle || '').trim();
125
- let handle = String(body.handle || cfg.handle || '').toLowerCase().trim();
126
- if (!handle) return json(res, 400, { error: 'a name at the gateway is required' });
127
- const fronted = body.fronted === true;
128
- // Availability first, for a clean answer before anything is created.
129
- const avail = async (h) => fetch(`${front}/api/handle?handle=${encodeURIComponent(h)}`,
130
- { headers: { accept: 'application/json' } }).then((r) => r.json()).catch(() => null);
131
- let chk = await avail(handle);
132
- if (!chk) return json(res, 502, { error: `${front} did not answer its handle check` });
133
- // An unnamed door name is plumbing nobody reads: walk to a free
134
- // variant instead of failing over a label the user never chose.
135
- if (!chk.available && !named) {
136
- for (let i = 2; i <= 9 && !chk.available; i++) {
137
- const cand = `${handle}${i}`;
138
- const c = await avail(cand);
139
- if (c?.available) { handle = cand; chk = c; }
140
- }
141
- }
142
- if (!chk.available) return json(res, 409, { error: chk.reason || `the name ${handle} is taken at ${front}` });
143
- const frontActor = `${front}/u/${handle}/ap/actor`;
144
- if (g.frontActor && (!fronted || g.frontActor !== frontActor)) {
145
- return json(res, 400, { error: `this identity already fronts through ${g.frontActor} — changing a published front renames every id; detach first if you mean it` });
146
- }
147
- const attach = await agent.remote.session.fetch(`${front}/api/attach`, {
148
- method: 'POST', headers: { 'content-type': 'application/json' },
149
- body: JSON.stringify({ handle, podHome: agent.urls.home, kind: cfg.kind || 'person', fronted }),
150
- }).catch(() => null);
151
- if (!attach) return json(res, 502, { error: `${front} did not answer the attach` });
152
- const d = await attach.json().catch(() => ({}));
153
- if (attach.status !== 201) {
154
- return json(res, attach.status >= 400 && attach.status < 500 ? attach.status : 502,
155
- { error: d.error || `attach failed (HTTP ${attach.status})` });
156
- }
157
- g.url = String(d.doorInbox || `${front}/u/${handle}/ap/inbox/`);
158
- if (d.hmacSecret) g.hmacSecret = String(d.hmacSecret);
159
- if (fronted) g.frontActor = String(d.frontActor || frontActor);
160
- if (!g.mode || g.mode === 'off') g.mode = 'shadow';
161
- await persist();
162
- // Inbox-only applies live: the actor republishes advertising the
163
- // door. A front carries new ids, which are wired at startup — so a
164
- // fronted attach restarts this agent itself, the reply going out
165
- // first so it is not taken down with the process.
166
- if (!fronted) {
167
- await agent.publisher?.publishProfile();
168
- await agent.publisher?.publishGatewayPolicy?.().catch(() => {});
169
- return json(res, 200, { ok: true, mode: g.mode, url: g.url });
170
- }
171
- await restampKeys(g.frontActor);
172
- json(res, 200, { ok: true, mode: g.mode, url: g.url,
173
- frontActor: g.frontActor, address: d.address || null, restarting: true });
174
- selfRestart('restarting to publish under the front');
175
- return true;
176
- }
177
- if (body.action === 'forget') {
178
- const wasLocked = g.mode === 'locked';
179
- const wasFronted = !!g.frontActor;
180
- delete cfg.gateway; agent.store.setConfig(cfg);
181
- if (agent.publisher) agent.publisher.config.gateway = undefined;
182
- await agent.store.flush();
183
- if (wasLocked && inboxUrl) await agent.remote.setAcl(inboxUrl, ['Append']).catch(() => {});
184
- if (wasFronted) {
185
- // Going home renames every id back to the pod: key and process
186
- // follow, the same way attach came.
187
- await restampKeys(podActorId());
188
- json(res, 200, { ok: true, mode: 'off', forgotten: true, restarting: true });
189
- selfRestart('restarting under the pod\'s own ids');
190
- return true;
191
- }
192
- await agent.publisher?.publishProfile(); // re-advertise the pod inbox
193
- return json(res, 200, { ok: true, mode: 'off', forgotten: true });
194
- }
195
- return json(res, 400, { error: 'action must be configure, mode, check, attach or forget' });
196
- }
197
- default: return false;
198
- }
199
- }