fedipod-server 0.29.0 → 0.31.0

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