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,90 +0,0 @@
1
- // notices-bar.js — the notices bell in the bar, on every page of ours.
2
- //
3
- // Whoever runs the site writes notices (the /notices page, admin only); every
4
- // signed-in account sees the bell. This asks /api/notices once per page load,
5
- // hides the bell where the site has none to offer (a DeviceAgent's own pages
6
- // answer no such thing), lists the titles, and opens one notice at a time.
7
- // Which notices this browser has already opened is this browser's business
8
- // alone, so it lives in localStorage and nowhere else.
9
- //
10
- // Every element here is declared in the page's markup; this fills them.
11
- (() => {
12
- const bell = document.getElementById('bar-notices');
13
- const list = document.getElementById('notices-list');
14
- const view = document.getElementById('notice-view');
15
- if (!bell || !list || !view) return;
16
- const $ = (id) => document.getElementById(id);
17
- const SEEN = 'fedipod-notices-seen';
18
- const readSeen = () => { try { return JSON.parse(localStorage.getItem(SEEN) || '[]'); } catch { return []; } };
19
- const writeSeen = (ids) => { try { localStorage.setItem(SEEN, JSON.stringify(ids.slice(-200))); } catch { /* keeps no site data */ } };
20
-
21
- const when = (iso) => { try { return new Date(iso).toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' }); } catch { return ''; } };
22
-
23
- // A notice's body is plain text: paragraphs at blank lines, and a bare
24
- // https link becomes a link. Nothing in it is ever read as markup.
25
- const renderBody = (el, text) => {
26
- el.textContent = '';
27
- for (const para of String(text || '').split(/\n\s*\n/u)) {
28
- const p = document.createElement('p');
29
- for (const part of para.split(/(https?:\/\/[^\s<>"']+)/u)) {
30
- if (/^https?:\/\//u.test(part)) {
31
- const a = document.createElement('a');
32
- a.href = part; a.textContent = part; a.target = '_blank'; a.rel = 'noopener';
33
- p.append(a);
34
- } else p.append(part);
35
- }
36
- el.append(p);
37
- }
38
- };
39
-
40
- let notices = [];
41
- const render = () => {
42
- const seen = new Set(readSeen());
43
- const fresh = notices.filter((n) => !seen.has(n.id)).length;
44
- $('bar-notices-count').textContent = fresh ? String(fresh) : '';
45
- bell.dataset.new = String(fresh);
46
- bell.setAttribute('aria-label', fresh ? `Notices, ${fresh} new` : 'Notices');
47
- const ul = $('notices-items');
48
- ul.textContent = '';
49
- if (!notices.length) {
50
- const p = document.createElement('p'); p.className = 'none'; p.textContent = 'No notices.';
51
- ul.append(p);
52
- return;
53
- }
54
- for (const n of notices) {
55
- const li = document.createElement('li');
56
- if (!seen.has(n.id)) li.classList.add('new');
57
- const b = document.createElement('button');
58
- b.type = 'button'; b.className = 'notice-open'; b.textContent = n.title;
59
- b.addEventListener('click', () => open(n));
60
- const w = document.createElement('span'); w.className = 'when'; w.textContent = when(n.at);
61
- li.append(b, w);
62
- ul.append(li);
63
- }
64
- };
65
-
66
- const open = (n) => {
67
- $('notice-view-title').textContent = n.title;
68
- $('notice-view-when').textContent = when(n.at);
69
- renderBody($('notice-view-body'), n.body);
70
- const seen = readSeen();
71
- if (!seen.includes(n.id)) { seen.push(n.id); writeSeen(seen); }
72
- render();
73
- list.close();
74
- view.showModal();
75
- };
76
-
77
- bell.addEventListener('click', () => { render(); list.showModal(); });
78
- $('notices-close').addEventListener('click', () => list.close());
79
- $('notice-view-close').addEventListener('click', () => { view.close(); list.showModal(); });
80
-
81
- fetch(location.origin + '/api/notices', { headers: { accept: 'application/json' } })
82
- .then((r) => (r.ok ? r.json() : null))
83
- .then((j) => {
84
- if (!j || !Array.isArray(j.notices)) return;
85
- notices = j.notices;
86
- render();
87
- bell.hidden = false;
88
- })
89
- .catch(() => { /* no site notices here; the bell stays hidden */ });
90
- })();
@@ -1,37 +0,0 @@
1
- // oauth-signin.mjs — a client asked this account to sign its owner in. The
2
- // owner signs in at their own pod, with the fediverse-account library, and the
3
- // page proves that sign-in to the account with one signed request; the account
4
- // then hands the client its code. No password of ours anywhere.
5
- import { fediLogin } from './fedi-login.mjs';
6
-
7
- const $ = (id) => document.getElementById(id);
8
- const say = (text, error = false) => { const s = $('signin-status'); s.textContent = text; s.setAttribute('role', error ? 'alert' : 'status'); };
9
- const webId = $('webid').href;
10
- const here = location.origin + location.pathname;
11
- const login = fediLogin({ dbName: 'fedipod-signin', clientName: 'FediPod sign-in', redirectUri: here });
12
-
13
- // Back from the pod: this finishes the sign-in and returns to the client's
14
- // request, which carries the client's own parameters.
15
- try { await login.resume(); } catch (e) { say(e.message, true); }
16
-
17
- async function prove() {
18
- const s = await login.getSession();
19
- if (!s) return false;
20
- if (s.webId !== webId) { say(`You signed in as ${s.webId}, but this account belongs to ${webId}. Sign out there and sign in as the owner.`, true); return true; }
21
- say('Signing you in…');
22
- const res = await s.fetch(here, {
23
- method: 'POST', headers: { 'content-type': 'application/x-www-form-urlencoded' },
24
- body: location.search.replace(/^\?/u, ''),
25
- });
26
- const d = await res.json().catch(() => ({}));
27
- if (res.ok && d.redirect) { location.href = d.redirect; return true; }
28
- if (res.ok && d.code) { say(`Your authorization code: ${d.code}`); return true; }
29
- say(d.error || `The account refused the sign-in (HTTP ${res.status}).`, true);
30
- return true;
31
- }
32
-
33
- if (location.search.includes('client_id=') && !(await prove())) $('signin').hidden = false;
34
- $('signin').addEventListener('click', async () => {
35
- say('Taking you to your pod…');
36
- try { await login.login(webId, { returnTo: location.href, redirectUri: here }); } catch (e) { say(e.message, true); }
37
- });
@@ -1,393 +0,0 @@
1
- // record.js — the record itself: what the page holds of the config, the
2
- // messages it says, every write, the load, the panels, and the rows of the
3
- // facts list with the identity rows and their controls.
4
- // admin.js — the record, as a page. Everything here is an existing admin
5
- // route; the CLI's own group commands are thin clients over the same ones.
6
- //
7
- // Two rules the routes enforce and this page respects: a write is a MERGE, so a
8
- // form that never mentions a field cannot delete it; and anything on the wire is
9
- // not real until the actor is republished, which POST /config does for itself.
10
- //
11
- // The UI password is deliberately not here — `fedipod passwd` sets it. It
12
- // only gates /oauth/authorize, so it does nothing for a loopback-only agent.
13
-
14
- let config = null;
15
- // Held, because render() moves it into a generated row and empties that row's
16
- // list on the next pass — after which getElementById would not find it again.
17
- const MODERATION = $('moderation');
18
- const STATUS = $('status-ctl');
19
- const STATUS_PICK = $('status-pick'); // held: getElementById can't see it mid-render
20
- const IDENT_CTL = $('ident-ctl');
21
- const FOLLOWS_CTL = $('follows-ctl');
22
- const FOLLOWS_PICK = $('follows-pick');
23
- const UPDATE_CTL = $('update-ctl');
24
- const UPDATE_WORD = $('update-word');
25
- const UPDATE_GO = $('update-go');
26
-
27
- // #say and #fatal live in the accessibility tree from load and hide by being
28
- // empty (see the stylesheet). Unhiding a live region and filling it in the same
29
- // task is the classic way to get no announcement at all.
30
- function say(text, cls = 'ok') {
31
- const el = $('say');
32
- el.className = cls;
33
- // Clear first, then set on the next task: a live region that is handed the
34
- // same text it already holds announces nothing, so two identical messages in
35
- // a row ("nothing changed", "nothing changed") would be silent the second time.
36
- el.textContent = '';
37
- setTimeout(() => { el.textContent = text; }, 30);
38
- }
39
-
40
- // Every write goes through here, so nothing silently half-succeeds.
41
- async function write(path, body, done) {
42
- const { status, json } = await postJson(path, body);
43
- if (status >= 400) { say(json?.error || `refused (HTTP ${status})`, 'err'); return null; }
44
- say(done);
45
- return json;
46
- }
47
-
48
- UPDATE_GO.onclick = async () => {
49
- UPDATE_GO.disabled = true;
50
- const r = await write('/update', {}, 'updating — the agents restart when it finishes; reload in a moment');
51
- if (!r) UPDATE_GO.disabled = false;
52
- };
53
-
54
- async function load() {
55
- const { status, json } = await api('/config');
56
- if (status === 409) {
57
- $('fatal').textContent = 'This agent has no identity yet.';
58
- const a = document.createElement('a');
59
- a.href = '/admin/setup/';
60
- a.textContent = ' Set it up.';
61
- $('fatal').appendChild(a);
62
- return;
63
- }
64
- // No agent answering on this browser: nobody is signed in here (the
65
- // worker answers 503 with no session, and nothing answers at all before
66
- // the worker exists). Say so, with the way on, rather than the reason.
67
- if (status === 503 || status === 404) {
68
- $('fatal').textContent = 'Not signed in on this browser. Sign in ';
69
- const a = document.createElement('a');
70
- a.href = '/';
71
- a.textContent = 'here';
72
- $('fatal').appendChild(a);
73
- $('fatal').appendChild(document.createTextNode('.'));
74
- return;
75
- }
76
- if (status !== 200 || !json) {
77
- $('fatal').textContent = json?.error || `could not read the record (HTTP ${status})`;
78
- return;
79
- }
80
- config = json;
81
- render();
82
- if (new URLSearchParams(location.search).has('new')) openNewActor();
83
- }
84
-
85
- // Every disclosure on the page — a form, the log, a lifecycle confirmation —
86
- // is a panel declared inside the floating window and shown by window.js. It
87
- // used to be an accordion at the foot of the page, which pushed whatever you
88
- // were reading out from under you and could only ever show one thing.
89
- //
90
- // The reset lives here rather than in window.js: the window knows how to show a
91
- // panel, not what any of them mean.
92
- function resetConfirm() {
93
- pending = null;
94
- for (const k of Object.keys(LIFECYCLE)) $(`warn-${k}`)?.hidden !== undefined && ($(`warn-${k}`).hidden = true);
95
- $('confirm-handle').value = '';
96
- $('confirm-handle-move').value = '';
97
- $('confirm-handle-close').value = '';
98
- $('move-target').value = '';
99
- }
100
- function closePanels(keep = null) {
101
- if (!keep) solWindow.close();
102
- if (keep !== 'output') outputSource = null;
103
- if (keep !== 'confirm-form') resetConfirm();
104
- }
105
- // Closing it by the ✕ or by Escape has to clear the same state a Cancel does.
106
- document.getElementById('win').addEventListener('win:closed', () => {
107
- outputSource = null;
108
- resetConfirm();
109
- $('bsky-password').value = ''; // never leave a secret in a closed panel
110
- });
111
-
112
-
113
- // One row per identity connected elsewhere, indented under the row that adds
114
- // them. Each carries its own way out: disconnecting one has nothing to do with
115
- // the others.
116
- function identityRows() {
117
- const out = [];
118
- const row = (label, ...nodes) => {
119
- const dt = document.createElement('dt');
120
- dt.className = 'under';
121
- dt.textContent = label;
122
- const dd = document.createElement('dd');
123
- dd.append(...nodes);
124
- out.push([dt, dd]);
125
- };
126
- // One descriptor shape for every connected account — Bluesky and each
127
- // fediverse account — so the row and its Options menu build the same way.
128
- const accounts = [];
129
- if (config.atproto?.connected) accounts.push({
130
- label: 'Bluesky', handle: `@${config.atproto.handle}`,
131
- href: `https://bsky.app/profile/${config.atproto.handle}`,
132
- storage: config.atproto.storage || null,
133
- feedPaused: 'feedPaused' in config.atproto ? config.atproto.feedPaused : null,
134
- crossPost: 'crossPost' in config.atproto ? config.atproto.crossPost : null,
135
- feed: (paused) => ['/atproto', { feedPaused: paused }],
136
- cross: (on) => ['/atproto', { crossPost: on }],
137
- store: (w) => ['/atproto', { storage: w }],
138
- off: () => ['/atproto/disconnect', {}],
139
- });
140
- for (const acct of config.fediAccounts || []) accounts.push({
141
- label: acct.host,
142
- handle: acct.needsReconnect ? `${acct.handle} — sign in again` : acct.handle,
143
- warn: acct.needsReconnect,
144
- storage: acct.storage || null,
145
- feedPaused: !acct.enabled,
146
- crossPost: null,
147
- feed: (paused) => ['/fediacct', { id: acct.id, enabled: !paused }],
148
- store: (w) => ['/fediacct', { id: acct.id, storage: w }],
149
- off: () => ['/fediacct/disconnect', { id: acct.id }],
150
- });
151
- for (const acct of accounts) {
152
- const name = document.createElement(acct.href ? 'a' : 'span');
153
- name.textContent = acct.handle;
154
- if (acct.href) { name.href = acct.href; name.target = '_blank'; name.rel = 'noopener'; name.title = ' Open this account elsewhere in a new tab'; }
155
- if (acct.warn) name.className = 'warn';
156
- // Where storage is a real choice (every browser-build account today), two
157
- // dropdowns sit in the row itself. Where it isn't (the Node agent's
158
- // Bluesky, which shows a cross-post toggle instead), the Options
159
- // disclosure it always has is unchanged.
160
- row(acct.label, name, ' ', ...(acct.storage ? connectionControls(acct) : [optionsMenu(acct)]));
161
- }
162
- return out;
163
- }
164
-
165
- // Connected, Paused or Disconnected, and where the key lives — one dropdown
166
- // each, in the row. Replaces the separate feed and connect dropdowns that used
167
- // to sit behind an Options disclosure; only reached where acct.storage is set.
168
- function connectionControls(acct) {
169
- const send = async ([path, payload], msg) => { if (await write(path, payload, msg)) await load(); };
170
- const pick = (opts, current, onChange, title) => {
171
- const el = document.createElement('select');
172
- if (title) el.title = title;
173
- for (const [v, t] of opts) { const o = document.createElement('option'); o.value = v; o.textContent = t; o.selected = v === current; el.appendChild(o); }
174
- el.addEventListener('change', () => onChange(el.value));
175
- return el;
176
- };
177
- const conn = pick(
178
- [['connected', 'Connected'], ['paused', 'Paused'], ['disconnected', 'Disconnected']],
179
- acct.feedPaused ? 'paused' : 'connected',
180
- (v) => (v === 'disconnected'
181
- ? send(acct.off(), 'disconnected')
182
- : send(acct.feed(v === 'paused'), v === 'paused' ? 'paused adding to your feed' : 'added to your home feed')),
183
- ' Connected feeds this account into your home feed here; Paused keeps the account but stops adding its posts; Disconnected removes it.');
184
- const storage = pick(
185
- [['pod', 'Store key on Pod'], ['browser', 'Store key in Browser']],
186
- acct.storage,
187
- (v) => {
188
- if (v === 'pod' && !confirm('Store this account on your pod?\n\nIt will follow you to any browser you sign in from — but a full-access token to that account then lives on your pod.')) { load(); return; }
189
- send(acct.store(v), v === 'pod' ? 'stored on your pod' : 'stored in this browser');
190
- },
191
- ' On your pod the key follows you to any browser you sign in from, and a full-access token then lives there; in this browser the token never leaves this device.');
192
- const wrap = document.createElement('span');
193
- wrap.className = 'conn-controls';
194
- wrap.append(conn, ' ', storage);
195
- return [wrap];
196
- }
197
-
198
- // Every connected account without a storage choice carries an Options menu
199
- // instead: pause its feed, its cross-post toggle (the Node agent's Bluesky),
200
- // disconnect.
201
- function optionsMenu(acct) {
202
- const d = document.createElement('details');
203
- d.className = 'opts';
204
- const sum = document.createElement('summary');
205
- sum.textContent = 'Options';
206
- d.appendChild(sum);
207
- const body = document.createElement('div');
208
- d.appendChild(body);
209
-
210
- // Each control is one dropdown whose options ARE the states, so it needs no
211
- // separate label — the chosen option reads as the current state.
212
- const pick = (opts, current, onChange) => {
213
- const el = document.createElement('select');
214
- for (const [v, t] of opts) { const o = document.createElement('option'); o.value = v; o.textContent = t; o.selected = v === current; el.appendChild(o); }
215
- el.addEventListener('change', () => onChange(el.value));
216
- body.appendChild(el);
217
- };
218
- const send = async ([path, payload], msg) => { if (await write(path, payload, msg)) await load(); };
219
-
220
- // Feed: shown in / hidden from the feed you read here.
221
- if (acct.feedPaused !== null) {
222
- pick([['show', 'Add to home feed'], ['hide', 'Pause adding to home feed']], acct.feedPaused ? 'hide' : 'show',
223
- (v) => send(acct.feed(v === 'hide'), v === 'hide' ? 'paused adding to your feed' : 'added to your home feed'));
224
- }
225
- // Storage where the browser offers the choice; the Node agent's Bluesky shows
226
- // its cross-post toggle in the same slot instead.
227
- if (acct.storage) {
228
- pick([['browser', 'Store key in Browser'], ['pod', 'Store key on Pod']], acct.storage, (v) => {
229
- if (v === 'pod' && !confirm('Store this account on your pod?\n\nIt will follow you to any browser you sign in from — but a full-access token to that account then lives on your pod.')) { load(); return; }
230
- send(acct.store(v), v === 'pod' ? 'stored on your pod' : 'stored in this browser');
231
- });
232
- } else if (acct.crossPost !== null) {
233
- pick([['on', 'Cross-post On'], ['off', 'Cross-post Off']], acct.crossPost ? 'on' : 'off',
234
- (v) => send(acct.cross(v === 'on'), ''));
235
- }
236
- // Connection: staying connected, or disconnecting.
237
- pick([['connected', 'Connected'], ['disconnect', 'Disconnect']], 'connected',
238
- (v) => { if (v === 'disconnect') send(acct.off(), 'disconnected'); else load(); });
239
-
240
- // The storage consequence, at the bottom of the box under every dropdown.
241
- if (acct.storage) {
242
- const hint = document.createElement('p'); hint.className = 'opt-hint';
243
- hint.textContent = acct.storage === 'pod'
244
- ? 'Follows you to every browser you sign in from; a full-access token lives on your pod.'
245
- : 'Stays in this browser; the token never leaves this device.';
246
- body.appendChild(hint);
247
- }
248
- return d;
249
- }
250
-
251
- function render() {
252
- // The bar names the actor, the same way on every page. Only the tab title is
253
- // this page's own business.
254
- document.title = `FediPod — ${config.handle}`;
255
- const facts = $('facts');
256
- facts.textContent = '';
257
- // What this actor IS comes first. The handle is already in the address beside
258
- // the heading; the pod, the issuer and the actor URL all read off the WebID;
259
- // and where the private half sits is not something you act on from here.
260
- const origins = config.origins || {};
261
- // Two of these are addresses of things you can open, so they are links. The
262
- // fediverse one goes to this actor's own page in the client, same origin, so
263
- // it stays in the tab. The Solid one leaves for the pod, so it does not.
264
- const rows = [
265
- ['kind', config.kind ? config.kind[0].toUpperCase() + config.kind.slice(1) : config.kind],
266
- // The value is the select itself — what it shows IS the state, and
267
- // changing the word is the whole action, like the moderation controls.
268
- ['status', 'ctl'],
269
- ['Fediverse identity', config.address || `@${config.handle} — no resolvable address`,
270
- config.accountId && config.address ? { href: `/admin/client/#/a/${config.accountId}` } : null],
271
- ['Solid identity', config.webId, config.remotePod ? { href: config.remotePod, blank: true } : null],
272
- // Where on the pod the account's data lives: the container its owner chose.
273
- ['stored at', config.remotePod && config.root ? config.remotePod + config.root : null,
274
- config.remotePod && config.root ? { href: config.remotePod + config.root, blank: true } : null],
275
- ['Other identities', 'ctl'],
276
- ['local store', config.home],
277
- // The address you actually open, not the bare number — the named origin when
278
- // there is one, since that is what the client and the OAuth redirect use. An
279
- // agent with no local host of its own (embedded in a pod server, or in a
280
- // browser) sends none, and then there is no row rather than a bare number.
281
- ['local host', (origins.named || origins.loopback || '').replace(/\/$/, '') || null],
282
- ];
283
- if (config.version || config.update || config.pendingUpgrade?.length) rows.push(['software', 'ctl']);
284
- rows.push(['gateway', 'ctl']);
285
- if (config.quiescedAt) rows.push(['parked since', config.quiescedAt]);
286
- if (config.movedTo) rows.push(['moved to', config.movedTo]);
287
- // A person gates followers here; a group's gate is the joins control on its
288
- // kind row, so the row would be a second switch for the same thing.
289
- if (config.kind !== 'group') rows.splice(2, 0, ['new followers', 'ctl']);
290
- // Rows that belong under the one being written, appended after it.
291
- let kids = null;
292
- for (const [k, v, link] of rows) {
293
- if (!v) continue;
294
- const dt = document.createElement('dt');
295
- dt.textContent = k;
296
- const dd = document.createElement('dd');
297
- if (link) {
298
- const a = document.createElement('a');
299
- a.href = link.href;
300
- a.textContent = v;
301
- if (link.blank) {
302
- a.target = '_blank';
303
- // noopener because the pod is another origin: without it the page we
304
- // open gets a handle on this one through window.opener.
305
- a.rel = 'noopener';
306
- a.title = ` Open ${link.href} in a new tab`;
307
- } else {
308
- a.title = ` This actor's page in our client`;
309
- }
310
- dd.appendChild(a);
311
- } else {
312
- dd.textContent = v;
313
- }
314
- // What a group can be moderated into is a property of BEING a group, so the
315
- // controls sit on the row that says so. Moved rather than built here: the
316
- // page still declares them, and `facts` is emptied on every render.
317
- if (k === 'kind' && config.kind === 'group') dd.append(MODERATION);
318
- if (k === 'status') {
319
- dd.textContent = '';
320
- dd.append(STATUS);
321
- STATUS.hidden = false;
322
- renderStatus();
323
- }
324
- if (k === 'new followers') {
325
- dd.textContent = '';
326
- dd.append(FOLLOWS_CTL);
327
- FOLLOWS_CTL.hidden = false;
328
- FOLLOWS_PICK.value = config.autoAcceptFollows ? 'auto' : 'approve';
329
- }
330
- if (k === 'gateway') {
331
- dd.textContent = '';
332
- dd.append(GATEWAY_CTL);
333
- refreshGateway();
334
- }
335
- if (k === 'software') {
336
- dd.textContent = '';
337
- dd.append(UPDATE_CTL);
338
- UPDATE_CTL.hidden = false;
339
- const u = config.update;
340
- // The version this agent is running, never the one sitting in the
341
- // checkout — saying otherwise would name a version nobody is serving.
342
- const running = config.version || u?.current || null;
343
- const words = [];
344
- if (running) words.push(u?.available ? `FediPod ${running} — ${u.latest} available` : `FediPod ${running}`);
345
- if (config.versionOnDisk && running && config.versionOnDisk !== running)
346
- words.push(`${config.versionOnDisk} is on disk — restart to run it`);
347
- if (config.pendingUpgrade?.length) words.push('older data layout — run `fedipod upgrade` in a terminal');
348
- UPDATE_WORD.textContent = words.join('; ');
349
- UPDATE_GO.hidden = !u?.available;
350
- }
351
- // The way to add one. Each account already connected is a row of its own
352
- // underneath, so this row stays the action and never becomes a list.
353
- if (k === 'Other identities') {
354
- dd.textContent = '';
355
- dd.append(IDENT_CTL);
356
- IDENT_CTL.hidden = false;
357
- kids = identityRows();
358
- }
359
- facts.append(dt, dd);
360
- if (kids) {
361
- for (const [ckt, ckd] of kids) facts.append(ckt, ckd);
362
- kids = null;
363
- }
364
- }
365
- if (!config.address) {
366
- const p = document.createElement('p');
367
- p.className = 'warn';
368
- p.textContent = `${config.remotePod} is a suffixed pod, so this actor cannot be `
369
- + 'discovered as a handle by other servers. Posting and reading still work.';
370
- $('pane-identity').appendChild(p);
371
- }
372
-
373
- // pane-others carries the create control too, so it appears even when this is
374
- // the only actor and even if /profiles cannot be read.
375
- for (const id of ['pane-others', 'pane-identity', 'rail']) $(id).hidden = false;
376
- renderAliases();
377
- renderOthers();
378
- renderInbox();
379
- if (config.kind === 'group') {
380
- // Its lists have no bound, so this page scrolls — see body.group in the CSS.
381
- document.body.classList.add('group');
382
- $('pane-group').hidden = false;
383
- MODERATION.hidden = false; // only a group has any
384
- renderGroupToggles();
385
- refreshGroup();
386
- } else {
387
- // A person has a follow-request queue too now: nothing binds an inbound
388
- // Follow to the actor it names, so one that cannot be verified waits here
389
- // rather than being accepted on the strength of who it claims to be.
390
- refreshRequests();
391
- }
392
- }
393
-