fedipod-server 0.28.1 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (438) hide show
  1. package/README.md +38 -34
  2. package/config/server.json +22 -0
  3. package/dist/claims.js +3 -2
  4. package/dist/directory.d.ts +2 -0
  5. package/dist/door.d.ts +4 -0
  6. package/dist/door.js +31 -0
  7. package/dist/fedipod.d.ts +16 -0
  8. package/dist/fedipod.js +13 -0
  9. package/dist/front.d.ts +3 -0
  10. package/dist/front.js +94 -0
  11. package/dist/handler.d.ts +39 -101
  12. package/dist/handler.js +86 -617
  13. package/dist/handler.jsonld +6 -30
  14. package/dist/identities.d.ts +62 -0
  15. package/dist/identities.js +236 -0
  16. package/dist/mounts.d.ts +43 -0
  17. package/dist/mounts.js +123 -0
  18. package/dist/opt-in.d.ts +46 -0
  19. package/dist/opt-in.js +176 -0
  20. package/dist/store-pod.js +37 -0
  21. package/package.json +10 -18
  22. package/lib/client/c2s.mjs +0 -582
  23. package/lib/client/localapi.mjs +0 -87
  24. package/lib/client/masto/accounts.mjs +0 -309
  25. package/lib/client/masto/body.mjs +0 -156
  26. package/lib/client/masto/index.mjs +0 -206
  27. package/lib/client/masto/instance.mjs +0 -112
  28. package/lib/client/masto/media.mjs +0 -79
  29. package/lib/client/masto/oauth.mjs +0 -656
  30. package/lib/client/masto/render.mjs +0 -518
  31. package/lib/client/masto/statuses.mjs +0 -372
  32. package/lib/client/masto/timelines.mjs +0 -438
  33. package/lib/client/oidc-auth.mjs +0 -62
  34. package/lib/client/streaming.mjs +0 -154
  35. package/lib/client/webpush.mjs +0 -98
  36. package/lib/connections/acctfeed.mjs +0 -257
  37. package/lib/connections/atproto.mjs +0 -309
  38. package/lib/connections/bskyfeed.mjs +0 -243
  39. package/lib/connections/bskygroup.mjs +0 -162
  40. package/lib/connections/fediacct.mjs +0 -253
  41. package/lib/connections/import.mjs +0 -357
  42. package/lib/connections/tagfeed.mjs +0 -212
  43. package/lib/connections/vault.mjs +0 -114
  44. package/lib/core/as2.mjs +0 -206
  45. package/lib/core/contexts/activitystreams.json +0 -379
  46. package/lib/core/contexts/anno.json +0 -126
  47. package/lib/core/contexts/did-v1.json +0 -57
  48. package/lib/core/contexts/fep-5711.json +0 -36
  49. package/lib/core/contexts/gotosocial.json +0 -86
  50. package/lib/core/contexts/identity-v1.json +0 -152
  51. package/lib/core/contexts/index.mjs +0 -63
  52. package/lib/core/contexts/join-lemmy.json +0 -33
  53. package/lib/core/contexts/joinmastodon.json +0 -28
  54. package/lib/core/contexts/litepub-0.1.json +0 -60
  55. package/lib/core/contexts/map.json +0 -19
  56. package/lib/core/contexts/miscellany.json +0 -19
  57. package/lib/core/contexts/quotes.json +0 -18
  58. package/lib/core/contexts/schemaorg.json +0 -8845
  59. package/lib/core/contexts/security-data-integrity-v1.json +0 -78
  60. package/lib/core/contexts/security-data-integrity-v2.json +0 -81
  61. package/lib/core/contexts/security-multikey-v1.json +0 -35
  62. package/lib/core/contexts/security-v1.json +0 -74
  63. package/lib/core/contexts/webfinger.json +0 -10
  64. package/lib/core/deliver.mjs +0 -371
  65. package/lib/core/graphview.mjs +0 -327
  66. package/lib/core/intake/activities.mjs +0 -633
  67. package/lib/core/intake/activity.mjs +0 -318
  68. package/lib/core/intake/channel.mjs +0 -144
  69. package/lib/core/intake/group.mjs +0 -256
  70. package/lib/core/intake/index.mjs +0 -701
  71. package/lib/core/intake/notes.mjs +0 -360
  72. package/lib/core/intake/verify.mjs +0 -142
  73. package/lib/core/keys.mjs +0 -153
  74. package/lib/core/lease.mjs +0 -206
  75. package/lib/core/polls.mjs +0 -105
  76. package/lib/core/profile-page.mjs +0 -104
  77. package/lib/core/proof.mjs +0 -79
  78. package/lib/core/publisher/collections.mjs +0 -237
  79. package/lib/core/publisher/index.mjs +0 -500
  80. package/lib/core/publisher/notes.mjs +0 -453
  81. package/lib/core/publisher/questions.mjs +0 -239
  82. package/lib/core/publisher/restore.mjs +0 -224
  83. package/lib/core/shapes/activitystreams.ttl +0 -157
  84. package/lib/core/shapes/index.mjs +0 -132
  85. package/lib/core/shapes/shapes-text.mjs +0 -13
  86. package/lib/core/social.mjs +0 -531
  87. package/lib/core/storage.mjs +0 -176
  88. package/lib/core/store.mjs +0 -568
  89. package/lib/core/wire-quotes.mjs +0 -71
  90. package/lib/core/wire.mjs +0 -889
  91. package/lib/device/account.mjs +0 -87
  92. package/lib/device/admin/index.mjs +0 -13
  93. package/lib/device/admin/origins.mjs +0 -35
  94. package/lib/device/admin/routes/connections.mjs +0 -144
  95. package/lib/device/admin/routes/gateway.mjs +0 -199
  96. package/lib/device/admin/routes/lifecycle.mjs +0 -200
  97. package/lib/device/admin/routes/owner.mjs +0 -322
  98. package/lib/device/admin/routes/setup.mjs +0 -412
  99. package/lib/device/admin/routes/social.mjs +0 -188
  100. package/lib/device/admin/server.mjs +0 -95
  101. package/lib/device/admin/static.mjs +0 -247
  102. package/lib/device/admin/surface.mjs +0 -315
  103. package/lib/device/certs.mjs +0 -281
  104. package/lib/device/cli/commands/account.mjs +0 -586
  105. package/lib/device/cli/commands/run.mjs +0 -278
  106. package/lib/device/cli/commands/service.mjs +0 -221
  107. package/lib/device/cli/commands/setup.mjs +0 -447
  108. package/lib/device/cli/commands/state.mjs +0 -561
  109. package/lib/device/cli/context.mjs +0 -288
  110. package/lib/device/export-collections.mjs +0 -161
  111. package/lib/device/gateway-move.mjs +0 -58
  112. package/lib/device/home.mjs +0 -161
  113. package/lib/device/migrate.mjs +0 -115
  114. package/lib/device/ports.mjs +0 -27
  115. package/lib/device/remote.mjs +0 -54
  116. package/lib/device/setup.mjs +0 -459
  117. package/lib/device/update.mjs +0 -96
  118. package/lib/gateway/caches.mjs +0 -36
  119. package/lib/gateway/directory.mjs +0 -90
  120. package/lib/gateway/front-core.mjs +0 -970
  121. package/lib/gateway/gateway-core.mjs +0 -165
  122. package/lib/gateway/headers.mjs +0 -49
  123. package/lib/gateway/httpsig.mjs +0 -159
  124. package/lib/gateway/notices.mjs +0 -84
  125. package/lib/gateway/quiet.mjs +0 -189
  126. package/lib/pod/README.md +0 -61
  127. package/lib/pod/actor.mjs +0 -96
  128. package/lib/pod/collection.mjs +0 -77
  129. package/lib/pod/containers.mjs +0 -140
  130. package/lib/pod/discovery.mjs +0 -46
  131. package/lib/pod/featured.mjs +0 -18
  132. package/lib/pod/followers.mjs +0 -24
  133. package/lib/pod/following.mjs +0 -10
  134. package/lib/pod/http.mjs +0 -74
  135. package/lib/pod/inbox.mjs +0 -166
  136. package/lib/pod/links.mjs +0 -35
  137. package/lib/pod/media.mjs +0 -27
  138. package/lib/pod/notes.mjs +0 -80
  139. package/lib/pod/notifications.mjs +0 -89
  140. package/lib/pod/outbox.mjs +0 -18
  141. package/lib/pod/package.json +0 -19
  142. package/lib/pod/policy.mjs +0 -58
  143. package/lib/pod/private.mjs +0 -19
  144. package/lib/pod/root.mjs +0 -104
  145. package/lib/pod/state.mjs +0 -40
  146. package/lib/pod/transport.mjs +0 -525
  147. package/lib/pod/urls.mjs +0 -85
  148. package/lib/server/embed.mjs +0 -423
  149. package/lib/session/README.md +0 -137
  150. package/lib/session/demo.html +0 -94
  151. package/lib/session/fedi-account.mjs +0 -408
  152. package/lib/session/fedi-login.mjs +0 -123
  153. package/lib/session/oidc-session.mjs +0 -233
  154. package/lib/session/package.json +0 -49
  155. package/lib/shared/guard.mjs +0 -213
  156. package/lib/shared/links.mjs +0 -9
  157. package/lib/shared/safefetch.mjs +0 -235
  158. package/lib/shared/ua.mjs +0 -29
  159. package/phanpy/dist/404.html +0 -40
  160. package/phanpy/dist/_headers +0 -2
  161. package/phanpy/dist/apple-touch-icon.png +0 -0
  162. package/phanpy/dist/assets/ICONS-DIPJeU0C.js +0 -2
  163. package/phanpy/dist/assets/ICONS-DIPJeU0C.js.map +0 -1
  164. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js +0 -183
  165. package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js.map +0 -1
  166. package/phanpy/dist/assets/Temml-CCjoacWt.woff2 +0 -0
  167. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js +0 -2
  168. package/phanpy/dist/assets/__vite-browser-external-C7iut881.js.map +0 -1
  169. package/phanpy/dist/assets/boosts-carousel-BiOaNdMT.jpg +0 -0
  170. package/phanpy/dist/assets/catch-up-O5q5C75Z.png +0 -0
  171. package/phanpy/dist/assets/chunk-aKtaBQYM.js +0 -1
  172. package/phanpy/dist/assets/compose-CFEx7wb4.js +0 -2
  173. package/phanpy/dist/assets/compose-CFEx7wb4.js.map +0 -1
  174. package/phanpy/dist/assets/compose-ZJN5xSb4.js +0 -35
  175. package/phanpy/dist/assets/compose-ZJN5xSb4.js.map +0 -1
  176. package/phanpy/dist/assets/debug.module-YFQgwnIr.js +0 -52
  177. package/phanpy/dist/assets/debug.module-YFQgwnIr.js.map +0 -1
  178. package/phanpy/dist/assets/dom-p1YcJ5Rw.js +0 -2
  179. package/phanpy/dist/assets/dom-p1YcJ5Rw.js.map +0 -1
  180. package/phanpy/dist/assets/home-mobile-dark@2x-Dc-J8-SM.png +0 -0
  181. package/phanpy/dist/assets/home-mobile-light@2x-Bd3fod8m.png +0 -0
  182. package/phanpy/dist/assets/home-tablet-dark@2x-BgcNI8le.png +0 -0
  183. package/phanpy/dist/assets/home-tablet-light@2x-BW2RV9T6.png +0 -0
  184. package/phanpy/dist/assets/icons/add-circle-line-WD0mwORD.js +0 -1
  185. package/phanpy/dist/assets/icons/alert-line-CpFUMf9s.js +0 -1
  186. package/phanpy/dist/assets/icons/android-2-line-Bzxnrd3S.js +0 -1
  187. package/phanpy/dist/assets/icons/announcement-line-5nwaJFJm.js +0 -1
  188. package/phanpy/dist/assets/icons/arrow-down-circle-line-a7Id9-Iv.js +0 -1
  189. package/phanpy/dist/assets/icons/arrow-down-line-B8uzXzq6.js +0 -1
  190. package/phanpy/dist/assets/icons/arrow-left-line-CGrGT9C-.js +0 -1
  191. package/phanpy/dist/assets/icons/arrow-right-line-CE-HERfX.js +0 -1
  192. package/phanpy/dist/assets/icons/arrow-to-up-line-CvdQjmcy.js +0 -1
  193. package/phanpy/dist/assets/icons/arrow-up-circle-line-DEparSNF.js +0 -1
  194. package/phanpy/dist/assets/icons/arrow-up-line-C7yBeugc.js +0 -1
  195. package/phanpy/dist/assets/icons/arrows-right-line-BtbXmJGP.js +0 -1
  196. package/phanpy/dist/assets/icons/at-line-CF66Bznk.js +0 -1
  197. package/phanpy/dist/assets/icons/attachment-line-BY8It-l9.js +0 -1
  198. package/phanpy/dist/assets/icons/blockquote-line-BS6pU_hm.js +0 -1
  199. package/phanpy/dist/assets/icons/board-line-C0UWXyA6.js +0 -1
  200. package/phanpy/dist/assets/icons/bookmark-line-1CtX5JLF.js +0 -1
  201. package/phanpy/dist/assets/icons/building-5-line-Dd59MzbO.js +0 -1
  202. package/phanpy/dist/assets/icons/bus-2-line-6_dvA0GG.js +0 -1
  203. package/phanpy/dist/assets/icons/calendar-day-line-Crpl_fmu.js +0 -1
  204. package/phanpy/dist/assets/icons/calendar-month-line-vommts2C.js +0 -1
  205. package/phanpy/dist/assets/icons/calendar-time-add-line-BU_DTlQk.js +0 -1
  206. package/phanpy/dist/assets/icons/camera-line-Cv69MEei.js +0 -1
  207. package/phanpy/dist/assets/icons/celebrate-line-B8DvIoi0.js +0 -1
  208. package/phanpy/dist/assets/icons/chart-bar-line-FK-QOmtF.js +0 -1
  209. package/phanpy/dist/assets/icons/chart-line-line-BGcJAFWw.js +0 -1
  210. package/phanpy/dist/assets/icons/chat-3-line-YFK2-hwz.js +0 -1
  211. package/phanpy/dist/assets/icons/check-circle-line-DsAxFr5-.js +0 -1
  212. package/phanpy/dist/assets/icons/clipboard-line-BBp364gJ.js +0 -1
  213. package/phanpy/dist/assets/icons/close-circle-line-CICdiuGz.js +0 -1
  214. package/phanpy/dist/assets/icons/close-line-DYrFWcjv.js +0 -1
  215. package/phanpy/dist/assets/icons/cloud-line-tiQAbah8.js +0 -1
  216. package/phanpy/dist/assets/icons/code-line-fAl8iiV3.js +0 -1
  217. package/phanpy/dist/assets/icons/comment-2-line-CR3g7WeB.js +0 -1
  218. package/phanpy/dist/assets/icons/copy-2-line-CLW69yF5.js +0 -1
  219. package/phanpy/dist/assets/icons/delete-2-line-B8xmbr4n.js +0 -1
  220. package/phanpy/dist/assets/icons/document-3-line-DBGNhAg2.js +0 -1
  221. package/phanpy/dist/assets/icons/document-line-C7mb9sb7.js +0 -1
  222. package/phanpy/dist/assets/icons/down-line-BGqSSThd.js +0 -1
  223. package/phanpy/dist/assets/icons/edit-4-line-DcgGaEhx.js +0 -1
  224. package/phanpy/dist/assets/icons/emoji-2-line-D8YgnM-y.js +0 -1
  225. package/phanpy/dist/assets/icons/exit-line-Dc07BS-x.js +0 -1
  226. package/phanpy/dist/assets/icons/external-link-line-BvpSkmjO.js +0 -1
  227. package/phanpy/dist/assets/icons/eye-2-line-CiWXx-f_.js +0 -1
  228. package/phanpy/dist/assets/icons/eye-close-line-BgTaSJ4P.js +0 -1
  229. package/phanpy/dist/assets/icons/filter-2-line-B_mR2usy.js +0 -1
  230. package/phanpy/dist/assets/icons/filter-line-C_nm-3cU.js +0 -1
  231. package/phanpy/dist/assets/icons/flag-1-line-C2HB05I0.js +0 -1
  232. package/phanpy/dist/assets/icons/forbid-circle-line-D3LTT9yd.js +0 -1
  233. package/phanpy/dist/assets/icons/formula-line-DLrt2d6j.js +0 -1
  234. package/phanpy/dist/assets/icons/grid-line-CgUmEikf.js +0 -1
  235. package/phanpy/dist/assets/icons/group-line-C5fnX0wU.js +0 -1
  236. package/phanpy/dist/assets/icons/hand-finger-2-line-BGgxbuL9.js +0 -1
  237. package/phanpy/dist/assets/icons/hashtag-line-CyTEEXBb.js +0 -1
  238. package/phanpy/dist/assets/icons/heart-crack-line-BZddbO2C.js +0 -1
  239. package/phanpy/dist/assets/icons/heart-line-CJ7K47J4.js +0 -1
  240. package/phanpy/dist/assets/icons/history-2-line-kWWvFzqv.js +0 -1
  241. package/phanpy/dist/assets/icons/history-line-bGQiwbTH.js +0 -1
  242. package/phanpy/dist/assets/icons/home-3-line-fRU1zeLG.js +0 -1
  243. package/phanpy/dist/assets/icons/information-line-iNk6-sOY.js +0 -1
  244. package/phanpy/dist/assets/icons/keyboard-line-DsCyuQNz.js +0 -1
  245. package/phanpy/dist/assets/icons/layout-4-line-CZkOX52Z.js +0 -1
  246. package/phanpy/dist/assets/icons/layout-5-line-B_znt5wO.js +0 -1
  247. package/phanpy/dist/assets/icons/left-line-eUw0tya4.js +0 -1
  248. package/phanpy/dist/assets/icons/lightning-line-DaKoDdix.js +0 -1
  249. package/phanpy/dist/assets/icons/link-2-line-DCqLmMA7.js +0 -1
  250. package/phanpy/dist/assets/icons/list-check-line-BAxosBh9.js +0 -1
  251. package/phanpy/dist/assets/icons/lock-line-CPoaXeUW.js +0 -1
  252. package/phanpy/dist/assets/icons/mail-line-B0P8aa1L.js +0 -1
  253. package/phanpy/dist/assets/icons/moon-line-CEqNAToP.js +0 -1
  254. package/phanpy/dist/assets/icons/more-1-fill-Dw2e5xab.js +0 -1
  255. package/phanpy/dist/assets/icons/more-3-line-BIiVjYTz.js +0 -1
  256. package/phanpy/dist/assets/icons/notification-line-BZZq2Gtu.js +0 -1
  257. package/phanpy/dist/assets/icons/pencil-line-CKh8-A1v.js +0 -1
  258. package/phanpy/dist/assets/icons/photo-album-line-Bnfg2u40.js +0 -1
  259. package/phanpy/dist/assets/icons/pin-line-DpTolyhs.js +0 -1
  260. package/phanpy/dist/assets/icons/play-fill-B0-G_8lX.js +0 -1
  261. package/phanpy/dist/assets/icons/qrcode-2-line-B6SPCaHn.js +0 -1
  262. package/phanpy/dist/assets/icons/quill-pen-line-B6LUrnCP.js +0 -1
  263. package/phanpy/dist/assets/icons/quote-left-fill-hQZ1cj_6.js +0 -1
  264. package/phanpy/dist/assets/icons/radar-line-CKyroTth.js +0 -1
  265. package/phanpy/dist/assets/icons/react-line-CoIKhhtK.js +0 -1
  266. package/phanpy/dist/assets/icons/refresh-2-line-D0mTF97S.js +0 -1
  267. package/phanpy/dist/assets/icons/right-line-B3KWJaqc.js +0 -1
  268. package/phanpy/dist/assets/icons/rocket-line-4KZl537D.js +0 -1
  269. package/phanpy/dist/assets/icons/round-fill-C69NTrZ0.js +0 -1
  270. package/phanpy/dist/assets/icons/round-line-B9k_1uo-.js +0 -1
  271. package/phanpy/dist/assets/icons/route-line-B28ReHcE.js +0 -1
  272. package/phanpy/dist/assets/icons/rows-4-line-CrBniagM.js +0 -1
  273. package/phanpy/dist/assets/icons/scan-line-DSf74YdP.js +0 -1
  274. package/phanpy/dist/assets/icons/search-2-line-B6geIU1z.js +0 -1
  275. package/phanpy/dist/assets/icons/settings-3-line-azJwK47w.js +0 -1
  276. package/phanpy/dist/assets/icons/settings-6-line-C_5zc5YR.js +0 -1
  277. package/phanpy/dist/assets/icons/share-2-line-D5MxWjrm.js +0 -1
  278. package/phanpy/dist/assets/icons/share-forward-line-Cp61fZzZ.js +0 -1
  279. package/phanpy/dist/assets/icons/sparkles-2-line-DYYyXTaW.js +0 -1
  280. package/phanpy/dist/assets/icons/sparkles-line-C2hY1s6I.js +0 -1
  281. package/phanpy/dist/assets/icons/time-line-BF3eet1v.js +0 -1
  282. package/phanpy/dist/assets/icons/transfer-4-line-oisfvTBw.js +0 -1
  283. package/phanpy/dist/assets/icons/translate-line-BFWol2Ce.js +0 -1
  284. package/phanpy/dist/assets/icons/unlock-line-X_x5vwv3.js +0 -1
  285. package/phanpy/dist/assets/icons/upload-3-line-DgzwUJeW.js +0 -1
  286. package/phanpy/dist/assets/icons/user-4-line-BVSynZCp.js +0 -1
  287. package/phanpy/dist/assets/icons/user-add-2-line-BlGS5Q8q.js +0 -1
  288. package/phanpy/dist/assets/icons/user-add-line-BbXdHG4z.js +0 -1
  289. package/phanpy/dist/assets/icons/user-edit-line-BFAHOV0X.js +0 -1
  290. package/phanpy/dist/assets/icons/user-follow-line-BXux0wSd.js +0 -1
  291. package/phanpy/dist/assets/icons/user-star-line-DdYlpHLU.js +0 -1
  292. package/phanpy/dist/assets/icons/user-warning-line-Cj43j0_E.js +0 -1
  293. package/phanpy/dist/assets/icons/user-x-line-DIDgNlPH.js +0 -1
  294. package/phanpy/dist/assets/icons/volume-line-Bs390KQt.js +0 -1
  295. package/phanpy/dist/assets/icons/volume-mute-line-DzlzIqFZ.js +0 -1
  296. package/phanpy/dist/assets/icons/walk-line-yNXfB-md.js +0 -1
  297. package/phanpy/dist/assets/icons/world-2-line-CenkGIwj.js +0 -1
  298. package/phanpy/dist/assets/icons/zoom-in-line-CaENUphf.js +0 -1
  299. package/phanpy/dist/assets/icons/zoom-out-line-BDNk0EWo.js +0 -1
  300. package/phanpy/dist/assets/instances-BNPptnn-.json +0 -333
  301. package/phanpy/dist/assets/locales/ar-SA-CfheRbCu.js +0 -1
  302. package/phanpy/dist/assets/locales/ca-ES-DHRW86Tz.js +0 -1
  303. package/phanpy/dist/assets/locales/cs-CZ-CKoqEuA1.js +0 -1
  304. package/phanpy/dist/assets/locales/de-DE-ByRPMRFy.js +0 -1
  305. package/phanpy/dist/assets/locales/eo-UY-CPC7wLCS.js +0 -1
  306. package/phanpy/dist/assets/locales/es-ES-dJa0Fd9t.js +0 -1
  307. package/phanpy/dist/assets/locales/eu-ES-C3djlPR2.js +0 -1
  308. package/phanpy/dist/assets/locales/fa-IR-DTT490Ck.js +0 -1
  309. package/phanpy/dist/assets/locales/fi-FI-B23MCPuz.js +0 -1
  310. package/phanpy/dist/assets/locales/fr-FR-BcaQsO5C.js +0 -1
  311. package/phanpy/dist/assets/locales/gl-ES-BR-CVKBN.js +0 -1
  312. package/phanpy/dist/assets/locales/he-IL-CfheRbCu.js +0 -1
  313. package/phanpy/dist/assets/locales/hu-HU-CfheRbCu.js +0 -1
  314. package/phanpy/dist/assets/locales/it-IT-C1136UFV.js +0 -1
  315. package/phanpy/dist/assets/locales/ja-JP-CRZmRAhD.js +0 -1
  316. package/phanpy/dist/assets/locales/kab-Cz8xH_TT.js +0 -1
  317. package/phanpy/dist/assets/locales/ko-KR-CG9UiY4o.js +0 -1
  318. package/phanpy/dist/assets/locales/lt-LT-CJcI6sHZ.js +0 -1
  319. package/phanpy/dist/assets/locales/nb-NO-CfheRbCu.js +0 -1
  320. package/phanpy/dist/assets/locales/nl-NL-DxN4Yc1t.js +0 -1
  321. package/phanpy/dist/assets/locales/oc-FR-CfheRbCu.js +0 -1
  322. package/phanpy/dist/assets/locales/pl-PL-DkwGXf6P.js +0 -1
  323. package/phanpy/dist/assets/locales/pseudo-LOCALE-CQ4XxkQ0.js +0 -1
  324. package/phanpy/dist/assets/locales/pt-BR-nGL0HdFS.js +0 -1
  325. package/phanpy/dist/assets/locales/pt-PT-Cp17aj2z.js +0 -1
  326. package/phanpy/dist/assets/locales/ru-RU-0Y8cIoaK.js +0 -1
  327. package/phanpy/dist/assets/locales/th-TH-CfheRbCu.js +0 -1
  328. package/phanpy/dist/assets/locales/tok-CfheRbCu.js +0 -1
  329. package/phanpy/dist/assets/locales/tr-TR-CfheRbCu.js +0 -1
  330. package/phanpy/dist/assets/locales/uk-UA-C5E3dFBf.js +0 -1
  331. package/phanpy/dist/assets/locales/zh-CN-BHJi7_et.js +0 -1
  332. package/phanpy/dist/assets/locales/zh-TW-CfheRbCu.js +0 -1
  333. package/phanpy/dist/assets/main-BdqNbG-a.js +0 -26
  334. package/phanpy/dist/assets/main-BdqNbG-a.js.map +0 -1
  335. package/phanpy/dist/assets/mock-home-DGhR__He.js +0 -2
  336. package/phanpy/dist/assets/mock-home-DGhR__He.js.map +0 -1
  337. package/phanpy/dist/assets/multi-column-ROck0NVt.jpg +0 -0
  338. package/phanpy/dist/assets/multi-hashtag-timeline-DH5INVHi.jpg +0 -0
  339. package/phanpy/dist/assets/nested-comments-thread-hv59kZLc.jpg +0 -0
  340. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js +0 -2
  341. package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js.map +0 -1
  342. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js +0 -20
  343. package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js.map +0 -1
  344. package/phanpy/dist/assets/style-B1iLPTPR.css +0 -2
  345. package/phanpy/dist/assets/temml-DuyIQMei.js +0 -97
  346. package/phanpy/dist/assets/temml-DuyIQMei.js.map +0 -1
  347. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js +0 -2
  348. package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js.map +0 -1
  349. package/phanpy/dist/assets/year-in-posts-B2lywqdx.png +0 -0
  350. package/phanpy/dist/assets/year-in-posts-DJv_star.js +0 -3
  351. package/phanpy/dist/assets/year-in-posts-DJv_star.js.map +0 -1
  352. package/phanpy/dist/compose/index.html +0 -20
  353. package/phanpy/dist/favicon.ico +0 -0
  354. package/phanpy/dist/index.html +0 -73
  355. package/phanpy/dist/logo-192.png +0 -0
  356. package/phanpy/dist/logo-512.png +0 -0
  357. package/phanpy/dist/logo-badge-72.png +0 -0
  358. package/phanpy/dist/logo-maskable-512.png +0 -0
  359. package/phanpy/dist/logo-monochrome-512.png +0 -0
  360. package/phanpy/dist/logo-monochrome-maskable-512.png +0 -0
  361. package/phanpy/dist/manifest.webmanifest +0 -1
  362. package/phanpy/dist/og-image-2.jpg +0 -0
  363. package/phanpy/dist/og-image.png +0 -0
  364. package/phanpy/dist/robots.txt +0 -2
  365. package/phanpy/dist/sw.js +0 -2
  366. package/phanpy/dist/sw.js.map +0 -1
  367. package/phanpy/dist/version.json +0 -1
  368. package/run-agent.mjs +0 -897
  369. package/vendor/gate.cjs +0 -138
  370. package/vendor/idp-grant.cjs +0 -394
  371. package/vendor/jfetch.cjs +0 -16
  372. package/web/admin/actors.js +0 -145
  373. package/web/admin/bar.css +0 -126
  374. package/web/admin/bar.js +0 -99
  375. package/web/admin/client/client.js +0 -66
  376. package/web/admin/client/index.html +0 -69
  377. package/web/admin/client-pick.js +0 -79
  378. package/web/admin/common.js +0 -23
  379. package/web/admin/connections.js +0 -112
  380. package/web/admin/gateway.js +0 -133
  381. package/web/admin/group.js +0 -258
  382. package/web/admin/index.html +0 -603
  383. package/web/admin/notices-bar.js +0 -90
  384. package/web/admin/oauth-signin.mjs +0 -37
  385. package/web/admin/record.js +0 -390
  386. package/web/admin/setup/index.html +0 -241
  387. package/web/admin/setup/setup.js +0 -326
  388. package/web/admin/tokens.css +0 -68
  389. package/web/admin/upkeep.js +0 -177
  390. package/web/admin/window.css +0 -55
  391. package/web/admin/window.js +0 -136
  392. package/web/app/README.md +0 -81
  393. package/web/app/admin-facade.mjs +0 -588
  394. package/web/app/agent.mjs +0 -663
  395. package/web/app/atproto-browser.mjs +0 -86
  396. package/web/app/authorize_interaction.html +0 -56
  397. package/web/app/authorize_interaction.js +0 -69
  398. package/web/app/boot.mjs +0 -576
  399. package/web/app/deliver-relay.mjs +0 -129
  400. package/web/app/dist/boot.js +0 -34218
  401. package/web/app/dist/boot.js.map +0 -7
  402. package/web/app/dist/sw.js +0 -72810
  403. package/web/app/dist/sw.js.map +0 -7
  404. package/web/app/fediacct-browser.mjs +0 -146
  405. package/web/app/gateway-move.mjs +0 -60
  406. package/web/app/idb-kv.mjs +0 -35
  407. package/web/app/index.html +0 -242
  408. package/web/app/keys-browser.mjs +0 -71
  409. package/web/app/keystore.mjs +0 -82
  410. package/web/app/oidc-session.mjs +0 -6
  411. package/web/app/pod-auth.mjs +0 -248
  412. package/web/app/pod-remote.mjs +0 -84
  413. package/web/app/shims/_globals.mjs +0 -2
  414. package/web/app/shims/fedify-sig.mjs +0 -77
  415. package/web/app/shims/node-crypto.mjs +0 -113
  416. package/web/app/shims/node-fs.mjs +0 -17
  417. package/web/app/shims/node-path.mjs +0 -19
  418. package/web/app/shims/node-url.mjs +0 -7
  419. package/web/app/shims/prelude.js +0 -58
  420. package/web/app/shims/safefetch.mjs +0 -58
  421. package/web/app/shims/shapes-text.mjs +0 -8
  422. package/web/app/shims/web-push.mjs +0 -14
  423. package/web/app/signup.mjs +0 -318
  424. package/web/app/sw-src.mjs +0 -220
  425. package/web/app/update.js +0 -70
  426. package/web/front/admin.html +0 -55
  427. package/web/front/admin.js +0 -89
  428. package/web/front/install.sh +0 -69
  429. package/web/front/new-account.html +0 -35
  430. package/web/front/new-account.js +0 -13
  431. package/web/front/notices.html +0 -69
  432. package/web/front/notices.js +0 -107
  433. package/web/front/run.html +0 -58
  434. package/web/front/run.js +0 -195
  435. package/web/front/solid-oidc-client.js +0 -6
  436. package/web/icons/forum.svg +0 -11
  437. package/web/icons/gateway.svg +0 -14
  438. package/web/icons/local.svg +0 -11
package/web/app/boot.mjs DELETED
@@ -1,576 +0,0 @@
1
- // boot.mjs — the page side of the browser agent.
2
- //
3
- // Login is a Solid-OIDC redirect: the page sends you to your pod's login, and on
4
- // return the session is kept in IndexedDB (a non-extractable DPoP key + refresh
5
- // token, see oidc-session.mjs). The agent runs in the service worker, which reads
6
- // that same session from IndexedDB. So a returning visit restores silently, and
7
- // a new browser signs in with one redirect.
8
- //
9
- // New account: fedipodPodLogin({ issuer }) — sign in at the pod, and come
10
- // back to the identity screen; fedipodSignup(answers) then
11
- // sets the account up on that session and boots.
12
- // Move in: the same door, on a pod whose account lives at ANOTHER
13
- // gateway: the identity screen becomes a move, and
14
- // fedipodMoveIn(answers) brings the address here.
15
- // Returning: fedipodSignin({ address }) — redirect to the pod's login.
16
- // On every load: fedipodOnLoad() — finish a redirect, or restore, then boot.
17
- import { signUp, moveIn, readAccount, handleProblem, AP_ROOT } from './signup.mjs';
18
- import * as podActor from '../../lib/pod/actor.mjs';
19
- import * as podState from '../../lib/pod/state.mjs';
20
- import { podBaseOfWebId } from '../../lib/pod/urls.mjs';
21
- import { resourceExists } from '../../lib/pod/root.mjs';
22
- import { BrowserRemotePod } from './pod-remote.mjs';
23
- import { beginLogin, completeLogin, getSession, signOut } from './oidc-session.mjs';
24
- import { generateKeys, unwrapKeys, isKeyEnvelope } from './keystore.mjs';
25
- import { cacheOpenedKeys } from './keys-browser.mjs';
26
-
27
- const REDIRECT = `${location.origin}/`; // the app root doubles as the OIDC callback
28
-
29
- async function bootWorker({ reset = false } = {}) {
30
- const reg = await navigator.serviceWorker.register('/sw.js', { type: 'module' });
31
- await navigator.serviceWorker.ready;
32
- if (!navigator.serviceWorker.controller) {
33
- await new Promise((r) => navigator.serviceWorker.addEventListener('controllerchange', r, { once: true }));
34
- }
35
- const worker = reg.active || navigator.serviceWorker.controller;
36
- // A fresh login means a possibly different identity, and the worker may still
37
- // be holding the last one. Make it let go before it is asked to boot, and
38
- // wait for the acknowledgement — posting and racing on would let the boot
39
- // land while the old agent was still installed.
40
- if (reset) {
41
- await new Promise((res) => {
42
- const on = (e) => {
43
- if (e.data?.type !== 'reset-done') return;
44
- navigator.serviceWorker.removeEventListener('message', on);
45
- res();
46
- };
47
- navigator.serviceWorker.addEventListener('message', on);
48
- worker.postMessage({ type: 'reset' });
49
- setTimeout(res, 2000); // an older worker will not answer; boot anyway
50
- });
51
- }
52
- const booted = new Promise((res, rej) => {
53
- const on = (e) => {
54
- if (e.data?.type === 'booted') { navigator.serviceWorker.removeEventListener('message', on); res(); }
55
- if (e.data?.type === 'boot-error') { navigator.serviceWorker.removeEventListener('message', on); const err = new Error(e.data.error); err.detail = e.data.stack || ''; err.code = e.data.code || null; rej(err); }
56
- };
57
- navigator.serviceWorker.addEventListener('message', on);
58
- });
59
- worker.postMessage({ type: 'boot', frontOrigin: location.origin });
60
- await booted;
61
- }
62
-
63
- // An account made before 1.28.0, whose key on the pod is still under the
64
- // sign-up password. Since 1.28.0 the key is stored as it is, behind the pod's
65
- // own login, and a new browser reads it with its session (keys-browser.mjs).
66
- // One of these older accounts is opened once, with the password, and the key
67
- // is then written back as it is — so no browser ever asks again.
68
- //
69
- // The unwrap happens HERE, in the page, and not in the worker: the worker boots
70
- // itself whenever the browser restarts it, with nobody present to type anything.
71
- //
72
- // Both paths below read the account's config and key the same way: with the
73
- // session, as the owner, through the transport rather than the bare session —
74
- // a pod read like any other, with the retry ladder that exists because the pod
75
- // host throttles bursts.
76
- async function readAccountState() {
77
- const session = await getSession();
78
- if (!session) throw new Error('Sign in first.');
79
- const podFromWebId = podBaseOfWebId(session.webId); // a suffix-based host, or its own host
80
- const state = `${podFromWebId}${AP_ROOT}ap-state/`;
81
- const remote = new BrowserRemotePod(session, { webId: session.webId, role: 'signup', log: () => {} });
82
- const urls = { state };
83
- const [cfg, doc] = await Promise.all([
84
- podState.readConfig(remote, urls), podState.readKeys(remote, urls),
85
- ]);
86
- if (!cfg) throw new Error(`could not read this account's config under ${state}`);
87
- const actorUrl = `${cfg.remotePod}${cfg.root || AP_ROOT}ap/actor`;
88
- return { remote, urls, cfg, doc, actorUrl };
89
- }
90
-
91
- window.fedipodUnlock = async (password) => {
92
- if (!password) throw new Error('Enter your password.');
93
- const { remote, urls, doc, actorUrl } = await readAccountState();
94
- if (!doc) throw new Error('could not read this account\'s key on the pod');
95
- if (!isKeyEnvelope(doc)) throw new Error('this account\'s key is not under a password — nothing to unlock');
96
- const rec = await unwrapKeys(doc, password); // throws 'wrong password'
97
- // Stored as it is from here on: the next browser reads it with the pod
98
- // login and asks for nothing.
99
- await podState.writeKeys(remote, urls, rec);
100
- await cacheOpenedKeys(actorUrl, rec);
101
- await bootWorker();
102
- };
103
-
104
- // The same pane, for someone who no longer has the old password: a new key,
105
- // stored as it is, written over the pod's copy. Nothing is unwrapped, so the
106
- // old password is never needed. The boot that follows publishes the new public
107
- // key (agent.goActive → publishProfile).
108
- window.fedipodNewKey = async () => {
109
- const { remote, urls, cfg, actorUrl } = await readAccountState();
110
- const keys = await generateKeys();
111
- keys.mintedFor = cfg.gateway?.frontActor || actorUrl; // one key, one actor (signup.mjs)
112
- await podState.writeKeys(remote, urls, keys);
113
- await cacheOpenedKeys(actorUrl, keys);
114
- await bootWorker();
115
- };
116
-
117
- // New account, first half: sign in at the pod. The pod already exists — made
118
- // on the provider's own page, or brought — and its login is the only place
119
- // a password is ever typed. `returnTo` marks the way back as a sign-up, so
120
- // the load that follows shows the identity screen instead of booting.
121
- const SIGNUP_RETURN = 'signup';
122
- const issuerOf = (v) => { let s = String(v || '').trim(); if (!s) throw new Error('A pod provider is required.'); if (!/^https?:\/\//i.test(s)) s = 'https://' + s; return new URL(s).origin; };
123
- window.fedipodPodLogin = async ({ issuer }) => {
124
- const { authorizationUrl } = await beginLogin({ issuer: issuerOf(issuer), redirectUri: REDIRECT, returnTo: SIGNUP_RETURN });
125
- location.href = authorizationUrl;
126
- };
127
- // Second half, back on the session: key, config and gateway attach on the pod,
128
- // then the agent boots here. Nothing is typed and nothing leaves the browser
129
- // but pod writes on the session the pod itself issued.
130
- window.fedipodSignup = async ({ onStep, ...answers }) => {
131
- const session = await getSession();
132
- if (!session) throw new Error('Sign in at your pod first.');
133
- await signUp(answers, { session, onStep, frontOrigin: location.origin });
134
- await bootWorker({ reset: true });
135
- };
136
- // An account whose address lives at another gateway, moving here: the pod's
137
- // part (signup.mjs moveIn), then a boot under the new ids, which finishes
138
- // the move by telling the old gateway and the followers (gateway-move.mjs).
139
- window.fedipodMoveIn = async ({ onStep, ...answers }) => {
140
- const session = await getSession();
141
- if (!session) throw new Error('Sign in at your pod first.');
142
- await moveIn(answers, { session, onStep, frontOrigin: location.origin });
143
- await bootWorker({ reset: true });
144
- };
145
- // Set on the load that finds an account at another gateway; read by the
146
- // identity screen, which then offers a move instead of a new account.
147
- let moveFrom = null;
148
-
149
- // Returning / new browser: sign-in takes the full Fediverse address, @you@yourpod.
150
- // The host part IS the pod (a FediPod address lives at a host root), so the pod is
151
- // `https://<host>/`. The pod's actor says where to sign in; we fall back to the
152
- // host's parent domain when the pod does not answer. Everything else — the account
153
- // config and the key — is read from the pod on return.
154
- export function parseAddress(input) {
155
- let s = String(input || '').trim();
156
- if (s.startsWith('@')) s = s.slice(1); // @you@yourpod → you@yourpod
157
- const at = s.indexOf('@');
158
- if (at < 1) return null; // needs a handle and a host
159
- const handle = s.slice(0, at).toLowerCase();
160
- const host = s.slice(at + 1).toLowerCase().replace(/\/+$/, '');
161
- if (!handle || !host || !host.includes('.')) return null;
162
- return { handle, host };
163
- }
164
- async function issuerForPod(pod) {
165
- // The pod's actor says where a client signs in (oauthAuthorizationEndpoint's
166
- // origin); failing that, the account provider is the pod host's parent
167
- // domain for a subdomain pod, and the host itself for a pod on a path.
168
- try {
169
- const authz = await podActor.readIssuer(`${pod}${AP_ROOT}ap/actor`);
170
- if (authz) return new URL(authz).origin;
171
- } catch { /* fall through */ }
172
- const u = new URL(pod);
173
- if (u.pathname !== '/') return u.origin;
174
- const parent = u.host.split('.').slice(1).join('.');
175
- return `https://${parent || u.host}`;
176
- }
177
- // An address at this site names a fronted identity. Its documents live on a
178
- // pod this site's WebFinger names as an alias — the pod's own actor id.
179
- async function podForFrontedAddress(handle) {
180
- const res = await fetch(`/.well-known/webfinger?resource=${encodeURIComponent(`acct:${handle}@${location.host}`)}`,
181
- { headers: { accept: 'application/jrd+json, application/json' } }).catch(() => null);
182
- if (res?.status === 410) throw new Error(`@${handle}@${location.host} is closed: nothing on the pod behind it was touched, but the address is gone for good.`);
183
- if (!res || res.status >= 400) throw new Error(`nobody at this site is called @${handle}@${location.host}`);
184
- const doc = await res.json().catch(() => ({}));
185
- const podActorId = (doc.aliases || []).find((a) => /\/ap\/actor$/u.test(String(a)));
186
- if (!podActorId) throw new Error(`@${handle}@${location.host} lives here but names no pod to sign in to`);
187
- const tail = `${AP_ROOT}ap/actor`;
188
- if (!podActorId.endsWith(tail)) throw new Error(`the pod actor ${podActorId} is not where a FediPod pod keeps one`);
189
- return podActorId.slice(0, -tail.length);
190
- }
191
- window.fedipodSignin = async ({ address }) => {
192
- const parsed = parseAddress(address);
193
- if (!parsed) throw new Error('Enter your address as @you@yourpod (for example @alice@alice.solidcommunity.net).');
194
- const bad = handleProblem(parsed.handle);
195
- if (bad) throw new Error(bad);
196
- const pod = parsed.host === location.host.toLowerCase()
197
- ? await podForFrontedAddress(parsed.handle)
198
- : `https://${parsed.host}/`;
199
- const issuer = await issuerForPod(pod);
200
- const { authorizationUrl } = await beginLogin({ issuer, redirectUri: REDIRECT });
201
- location.href = authorizationUrl;
202
- };
203
-
204
- // Called on every page load. Returns 'signed-in' | 'restored' | 'anonymous' |
205
- // 'signup' | 'move-in' — the last two being a return from the pod's login
206
- // in the middle of creating an account: with no account on the pod yet, or
207
- // with one whose address lives at another gateway.
208
- window.fedipodOnLoad = async () => {
209
- if (new URLSearchParams(location.search).get('code')) {
210
- const done = await completeLogin({ currentUrl: location.href });
211
- history.replaceState({}, '', REDIRECT);
212
- if (done?.returnTo === SIGNUP_RETURN) {
213
- const here = await readAccount(done).catch(() => null);
214
- if (!here) return 'signup';
215
- // An address at ANOTHER gateway: "create an account" here is a move
216
- // in, not a second account. One at this gateway, or on the pod
217
- // itself, is a sign-in.
218
- if (here.frontHost && here.frontHost !== location.host) { moveFrom = here; return 'move-in'; }
219
- }
220
- await bootWorker({ reset: true }); // this may be a different account
221
- return 'signed-in';
222
- }
223
- if (await getSession()) { await bootWorker(); return 'restored'; }
224
- return 'anonymous';
225
- };
226
-
227
- window.fedipodSignOut = async () => {
228
- await signOut();
229
- // The client (Phanpy) keeps its own account and token in this origin's
230
- // localStorage, which outlives the OIDC sign-out and would silently sign you
231
- // back in as the same identity — so signing out has to clear it too.
232
- try { localStorage.clear(); sessionStorage.clear(); } catch { /* storage blocked */ }
233
- // The worker holds a connection to the connected-accounts store, so stop it
234
- // before deleting that store. Browser-stored Bluesky/fediverse keys are wiped
235
- // here; pod-stored ones stay on the pod and return when you sign in again.
236
- const reg = await navigator.serviceWorker.getRegistration(); await reg?.unregister();
237
- await new Promise((res) => {
238
- let req; try { req = indexedDB.deleteDatabase('fedipod-accounts'); } catch { res(); return; }
239
- req.onsuccess = req.onerror = req.onblocked = () => res();
240
- });
241
- };
242
- window.fedipodHandleProblem = handleProblem;
243
-
244
- // --- page UI wiring (runs only in the page, never the worker) ---
245
- //
246
- // Three ways in, matching the front page:
247
- // signed-in / restored session → straight to the feed (/app/)
248
- // have an account, new browser → type @you@yourpod, redirect to your pod's login
249
- // no account → "create an account" reveals the register form
250
- if (typeof document !== 'undefined') (async () => {
251
- const $ = (id) => document.getElementById(id);
252
- const params = new URLSearchParams(location.search);
253
- // Set by the load below and acted on at the end, once the form is wired:
254
- // the identity screen needs the step machine, which is built further down.
255
- let pendingIdentity = false;
256
-
257
- // --- unlock: this browser's first use of an account whose key is locked ---
258
- //
259
- // Wired FIRST, before anything that can leave this function early. Showing the
260
- // pane is one of those early exits, so registering the handler further down
261
- // meant the pane appeared with a dead button: the one browser that needs it is
262
- // the only one that never got it.
263
- const doUnlock = async () => {
264
- $('unlock-error').textContent = '';
265
- const btn = $('unlock-go'); btn.disabled = true;
266
- try {
267
- await window.fedipodUnlock($('unlock-password').value);
268
- $('unlock-password').value = '';
269
- location.href = '/admin/client/';
270
- } catch (err) {
271
- // 'wrong password' is what unwrapKeys throws on a failed AES-GCM auth,
272
- // which is the only way to tell a typo from a real problem.
273
- $('unlock-error').textContent = err.message || String(err);
274
- btn.disabled = false;
275
- $('unlock-password').select();
276
- }
277
- };
278
- $('unlock-go')?.addEventListener('click', doUnlock);
279
- $('unlock-password')?.addEventListener('keydown', (e) => { if (e.key === 'Enter') doUnlock(); });
280
- // The new-key path: one click reveals the confirmation, the second acts.
281
- $('unlock-newkey')?.addEventListener('click', () => {
282
- $('unlock-newkey-confirm').hidden = false;
283
- $('unlock-password').focus();
284
- });
285
- const doNewKey = async () => {
286
- $('unlock-error').textContent = '';
287
- const btn = $('unlock-newkey-go'); btn.disabled = true;
288
- try {
289
- await window.fedipodNewKey();
290
- $('unlock-password').value = '';
291
- location.href = '/admin/client/';
292
- } catch (err) {
293
- $('unlock-error').textContent = err.message || String(err);
294
- btn.disabled = false;
295
- }
296
- };
297
- $('unlock-newkey-go')?.addEventListener('click', doNewKey);
298
-
299
-
300
- // The client shell's bar returns here for two things, and neither continues
301
- // into the client: `?signout` clears the FediPod session, the client's stored
302
- // account, and the worker on this browser; `?add` comes back to reach a
303
- // different pod (signing in anew replaces the session). Both show the sign-in
304
- // page.
305
- if (params.has('signout') || params.has('add')) {
306
- if (params.has('signout')) { try { await window.fedipodSignOut(); } catch { /* nothing to tear down */ } }
307
- history.replaceState({}, '', '/');
308
- $('loading').hidden = true;
309
- $('landing').hidden = false;
310
- } else {
311
- let state = 'anonymous';
312
- try { state = await window.fedipodOnLoad(); }
313
- catch (e) {
314
- // A browser that has never opened this account's key is not a failure —
315
- // it is the ordinary state of a NEW browser, and the answer is a password
316
- // field rather than a stack trace. Everything else falls through below.
317
- if (e.code === 'key-password-needed') {
318
- $('loading').hidden = true; $('hero').hidden = true; $('landing').hidden = true;
319
- $('brand').hidden = false; $('unlock').hidden = false;
320
- $('unlock-password').focus();
321
- return;
322
- }
323
- // We logged in (or had a saved session) but the agent could not start.
324
- // What the agent could name. Most of these the page can act on ITSELF,
325
- // and does: a sign-in the pod will not take is renewed (and, if the
326
- // renewal is refused too, taken back to the pod's own login), and a pod
327
- // that was busy or unreachable is asked again on a timer. Nobody is
328
- // asked to press a button to find out what happened, and nobody is left
329
- // pressing Reload by hand. A button is still there for whoever does not
330
- // want to wait — and for the failures where waiting would not help.
331
- //
332
- // Each automatic step happens ONCE per tab (`once` below): a renewal
333
- // that comes back refused, or a retry that fails the same way, means
334
- // something the page cannot fix, and the reader gets the message rather
335
- // than a loop.
336
- const once = (key) => {
337
- try {
338
- if (sessionStorage.getItem(key)) return false;
339
- sessionStorage.setItem(key, '1');
340
- return true;
341
- } catch { return false; } // no storage: never automatic, always the button
342
- };
343
- const reload = () => location.reload();
344
- const signIn = () => { location.href = '/?add'; };
345
- const known = {
346
- 'sign-in-refused': { title: 'Your pod refused this sign-in', retry: 'Sign in again', go: signIn },
347
- 'pod-busy': { title: 'Your pod is asking for a pause', retry: 'Reload', go: reload, wait: 45 },
348
- 'pod-error': { title: 'Your pod had an error', retry: 'Reload', go: reload, wait: 20 },
349
- 'pod-unreachable': { title: 'Your pod could not be reached', retry: 'Reload', go: reload, wait: 20 },
350
- // A session with no account behind it is a sign-up that has not
351
- // happened yet — the person who closed the tab between the pod's
352
- // login and the identity screen lands here.
353
- 'no-account-here': { title: 'No FediPod account in that pod', retry: 'Create one on this pod', go: () => showIdentity() },
354
- 'no-account': { title: 'No FediPod account in that pod', retry: 'Create one on this pod', go: () => showIdentity() },
355
- 'device-account': { title: 'This account is run from a device', retry: 'Use another pod', go: signIn },
356
- 'address-closed': { title: 'This address is closed', retry: 'Sign in with another account', go: signIn },
357
- }[e.code];
358
-
359
- // A sign-in the pod would not take: renew it here, and if the pod will
360
- // not renew it either, go to the pod's own login. Both without asking.
361
- if (e.code === 'sign-in-refused' && once('fedipod-renewing')) {
362
- $('loading').hidden = true; $('hero').hidden = true; $('landing').hidden = true;
363
- $('brand').hidden = false; $('running').hidden = false;
364
- $('running-title').textContent = 'Renewing your sign-in';
365
- // Not red: nothing has gone wrong for the reader yet, something is
366
- // being done about it. The pane is shared with the real failures,
367
- // which keep the alarm colouring.
368
- $('run-error').style.color = 'var(--sub)';
369
- $('run-error').style.borderLeftColor = 'var(--line)';
370
- $('run-error').textContent = 'Your pod would not take the sign-in this browser is holding. Renewing it now.';
371
- $('run-actions').hidden = true;
372
- const session = await getSession().catch(() => null);
373
- if (session) {
374
- try {
375
- await session.refresh();
376
- location.reload(); // renewed: boot again with it
377
- return;
378
- } catch { /* the pod will not renew it either: its login is the only way */ }
379
- try {
380
- const { authorizationUrl } = await beginLogin({ issuer: session.issuer, redirectUri: REDIRECT });
381
- location.href = authorizationUrl;
382
- return;
383
- } catch { /* cannot even reach the login: fall through and say so */ }
384
- }
385
- }
386
-
387
- console.error(e);
388
- $('loading').hidden = true; $('hero').hidden = true; $('landing').hidden = true;
389
- $('brand').hidden = false; $('running').hidden = false;
390
- $('running-title').textContent = known ? known.title : 'Signed in, but the agent could not start';
391
- $('run-error').style.whiteSpace = 'pre-wrap';
392
- $('run-error').textContent = (e.message || String(e)) + (!known && e.detail ? `\n\n${e.detail}` : '');
393
- $('run-actions').hidden = false;
394
- // The button that leads somewhere goes first. The pane is shared with the
395
- // sign-up flow, where "Start over" leads and "Try again" follows; here
396
- // the reader is being told what to do, so what to do is the first thing
397
- // under it.
398
- $('run-actions').prepend($('run-retry'));
399
- $('run-retry').textContent = known ? known.retry : 'Reload';
400
- $('run-retry').addEventListener('click', known ? known.go : reload);
401
- // Busy, broken or out of reach: the transport already climbed its own
402
- // retry ladder to get here, so this waits longer and asks once more by
403
- // itself. The button counts down so the wait is not a blank stare, and
404
- // pressing it goes now.
405
- if (known?.wait && once(`fedipod-waited-${e.code}`)) {
406
- let left = known.wait;
407
- const tick = () => {
408
- $('run-retry').textContent = left > 0 ? `Trying again in ${left}s` : 'Trying again…';
409
- if (left-- <= 0) { clearInterval(timer); location.reload(); }
410
- };
411
- const timer = setInterval(tick, 1000);
412
- tick();
413
- }
414
- $('run-back').textContent = 'Sign out'; $('run-back').addEventListener('click', async () => { try { await window.fedipodSignOut(); } catch {} location.href = '/'; });
415
- return;
416
- }
417
- // Into the client shell: the FediPod bar over the framed client (the same
418
- // web/admin surface as local). Its own script signs the framed client in on
419
- // a fresh session and forwards deep links on a returning one, so both a
420
- // fresh sign-in and a restored session land in the same place.
421
- if (state === 'signed-in' || state === 'restored') { location.href = '/admin/client/'; return; }
422
- // Back from the pod's login with no account there yet, or with one to
423
- // move here: the identity screen, once the form below is wired.
424
- if (state === 'signup' || state === 'move-in') pendingIdentity = true;
425
- else {
426
- // Anonymous: show the landing (sign-in address + create-account); form stays hidden.
427
- $('loading').hidden = true;
428
- $('landing').hidden = false;
429
- }
430
- }
431
-
432
- // Views. The register form stands alone: the marketing hero and the sign-in
433
- // landing give way to the short brand, so only "FediPod" and the form show.
434
- const showLanding = () => { $('pane-form').hidden = true; $('running').hidden = true; $('brand').hidden = true; $('hero').hidden = false; $('landing').hidden = false; };
435
- const showForm = () => { $('hero').hidden = true; $('landing').hidden = true; $('brand').hidden = false; $('pane-form').hidden = false; goStep(1); };
436
- // The identity screen, on a pod session: the pod is read off the WebID and
437
- // fixes what the form can offer (a path pod is fronted, no choice). For a
438
- // move in, the handle is the old one to start with, the address lives here
439
- // by definition, and the button says what it does.
440
- let signedPod = '';
441
- async function showIdentity() {
442
- const session = await getSession();
443
- if (!session) { showLanding(); return; }
444
- signedPod = podBaseOfWebId(session.webId);
445
- $('loading').hidden = true; $('hero').hidden = true; $('landing').hidden = true; $('running').hidden = true;
446
- $('brand').hidden = false; $('pane-form').hidden = false;
447
- $('signed-pod').textContent = signedPod;
448
- $('movein-note').hidden = !moveFrom;
449
- if (moveFrom) {
450
- $('movein-from').textContent = moveFrom.address;
451
- if (!f().handle.value) f().handle.value = moveFrom.config.handle;
452
- $('submit').textContent = 'Move your account here';
453
- }
454
- goStep(2);
455
- }
456
-
457
-
458
- // --- sign in: the full @you@yourpod address → redirect to your pod's login ---
459
- const doSignin = async () => {
460
- $('signin-error').textContent = '';
461
- try { await window.fedipodSignin({ address: $('signin-address').value }); }
462
- catch (err) { $('signin-error').textContent = err.message; }
463
- };
464
- $('signin').addEventListener('click', doSignin);
465
- $('signin-address').addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); doSignin(); } });
466
-
467
- // --- register form: two screens, the pod's login first, then the identity ---
468
- const f = () => $('form').elements;
469
- // The pod provider is a free-text URL; default and normalise to a scheme.
470
- // The provider is picked from the list, or typed under "Other…".
471
- const providerUrl = () => { let v = (f().provider.value || f().providerOther.value).trim(); if (!v) return ''; if (!/^https?:\/\//i.test(v)) v = 'https://' + v; return v; };
472
- const providerHost = () => { try { return new URL(providerUrl()).host; } catch { return ''; } };
473
- // Where a new pod is made: the provider's own sign-up page. Every provider
474
- // in the list runs Community Solid Server, whose page is at this path; a
475
- // typed provider gets its front page, which links to it.
476
- const registerUrl = () => {
477
- if (!providerHost()) return '';
478
- const origin = new URL(providerUrl()).origin;
479
- return f().provider.value ? `${origin}/.account/login/password/register/` : `${origin}/`;
480
- };
481
- // A pod on a suffix-based host cannot answer WebFinger, so its address
482
- // lives at this site; a pod at its own host root gets the choice. Known
483
- // from the signed-in pod, not guessed from the provider.
484
- const pathPod = () => { try { return new URL(signedPod).pathname !== '/'; } catch { return false; } };
485
- // A move between gateways is an address at a gateway: no choice either.
486
- const shape = () => ((pathPod() || moveFrom) ? 'front' : f().shape.value);
487
- const answers = () => ({ handle: f().handle.value.trim().toLowerCase(), shape: shape() });
488
- const previewAddr = () => {
489
- const handle = f().handle.value.trim().toLowerCase();
490
- let host = '';
491
- try { host = shape() === 'front' ? location.host : new URL(signedPod).host; } catch { host = ''; }
492
- $('preview').textContent = (handle && host) ? `@${handle}@${host}` : '@…@…';
493
- };
494
- // The shape choice is fixed for a path pod, and open for a host-root pod.
495
- // A path pod has no choice to make: the radios go away and the note says why.
496
- const applyShape = () => {
497
- const fixed = pathPod() || !!moveFrom;
498
- for (const r of f().shape) { if (fixed) r.checked = r.value === 'front'; }
499
- $('shape-group').hidden = fixed;
500
- $('shape-hint').hidden = !fixed || !!moveFrom; // a move explains itself in its own note
501
- };
502
- const applyMode = () => {
503
- const existing = f().mode.value === 'existing';
504
- $('newpod-field').hidden = existing;
505
- $('provider-other-field').hidden = f().provider.value !== '';
506
- const url = registerUrl();
507
- $('register-link').href = url || '#';
508
- $('register-link').textContent = providerHost() ? `Create your pod at ${providerHost()}` : 'Create your pod at your provider';
509
- };
510
- for (const el of $('form').elements) for (const evt of ['input', 'change']) el.addEventListener(evt, () => { applyMode(); applyShape(); previewAddr(); });
511
- applyMode();
512
-
513
- // Step machine: one screen at a time, each gated by its own validation.
514
- const STEP_IDS = ['step-1', 'step-2'];
515
- const FOCUS = { 1: 'provider', 2: 'handle' };
516
- const goStep = (n) => {
517
- STEP_IDS.forEach((id, i) => { $(id).hidden = i !== n - 1; });
518
- $('err-1').textContent = ''; $('form-error').textContent = '';
519
- if (n === 2) { applyShape(); previewAddr(); }
520
- if (FOCUS[n]) $(FOCUS[n]).focus();
521
- };
522
- const validateStep1 = () => {
523
- if (!providerHost()) return f().provider.value === '' ? 'A pod provider address is required under Other….' : 'A valid pod provider URL is required.';
524
- return null;
525
- };
526
- const validateStep2 = () => {
527
- const hp = window.fedipodHandleProblem(f().handle.value.trim().toLowerCase());
528
- if (hp) return `Fediverse handle: ${hp}`;
529
- return null;
530
- };
531
- $('create').addEventListener('click', showForm);
532
- $('cancel').addEventListener('click', () => { showLanding(); goStep(1); });
533
- // Off to the pod's login. The identity screen is shown by the load that
534
- // brings the person back (fedipodOnLoad → 'signup').
535
- $('to-2').addEventListener('click', async () => {
536
- const e = validateStep1(); if (e) { $('err-1').textContent = e; return; }
537
- $('err-1').textContent = ''; $('to-2').disabled = true;
538
- try { await window.fedipodPodLogin({ issuer: providerUrl() }); }
539
- catch (err) { $('err-1').textContent = err.message || String(err); $('to-2').disabled = false; }
540
- });
541
- $('back-1').addEventListener('click', () => goStep(1));
542
-
543
- // From the setup screen back to the form (a failed run) or the landing.
544
- const backToForm = (errMsg) => {
545
- $('running').hidden = true; $('brand').hidden = false; $('pane-form').hidden = false;
546
- goStep(2);
547
- if (errMsg) $('form-error').textContent = errMsg; // remind them what failed
548
- };
549
- $('run-retry').addEventListener('click', () => backToForm($('run-error').textContent));
550
- $('run-back').addEventListener('click', () => { showLanding(); goStep(1); });
551
-
552
- const LABELS = { pod: 'Checking your pod', keys: 'Making your signing key', gateway: 'Connecting your mail door' };
553
- const MOVE_LABELS = { pod: 'Reading your account on your pod', gateway: 'Taking your address here', keys: 'Moving your key and account record' };
554
- $('form').addEventListener('submit', async (e) => {
555
- e.preventDefault(); $('form-error').textContent = '';
556
- const e2 = validateStep2(); if (e2) { $('form-error').textContent = e2; goStep(2); return; }
557
- const a = answers();
558
- $('pane-form').hidden = true; $('running').hidden = false;
559
- $('running-title').textContent = 'Setting up…'; $('run-error').textContent = ''; $('run-actions').hidden = true;
560
- const steps = $('steps'); steps.textContent = ''; const mark = {};
561
- const labels = moveFrom ? MOVE_LABELS : LABELS;
562
- const onStep = (k, st) => { if (!mark[k]) { const li = document.createElement('li'); steps.appendChild(li); mark[k] = li; } mark[k].textContent = (st === 'ok' ? '✓ ' : st === 'running' ? '… ' : '') + (labels[k] || k); };
563
- try {
564
- if (moveFrom) await window.fedipodMoveIn({ handle: a.handle, onStep });
565
- else await window.fedipodSignup({ ...a, onStep });
566
- location.href = '/admin/client/';
567
- }
568
- catch (err) {
569
- $('running-title').textContent = 'Setup did not finish';
570
- $('run-error').textContent = err.message || String(err);
571
- $('run-actions').hidden = false; // the way out of the failure screen
572
- }
573
- });
574
-
575
- if (pendingIdentity) await showIdentity();
576
- })();