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,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
- }