fedipod-server 0.21.0 → 0.28.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 (332) hide show
  1. package/README.md +5 -4
  2. package/dist/claims.d.ts +3 -1
  3. package/dist/claims.js +20 -7
  4. package/dist/components/context.jsonld +6 -0
  5. package/dist/handler.d.ts +29 -1
  6. package/dist/handler.js +89 -4
  7. package/dist/handler.jsonld +36 -1
  8. package/lib/client/c2s.mjs +100 -3
  9. package/lib/client/masto/accounts.mjs +44 -4
  10. package/lib/client/masto/body.mjs +90 -3
  11. package/lib/client/masto/index.mjs +5 -1
  12. package/lib/client/masto/instance.mjs +11 -3
  13. package/lib/client/masto/media.mjs +3 -57
  14. package/lib/client/masto/oauth.mjs +66 -9
  15. package/lib/client/masto/render.mjs +62 -5
  16. package/lib/client/masto/statuses.mjs +25 -1
  17. package/lib/client/masto/timelines.mjs +128 -6
  18. package/lib/connections/tagfeed.mjs +42 -5
  19. package/lib/core/as2.mjs +36 -5
  20. package/lib/core/contexts/index.mjs +14 -0
  21. package/lib/core/contexts/litepub-0.1.json +60 -0
  22. package/lib/core/contexts/map.json +3 -1
  23. package/lib/core/contexts/quotes.json +18 -0
  24. package/lib/core/graphview.mjs +41 -3
  25. package/lib/core/intake/activities.mjs +136 -2
  26. package/lib/core/intake/activity.mjs +79 -1
  27. package/lib/core/intake/group.mjs +37 -3
  28. package/lib/core/intake/index.mjs +32 -2
  29. package/lib/core/intake/notes.mjs +60 -3
  30. package/lib/core/lease.mjs +12 -2
  31. package/lib/core/profile-page.mjs +104 -0
  32. package/lib/core/publisher/collections.mjs +6 -1
  33. package/lib/core/publisher/index.mjs +35 -17
  34. package/lib/core/publisher/notes.mjs +104 -3
  35. package/lib/core/shapes/activitystreams.ttl +28 -0
  36. package/lib/core/shapes/index.mjs +26 -1
  37. package/lib/core/wire-quotes.mjs +71 -0
  38. package/lib/core/wire.mjs +59 -103
  39. package/lib/device/admin/routes/lifecycle.mjs +9 -0
  40. package/lib/device/admin/static.mjs +4 -1
  41. package/lib/device/admin/surface.mjs +26 -2
  42. package/lib/device/certs.mjs +18 -2
  43. package/lib/device/cli/commands/setup.mjs +6 -2
  44. package/lib/device/cli/commands/state.mjs +3 -1
  45. package/lib/device/gateway-move.mjs +58 -0
  46. package/lib/device/migrate.mjs +3 -1
  47. package/lib/device/setup.mjs +67 -7
  48. package/lib/gateway/front-core.mjs +307 -36
  49. package/lib/gateway/gateway-core.mjs +15 -6
  50. package/lib/gateway/notices.mjs +84 -0
  51. package/lib/gateway/quiet.mjs +184 -0
  52. package/lib/pod/root.mjs +6 -3
  53. package/lib/pod/state.mjs +8 -7
  54. package/lib/pod/transport.mjs +5 -1
  55. package/lib/session/README.md +123 -0
  56. package/lib/session/demo.html +94 -0
  57. package/lib/session/fedi-account.mjs +346 -0
  58. package/lib/session/fedi-login.mjs +123 -0
  59. package/lib/session/oidc-session.mjs +233 -0
  60. package/lib/session/package.json +41 -0
  61. package/package.json +1 -1
  62. package/run-agent.mjs +28 -0
  63. package/vendor/gate.cjs +6 -3
  64. package/web/admin/bar.css +66 -0
  65. package/web/admin/bar.js +38 -0
  66. package/web/admin/client/index.html +31 -3
  67. package/web/admin/client-pick.js +79 -0
  68. package/web/admin/gateway.js +22 -0
  69. package/web/admin/index.html +54 -13
  70. package/web/admin/notices-bar.js +90 -0
  71. package/web/admin/oauth-signin.mjs +37 -0
  72. package/web/admin/record.js +13 -1
  73. package/web/admin/setup/index.html +31 -3
  74. package/web/admin/tokens.css +15 -3
  75. package/web/admin/upkeep.js +4 -5
  76. package/web/app/README.md +14 -10
  77. package/web/app/admin-facade.mjs +51 -12
  78. package/web/app/agent.mjs +157 -19
  79. package/web/app/authorize_interaction.html +56 -0
  80. package/web/app/authorize_interaction.js +69 -0
  81. package/web/app/boot.mjs +233 -95
  82. package/web/app/dist/boot.js +477 -569
  83. package/web/app/dist/boot.js.map +4 -4
  84. package/web/app/dist/sw.js +1861 -532
  85. package/web/app/dist/sw.js.map +4 -4
  86. package/web/app/gateway-move.mjs +60 -0
  87. package/web/app/index.html +40 -49
  88. package/web/app/keys-browser.mjs +12 -15
  89. package/web/app/keystore.mjs +19 -36
  90. package/web/app/oidc-session.mjs +5 -188
  91. package/web/app/signup.mjs +172 -132
  92. package/web/app/sw-src.mjs +1 -1
  93. package/web/app/update.js +66 -0
  94. package/web/front/admin.html +5 -3
  95. package/web/front/new-account.html +2 -2
  96. package/web/front/notices.html +69 -0
  97. package/web/front/notices.js +107 -0
  98. package/web/front/run.html +15 -8
  99. package/web/front/run.js +124 -36
  100. package/web/icons/forum.svg +11 -0
  101. package/web/icons/gateway.svg +14 -0
  102. package/web/icons/local.svg +11 -0
  103. package/web/app/index.html~ +0 -152
  104. package/web/app/site/_headers +0 -9
  105. package/web/app/site/_redirects +0 -22
  106. package/web/app/site/admin/actors.js +0 -145
  107. package/web/app/site/admin/bar.css +0 -60
  108. package/web/app/site/admin/bar.js +0 -61
  109. package/web/app/site/admin/client/client.js +0 -66
  110. package/web/app/site/admin/client/index.html +0 -43
  111. package/web/app/site/admin/common.js +0 -23
  112. package/web/app/site/admin/connections.js +0 -112
  113. package/web/app/site/admin/gateway.js +0 -111
  114. package/web/app/site/admin/group.js +0 -258
  115. package/web/app/site/admin/index.html +0 -564
  116. package/web/app/site/admin/record.js +0 -378
  117. package/web/app/site/admin/setup/index.html +0 -215
  118. package/web/app/site/admin/setup/setup.js +0 -326
  119. package/web/app/site/admin/tokens.css +0 -56
  120. package/web/app/site/admin/upkeep.js +0 -178
  121. package/web/app/site/admin/window.css +0 -55
  122. package/web/app/site/admin/window.js +0 -136
  123. package/web/app/site/app/404.html +0 -40
  124. package/web/app/site/app/_headers +0 -2
  125. package/web/app/site/app/apple-touch-icon.png +0 -0
  126. package/web/app/site/app/assets/ICONS-DIPJeU0C.js +0 -2
  127. package/web/app/site/app/assets/ICONS-DIPJeU0C.js.map +0 -1
  128. package/web/app/site/app/assets/ScheduledAtField-D-Abfo4J.js +0 -183
  129. package/web/app/site/app/assets/ScheduledAtField-D-Abfo4J.js.map +0 -1
  130. package/web/app/site/app/assets/Temml-CCjoacWt.woff2 +0 -0
  131. package/web/app/site/app/assets/__vite-browser-external-C7iut881.js +0 -2
  132. package/web/app/site/app/assets/__vite-browser-external-C7iut881.js.map +0 -1
  133. package/web/app/site/app/assets/boosts-carousel-BiOaNdMT.jpg +0 -0
  134. package/web/app/site/app/assets/catch-up-O5q5C75Z.png +0 -0
  135. package/web/app/site/app/assets/chunk-aKtaBQYM.js +0 -1
  136. package/web/app/site/app/assets/compose-CFEx7wb4.js +0 -2
  137. package/web/app/site/app/assets/compose-CFEx7wb4.js.map +0 -1
  138. package/web/app/site/app/assets/compose-ZJN5xSb4.js +0 -35
  139. package/web/app/site/app/assets/compose-ZJN5xSb4.js.map +0 -1
  140. package/web/app/site/app/assets/debug.module-YFQgwnIr.js +0 -52
  141. package/web/app/site/app/assets/debug.module-YFQgwnIr.js.map +0 -1
  142. package/web/app/site/app/assets/dom-p1YcJ5Rw.js +0 -2
  143. package/web/app/site/app/assets/dom-p1YcJ5Rw.js.map +0 -1
  144. package/web/app/site/app/assets/home-mobile-dark@2x-Dc-J8-SM.png +0 -0
  145. package/web/app/site/app/assets/home-mobile-light@2x-Bd3fod8m.png +0 -0
  146. package/web/app/site/app/assets/home-tablet-dark@2x-BgcNI8le.png +0 -0
  147. package/web/app/site/app/assets/home-tablet-light@2x-BW2RV9T6.png +0 -0
  148. package/web/app/site/app/assets/icons/add-circle-line-WD0mwORD.js +0 -1
  149. package/web/app/site/app/assets/icons/alert-line-CpFUMf9s.js +0 -1
  150. package/web/app/site/app/assets/icons/android-2-line-Bzxnrd3S.js +0 -1
  151. package/web/app/site/app/assets/icons/announcement-line-5nwaJFJm.js +0 -1
  152. package/web/app/site/app/assets/icons/arrow-down-circle-line-a7Id9-Iv.js +0 -1
  153. package/web/app/site/app/assets/icons/arrow-down-line-B8uzXzq6.js +0 -1
  154. package/web/app/site/app/assets/icons/arrow-left-line-CGrGT9C-.js +0 -1
  155. package/web/app/site/app/assets/icons/arrow-right-line-CE-HERfX.js +0 -1
  156. package/web/app/site/app/assets/icons/arrow-to-up-line-CvdQjmcy.js +0 -1
  157. package/web/app/site/app/assets/icons/arrow-up-circle-line-DEparSNF.js +0 -1
  158. package/web/app/site/app/assets/icons/arrow-up-line-C7yBeugc.js +0 -1
  159. package/web/app/site/app/assets/icons/arrows-right-line-BtbXmJGP.js +0 -1
  160. package/web/app/site/app/assets/icons/at-line-CF66Bznk.js +0 -1
  161. package/web/app/site/app/assets/icons/attachment-line-BY8It-l9.js +0 -1
  162. package/web/app/site/app/assets/icons/blockquote-line-BS6pU_hm.js +0 -1
  163. package/web/app/site/app/assets/icons/board-line-C0UWXyA6.js +0 -1
  164. package/web/app/site/app/assets/icons/bookmark-line-1CtX5JLF.js +0 -1
  165. package/web/app/site/app/assets/icons/building-5-line-Dd59MzbO.js +0 -1
  166. package/web/app/site/app/assets/icons/bus-2-line-6_dvA0GG.js +0 -1
  167. package/web/app/site/app/assets/icons/calendar-day-line-Crpl_fmu.js +0 -1
  168. package/web/app/site/app/assets/icons/calendar-month-line-vommts2C.js +0 -1
  169. package/web/app/site/app/assets/icons/calendar-time-add-line-BU_DTlQk.js +0 -1
  170. package/web/app/site/app/assets/icons/camera-line-Cv69MEei.js +0 -1
  171. package/web/app/site/app/assets/icons/celebrate-line-B8DvIoi0.js +0 -1
  172. package/web/app/site/app/assets/icons/chart-bar-line-FK-QOmtF.js +0 -1
  173. package/web/app/site/app/assets/icons/chart-line-line-BGcJAFWw.js +0 -1
  174. package/web/app/site/app/assets/icons/chat-3-line-YFK2-hwz.js +0 -1
  175. package/web/app/site/app/assets/icons/check-circle-line-DsAxFr5-.js +0 -1
  176. package/web/app/site/app/assets/icons/clipboard-line-BBp364gJ.js +0 -1
  177. package/web/app/site/app/assets/icons/close-circle-line-CICdiuGz.js +0 -1
  178. package/web/app/site/app/assets/icons/close-line-DYrFWcjv.js +0 -1
  179. package/web/app/site/app/assets/icons/cloud-line-tiQAbah8.js +0 -1
  180. package/web/app/site/app/assets/icons/code-line-fAl8iiV3.js +0 -1
  181. package/web/app/site/app/assets/icons/comment-2-line-CR3g7WeB.js +0 -1
  182. package/web/app/site/app/assets/icons/copy-2-line-CLW69yF5.js +0 -1
  183. package/web/app/site/app/assets/icons/delete-2-line-B8xmbr4n.js +0 -1
  184. package/web/app/site/app/assets/icons/document-3-line-DBGNhAg2.js +0 -1
  185. package/web/app/site/app/assets/icons/document-line-C7mb9sb7.js +0 -1
  186. package/web/app/site/app/assets/icons/down-line-BGqSSThd.js +0 -1
  187. package/web/app/site/app/assets/icons/edit-4-line-DcgGaEhx.js +0 -1
  188. package/web/app/site/app/assets/icons/emoji-2-line-D8YgnM-y.js +0 -1
  189. package/web/app/site/app/assets/icons/exit-line-Dc07BS-x.js +0 -1
  190. package/web/app/site/app/assets/icons/external-link-line-BvpSkmjO.js +0 -1
  191. package/web/app/site/app/assets/icons/eye-2-line-CiWXx-f_.js +0 -1
  192. package/web/app/site/app/assets/icons/eye-close-line-BgTaSJ4P.js +0 -1
  193. package/web/app/site/app/assets/icons/filter-2-line-B_mR2usy.js +0 -1
  194. package/web/app/site/app/assets/icons/filter-line-C_nm-3cU.js +0 -1
  195. package/web/app/site/app/assets/icons/flag-1-line-C2HB05I0.js +0 -1
  196. package/web/app/site/app/assets/icons/forbid-circle-line-D3LTT9yd.js +0 -1
  197. package/web/app/site/app/assets/icons/formula-line-DLrt2d6j.js +0 -1
  198. package/web/app/site/app/assets/icons/grid-line-CgUmEikf.js +0 -1
  199. package/web/app/site/app/assets/icons/group-line-C5fnX0wU.js +0 -1
  200. package/web/app/site/app/assets/icons/hand-finger-2-line-BGgxbuL9.js +0 -1
  201. package/web/app/site/app/assets/icons/hashtag-line-CyTEEXBb.js +0 -1
  202. package/web/app/site/app/assets/icons/heart-crack-line-BZddbO2C.js +0 -1
  203. package/web/app/site/app/assets/icons/heart-line-CJ7K47J4.js +0 -1
  204. package/web/app/site/app/assets/icons/history-2-line-kWWvFzqv.js +0 -1
  205. package/web/app/site/app/assets/icons/history-line-bGQiwbTH.js +0 -1
  206. package/web/app/site/app/assets/icons/home-3-line-fRU1zeLG.js +0 -1
  207. package/web/app/site/app/assets/icons/information-line-iNk6-sOY.js +0 -1
  208. package/web/app/site/app/assets/icons/keyboard-line-DsCyuQNz.js +0 -1
  209. package/web/app/site/app/assets/icons/layout-4-line-CZkOX52Z.js +0 -1
  210. package/web/app/site/app/assets/icons/layout-5-line-B_znt5wO.js +0 -1
  211. package/web/app/site/app/assets/icons/left-line-eUw0tya4.js +0 -1
  212. package/web/app/site/app/assets/icons/lightning-line-DaKoDdix.js +0 -1
  213. package/web/app/site/app/assets/icons/link-2-line-DCqLmMA7.js +0 -1
  214. package/web/app/site/app/assets/icons/list-check-line-BAxosBh9.js +0 -1
  215. package/web/app/site/app/assets/icons/lock-line-CPoaXeUW.js +0 -1
  216. package/web/app/site/app/assets/icons/mail-line-B0P8aa1L.js +0 -1
  217. package/web/app/site/app/assets/icons/moon-line-CEqNAToP.js +0 -1
  218. package/web/app/site/app/assets/icons/more-1-fill-Dw2e5xab.js +0 -1
  219. package/web/app/site/app/assets/icons/more-3-line-BIiVjYTz.js +0 -1
  220. package/web/app/site/app/assets/icons/notification-line-BZZq2Gtu.js +0 -1
  221. package/web/app/site/app/assets/icons/pencil-line-CKh8-A1v.js +0 -1
  222. package/web/app/site/app/assets/icons/photo-album-line-Bnfg2u40.js +0 -1
  223. package/web/app/site/app/assets/icons/pin-line-DpTolyhs.js +0 -1
  224. package/web/app/site/app/assets/icons/play-fill-B0-G_8lX.js +0 -1
  225. package/web/app/site/app/assets/icons/qrcode-2-line-B6SPCaHn.js +0 -1
  226. package/web/app/site/app/assets/icons/quill-pen-line-B6LUrnCP.js +0 -1
  227. package/web/app/site/app/assets/icons/quote-left-fill-hQZ1cj_6.js +0 -1
  228. package/web/app/site/app/assets/icons/radar-line-CKyroTth.js +0 -1
  229. package/web/app/site/app/assets/icons/react-line-CoIKhhtK.js +0 -1
  230. package/web/app/site/app/assets/icons/refresh-2-line-D0mTF97S.js +0 -1
  231. package/web/app/site/app/assets/icons/right-line-B3KWJaqc.js +0 -1
  232. package/web/app/site/app/assets/icons/rocket-line-4KZl537D.js +0 -1
  233. package/web/app/site/app/assets/icons/round-fill-C69NTrZ0.js +0 -1
  234. package/web/app/site/app/assets/icons/round-line-B9k_1uo-.js +0 -1
  235. package/web/app/site/app/assets/icons/route-line-B28ReHcE.js +0 -1
  236. package/web/app/site/app/assets/icons/rows-4-line-CrBniagM.js +0 -1
  237. package/web/app/site/app/assets/icons/scan-line-DSf74YdP.js +0 -1
  238. package/web/app/site/app/assets/icons/search-2-line-B6geIU1z.js +0 -1
  239. package/web/app/site/app/assets/icons/settings-3-line-azJwK47w.js +0 -1
  240. package/web/app/site/app/assets/icons/settings-6-line-C_5zc5YR.js +0 -1
  241. package/web/app/site/app/assets/icons/share-2-line-D5MxWjrm.js +0 -1
  242. package/web/app/site/app/assets/icons/share-forward-line-Cp61fZzZ.js +0 -1
  243. package/web/app/site/app/assets/icons/sparkles-2-line-DYYyXTaW.js +0 -1
  244. package/web/app/site/app/assets/icons/sparkles-line-C2hY1s6I.js +0 -1
  245. package/web/app/site/app/assets/icons/time-line-BF3eet1v.js +0 -1
  246. package/web/app/site/app/assets/icons/transfer-4-line-oisfvTBw.js +0 -1
  247. package/web/app/site/app/assets/icons/translate-line-BFWol2Ce.js +0 -1
  248. package/web/app/site/app/assets/icons/unlock-line-X_x5vwv3.js +0 -1
  249. package/web/app/site/app/assets/icons/upload-3-line-DgzwUJeW.js +0 -1
  250. package/web/app/site/app/assets/icons/user-4-line-BVSynZCp.js +0 -1
  251. package/web/app/site/app/assets/icons/user-add-2-line-BlGS5Q8q.js +0 -1
  252. package/web/app/site/app/assets/icons/user-add-line-BbXdHG4z.js +0 -1
  253. package/web/app/site/app/assets/icons/user-edit-line-BFAHOV0X.js +0 -1
  254. package/web/app/site/app/assets/icons/user-follow-line-BXux0wSd.js +0 -1
  255. package/web/app/site/app/assets/icons/user-star-line-DdYlpHLU.js +0 -1
  256. package/web/app/site/app/assets/icons/user-warning-line-Cj43j0_E.js +0 -1
  257. package/web/app/site/app/assets/icons/user-x-line-DIDgNlPH.js +0 -1
  258. package/web/app/site/app/assets/icons/volume-line-Bs390KQt.js +0 -1
  259. package/web/app/site/app/assets/icons/volume-mute-line-DzlzIqFZ.js +0 -1
  260. package/web/app/site/app/assets/icons/walk-line-yNXfB-md.js +0 -1
  261. package/web/app/site/app/assets/icons/world-2-line-CenkGIwj.js +0 -1
  262. package/web/app/site/app/assets/icons/zoom-in-line-CaENUphf.js +0 -1
  263. package/web/app/site/app/assets/icons/zoom-out-line-BDNk0EWo.js +0 -1
  264. package/web/app/site/app/assets/instances-BNPptnn-.json +0 -333
  265. package/web/app/site/app/assets/locales/ar-SA-CfheRbCu.js +0 -1
  266. package/web/app/site/app/assets/locales/ca-ES-DHRW86Tz.js +0 -1
  267. package/web/app/site/app/assets/locales/cs-CZ-CKoqEuA1.js +0 -1
  268. package/web/app/site/app/assets/locales/de-DE-ByRPMRFy.js +0 -1
  269. package/web/app/site/app/assets/locales/eo-UY-CPC7wLCS.js +0 -1
  270. package/web/app/site/app/assets/locales/es-ES-dJa0Fd9t.js +0 -1
  271. package/web/app/site/app/assets/locales/eu-ES-C3djlPR2.js +0 -1
  272. package/web/app/site/app/assets/locales/fa-IR-DTT490Ck.js +0 -1
  273. package/web/app/site/app/assets/locales/fi-FI-B23MCPuz.js +0 -1
  274. package/web/app/site/app/assets/locales/fr-FR-BcaQsO5C.js +0 -1
  275. package/web/app/site/app/assets/locales/gl-ES-BR-CVKBN.js +0 -1
  276. package/web/app/site/app/assets/locales/he-IL-CfheRbCu.js +0 -1
  277. package/web/app/site/app/assets/locales/hu-HU-CfheRbCu.js +0 -1
  278. package/web/app/site/app/assets/locales/it-IT-C1136UFV.js +0 -1
  279. package/web/app/site/app/assets/locales/ja-JP-CRZmRAhD.js +0 -1
  280. package/web/app/site/app/assets/locales/kab-Cz8xH_TT.js +0 -1
  281. package/web/app/site/app/assets/locales/ko-KR-CG9UiY4o.js +0 -1
  282. package/web/app/site/app/assets/locales/lt-LT-CJcI6sHZ.js +0 -1
  283. package/web/app/site/app/assets/locales/nb-NO-CfheRbCu.js +0 -1
  284. package/web/app/site/app/assets/locales/nl-NL-DxN4Yc1t.js +0 -1
  285. package/web/app/site/app/assets/locales/oc-FR-CfheRbCu.js +0 -1
  286. package/web/app/site/app/assets/locales/pl-PL-DkwGXf6P.js +0 -1
  287. package/web/app/site/app/assets/locales/pseudo-LOCALE-CQ4XxkQ0.js +0 -1
  288. package/web/app/site/app/assets/locales/pt-BR-nGL0HdFS.js +0 -1
  289. package/web/app/site/app/assets/locales/pt-PT-Cp17aj2z.js +0 -1
  290. package/web/app/site/app/assets/locales/ru-RU-0Y8cIoaK.js +0 -1
  291. package/web/app/site/app/assets/locales/th-TH-CfheRbCu.js +0 -1
  292. package/web/app/site/app/assets/locales/tok-CfheRbCu.js +0 -1
  293. package/web/app/site/app/assets/locales/tr-TR-CfheRbCu.js +0 -1
  294. package/web/app/site/app/assets/locales/uk-UA-C5E3dFBf.js +0 -1
  295. package/web/app/site/app/assets/locales/zh-CN-BHJi7_et.js +0 -1
  296. package/web/app/site/app/assets/locales/zh-TW-CfheRbCu.js +0 -1
  297. package/web/app/site/app/assets/main-BdqNbG-a.js +0 -26
  298. package/web/app/site/app/assets/main-BdqNbG-a.js.map +0 -1
  299. package/web/app/site/app/assets/mock-home-DGhR__He.js +0 -2
  300. package/web/app/site/app/assets/mock-home-DGhR__He.js.map +0 -1
  301. package/web/app/site/app/assets/multi-column-ROck0NVt.jpg +0 -0
  302. package/web/app/site/app/assets/multi-hashtag-timeline-DH5INVHi.jpg +0 -0
  303. package/web/app/site/app/assets/nested-comments-thread-hv59kZLc.jpg +0 -0
  304. package/web/app/site/app/assets/polyfill-force-H8sUkLGp.js +0 -2
  305. package/web/app/site/app/assets/polyfill-force-H8sUkLGp.js.map +0 -1
  306. package/web/app/site/app/assets/pwa-viewport-ogKbF51K.js +0 -20
  307. package/web/app/site/app/assets/pwa-viewport-ogKbF51K.js.map +0 -1
  308. package/web/app/site/app/assets/style-B1iLPTPR.css +0 -2
  309. package/web/app/site/app/assets/temml-DuyIQMei.js +0 -97
  310. package/web/app/site/app/assets/temml-DuyIQMei.js.map +0 -1
  311. package/web/app/site/app/assets/tinyld.light.node-DtbBhLYC.js +0 -2
  312. package/web/app/site/app/assets/tinyld.light.node-DtbBhLYC.js.map +0 -1
  313. package/web/app/site/app/assets/year-in-posts-B2lywqdx.png +0 -0
  314. package/web/app/site/app/assets/year-in-posts-DJv_star.js +0 -3
  315. package/web/app/site/app/assets/year-in-posts-DJv_star.js.map +0 -1
  316. package/web/app/site/app/compose/index.html +0 -20
  317. package/web/app/site/app/favicon.ico +0 -0
  318. package/web/app/site/app/index.html +0 -73
  319. package/web/app/site/app/logo-192.png +0 -0
  320. package/web/app/site/app/logo-512.png +0 -0
  321. package/web/app/site/app/logo-badge-72.png +0 -0
  322. package/web/app/site/app/logo-maskable-512.png +0 -0
  323. package/web/app/site/app/logo-monochrome-512.png +0 -0
  324. package/web/app/site/app/logo-monochrome-maskable-512.png +0 -0
  325. package/web/app/site/app/manifest.webmanifest +0 -1
  326. package/web/app/site/app/og-image-2.jpg +0 -0
  327. package/web/app/site/app/og-image.png +0 -0
  328. package/web/app/site/app/robots.txt +0 -2
  329. package/web/app/site/app/version.json +0 -1
  330. package/web/app/site/boot.js +0 -34277
  331. package/web/app/site/index.html +0 -251
  332. package/web/app/site/sw.js +0 -71331
package/web/app/boot.mjs CHANGED
@@ -6,17 +6,22 @@
6
6
  // that same session from IndexedDB. So a returning visit restores silently, and
7
7
  // a new browser signs in with one redirect.
8
8
  //
9
- // New account: fedipodSignup(answers) — create the account, then redirect.
10
- // Returning: fedipodSignin({ issuer }) — redirect to the pod's login.
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.
11
16
  // On every load: fedipodOnLoad() — finish a redirect, or restore, then boot.
12
- import { signUp, handleProblem, AP_ROOT } from './signup.mjs';
17
+ import { signUp, moveIn, readAccount, handleProblem, AP_ROOT } from './signup.mjs';
13
18
  import * as podActor from '../../lib/pod/actor.mjs';
14
19
  import * as podState from '../../lib/pod/state.mjs';
15
20
  import { podBaseOfWebId } from '../../lib/pod/urls.mjs';
16
- import { podLayout } from '../../lib/pod/root.mjs';
21
+ import { resourceExists } from '../../lib/pod/root.mjs';
17
22
  import { BrowserRemotePod } from './pod-remote.mjs';
18
23
  import { beginLogin, completeLogin, getSession, signOut } from './oidc-session.mjs';
19
- import { generateKeys, wrapKeys, unwrapKeys, isKeyEnvelope } from './keystore.mjs';
24
+ import { generateKeys, unwrapKeys, isKeyEnvelope } from './keystore.mjs';
20
25
  import { cacheOpenedKeys } from './keys-browser.mjs';
21
26
 
22
27
  const REDIRECT = `${location.origin}/`; // the app root doubles as the OIDC callback
@@ -55,12 +60,11 @@ async function bootWorker({ reset = false } = {}) {
55
60
  await booted;
56
61
  }
57
62
 
58
- // A browser that has signed in but has never opened this account's signing key.
59
- //
60
- // The key on the pod is wrapped under the account password (signup.mjs), which
61
- // is what keeps the pod's host from being able to sign as you. Opening it needs
62
- // the password once per browser; after that the opened copy lives in this
63
- // origin's IndexedDB and the worker boots from it with nothing to ask.
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.
64
68
  //
65
69
  // The unwrap happens HERE, in the page, and not in the worker: the worker boots
66
70
  // itself whenever the browser restarts it, with nobody present to type anything.
@@ -77,7 +81,7 @@ async function readAccountState() {
77
81
  const remote = new BrowserRemotePod(session, { webId: session.webId, role: 'signup', log: () => {} });
78
82
  const urls = { state };
79
83
  const [cfg, doc] = await Promise.all([
80
- podState.readConfig(remote, urls), podState.readWrappedKeys(remote, urls),
84
+ podState.readConfig(remote, urls), podState.readKeys(remote, urls),
81
85
  ]);
82
86
  if (!cfg) throw new Error(`could not read this account's config under ${state}`);
83
87
  const actorUrl = `${cfg.remotePod}${cfg.root || AP_ROOT}ap/actor`;
@@ -86,36 +90,61 @@ async function readAccountState() {
86
90
 
87
91
  window.fedipodUnlock = async (password) => {
88
92
  if (!password) throw new Error('Enter your password.');
89
- const { doc, actorUrl } = await readAccountState();
93
+ const { remote, urls, doc, actorUrl } = await readAccountState();
90
94
  if (!doc) throw new Error('could not read this account\'s key on the pod');
91
- if (!isKeyEnvelope(doc)) throw new Error('this account\'s key is not locked — nothing to unlock');
95
+ if (!isKeyEnvelope(doc)) throw new Error('this account\'s key is not under a password — nothing to unlock');
92
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);
93
100
  await cacheOpenedKeys(actorUrl, rec);
94
101
  await bootWorker();
95
102
  };
96
103
 
97
- // The same pane, for someone who no longer has the sign-up password: a new key,
98
- // wrapped under the password they use now, written over the pod's copy. Nothing
99
- // is unwrapped, so the old password is never needed. The boot that follows
100
- // publishes the new public key (agent.goActive → publishProfile).
101
- window.fedipodNewKey = async (password) => {
102
- if (!password) throw new Error('Enter the password you use for your pod now.');
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 () => {
103
109
  const { remote, urls, cfg, actorUrl } = await readAccountState();
104
110
  const keys = await generateKeys();
105
111
  keys.mintedFor = cfg.gateway?.frontActor || actorUrl; // one key, one actor (signup.mjs)
106
- await podState.writeWrappedKeys(remote, urls, await wrapKeys(keys, password));
112
+ await podState.writeKeys(remote, urls, keys);
107
113
  await cacheOpenedKeys(actorUrl, keys);
108
114
  await bootWorker();
109
115
  };
110
116
 
111
- // New account: create the account, pod, key, config and gateway attach (this
112
- // needs the password once), then redirect to the pod's login to establish the
113
- // durable session. The agent boots on return, reading config + key from the pod.
114
- window.fedipodSignup = async ({ onStep, ...answers }) => {
115
- await signUp(answers, { onStep, frontOrigin: location.origin });
116
- const { authorizationUrl } = await beginLogin({ issuer: answers.issuer, redirectUri: REDIRECT });
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 });
117
125
  location.href = authorizationUrl;
118
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;
119
148
 
120
149
  // Returning / new browser: sign-in takes the full Fediverse address, @you@yourpod.
121
150
  // The host part IS the pod (a FediPod address lives at a host root), so the pod is
@@ -150,6 +179,7 @@ async function issuerForPod(pod) {
150
179
  async function podForFrontedAddress(handle) {
151
180
  const res = await fetch(`/.well-known/webfinger?resource=${encodeURIComponent(`acct:${handle}@${location.host}`)}`,
152
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.`);
153
183
  if (!res || res.status >= 400) throw new Error(`nobody at this site is called @${handle}@${location.host}`);
154
184
  const doc = await res.json().catch(() => ({}));
155
185
  const podActorId = (doc.aliases || []).find((a) => /\/ap\/actor$/u.test(String(a)));
@@ -171,11 +201,22 @@ window.fedipodSignin = async ({ address }) => {
171
201
  location.href = authorizationUrl;
172
202
  };
173
203
 
174
- // Called on every page load. Returns 'signed-in' | 'restored' | 'anonymous'.
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.
175
208
  window.fedipodOnLoad = async () => {
176
209
  if (new URLSearchParams(location.search).get('code')) {
177
- await completeLogin({ currentUrl: location.href });
210
+ const done = await completeLogin({ currentUrl: location.href });
178
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
+ }
179
220
  await bootWorker({ reset: true }); // this may be a different account
180
221
  return 'signed-in';
181
222
  }
@@ -209,6 +250,9 @@ window.fedipodHandleProblem = handleProblem;
209
250
  if (typeof document !== 'undefined') (async () => {
210
251
  const $ = (id) => document.getElementById(id);
211
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;
212
256
 
213
257
  // --- unlock: this browser's first use of an account whose key is locked ---
214
258
  //
@@ -242,13 +286,12 @@ if (typeof document !== 'undefined') (async () => {
242
286
  $('unlock-error').textContent = '';
243
287
  const btn = $('unlock-newkey-go'); btn.disabled = true;
244
288
  try {
245
- await window.fedipodNewKey($('unlock-password').value);
289
+ await window.fedipodNewKey();
246
290
  $('unlock-password').value = '';
247
291
  location.href = '/admin/client/';
248
292
  } catch (err) {
249
293
  $('unlock-error').textContent = err.message || String(err);
250
294
  btn.disabled = false;
251
- $('unlock-password').select();
252
295
  }
253
296
  };
254
297
  $('unlock-newkey-go')?.addEventListener('click', doNewKey);
@@ -278,16 +321,96 @@ if (typeof document !== 'undefined') (async () => {
278
321
  return;
279
322
  }
280
323
  // We logged in (or had a saved session) but the agent could not start.
281
- // Show exactly why — including where it threw — instead of silently
282
- // dropping back to the landing, which hides every real failure.
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
+
283
387
  console.error(e);
284
388
  $('loading').hidden = true; $('hero').hidden = true; $('landing').hidden = true;
285
389
  $('brand').hidden = false; $('running').hidden = false;
286
- $('running-title').textContent = 'Signed in, but the agent could not start';
390
+ $('running-title').textContent = known ? known.title : 'Signed in, but the agent could not start';
287
391
  $('run-error').style.whiteSpace = 'pre-wrap';
288
- $('run-error').textContent = (e.message || String(e)) + (e.detail ? `\n\n${e.detail}` : '');
392
+ $('run-error').textContent = (e.message || String(e)) + (!known && e.detail ? `\n\n${e.detail}` : '');
289
393
  $('run-actions').hidden = false;
290
- $('run-retry').textContent = 'Reload'; $('run-retry').addEventListener('click', () => location.reload());
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
+ }
291
414
  $('run-back').textContent = 'Sign out'; $('run-back').addEventListener('click', async () => { try { await window.fedipodSignOut(); } catch {} location.href = '/'; });
292
415
  return;
293
416
  }
@@ -296,16 +419,40 @@ if (typeof document !== 'undefined') (async () => {
296
419
  // a fresh session and forwards deep links on a returning one, so both a
297
420
  // fresh sign-in and a restored session land in the same place.
298
421
  if (state === 'signed-in' || state === 'restored') { location.href = '/admin/client/'; return; }
299
-
300
- // Anonymous: show the landing (sign-in address + create-account); form stays hidden.
301
- $('loading').hidden = true;
302
- $('landing').hidden = false;
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
+ }
303
430
  }
304
431
 
305
432
  // Views. The register form stands alone: the marketing hero and the sign-in
306
433
  // landing give way to the short brand, so only "FediPod" and the form show.
307
434
  const showLanding = () => { $('pane-form').hidden = true; $('running').hidden = true; $('brand').hidden = true; $('hero').hidden = false; $('landing').hidden = false; };
308
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
+ }
309
456
 
310
457
 
311
458
  // --- sign in: the full @you@yourpod address → redirect to your pod's login ---
@@ -317,64 +464,51 @@ if (typeof document !== 'undefined') (async () => {
317
464
  $('signin').addEventListener('click', doSignin);
318
465
  $('signin-address').addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); doSignin(); } });
319
466
 
320
- // --- register form: two screens, pod first then Fediverse identity ---
467
+ // --- register form: two screens, the pod's login first, then the identity ---
321
468
  const f = () => $('form').elements;
322
469
  // The pod provider is a free-text URL; default and normalise to a scheme.
323
470
  // The provider is picked from the list, or typed under "Other…".
324
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; };
325
472
  const providerHost = () => { try { return new URL(providerUrl()).host; } catch { return ''; } };
326
- // A new pod is named by its subdomain under the provider; an existing pod is
327
- // brought by its address, which may be its own host or a path on a shared one.
328
- const podHostOf = () => { const sub = f().podName.value.trim().toLowerCase(); const ph = providerHost(); return (sub && ph) ? `${sub}.${ph}` : ''; };
329
- const podUrl = () => { let v = f().pod.value.trim(); if (!v) return ''; if (!/^https?:\/\//i.test(v)) v = 'https://' + v; if (!v.endsWith('/')) v += '/'; try { return new URL(v).href; } catch { return ''; } };
330
- // A pod on a suffix-based host cannot answer WebFinger, so its address
331
- // lives at this site; a pod at its own host root gets the choice.
332
- const isPathPod = (u) => { try { return new URL(u).pathname !== '/'; } catch { return false; } };
333
- // Where the chosen provider puts new pods, asked of the provider itself
334
- // (lib/pod/root.mjs podLayout) and remembered per provider: 'host', 'path',
335
- // or null when it would not say.
336
- const layouts = new Map();
337
- let layout = null;
338
- const learnLayout = async () => {
339
- const origin = providerHost() ? new URL(providerUrl()).origin : '';
340
- if (!origin) { layout = null; return; }
341
- if (!layouts.has(origin)) layouts.set(origin, podLayout(fetch, origin).catch(() => null));
342
- const known = await layouts.get(origin);
343
- if (providerHost() && new URL(providerUrl()).origin === origin) { layout = known; applyShape(); previewAddr(); }
344
- };
345
- const pathPod = () => (f().mode.value === 'existing' ? isPathPod(podUrl()) : layout === 'path');
346
- const shape = () => (pathPod() ? 'front' : f().shape.value);
347
- const answers = () => {
348
- const mode = f().mode.value;
349
- const a = { mode, handle: f().handle.value.trim().toLowerCase(), email: f().email.value.trim(),
350
- password: f().password.value, issuer: providerUrl(), shape: shape() };
351
- if (mode === 'new') a.podName = f().podName.value.trim().toLowerCase();
352
- else a.pod = podUrl();
353
- return a;
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}/`;
354
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() });
355
488
  const previewAddr = () => {
356
489
  const handle = f().handle.value.trim().toLowerCase();
357
- const host = shape() === 'front' ? location.host
358
- : (f().mode.value === 'existing' ? (podUrl() ? new URL(podUrl()).host : '') : podHostOf());
490
+ let host = '';
491
+ try { host = shape() === 'front' ? location.host : new URL(signedPod).host; } catch { host = ''; }
359
492
  $('preview').textContent = (handle && host) ? `@${handle}@${host}` : '@…@…';
360
493
  };
361
494
  // The shape choice is fixed for a path pod, and open for a host-root pod.
362
495
  // A path pod has no choice to make: the radios go away and the note says why.
363
496
  const applyShape = () => {
364
- const fixed = pathPod();
497
+ const fixed = pathPod() || !!moveFrom;
365
498
  for (const r of f().shape) { if (fixed) r.checked = r.value === 'front'; }
366
499
  $('shape-group').hidden = fixed;
367
- $('shape-hint').hidden = !fixed;
500
+ $('shape-hint').hidden = !fixed || !!moveFrom; // a move explains itself in its own note
368
501
  };
369
502
  const applyMode = () => {
370
503
  const existing = f().mode.value === 'existing';
371
- $('pod-field').hidden = !existing;
372
- $('podname-field').hidden = existing;
504
+ $('newpod-field').hidden = existing;
373
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';
374
509
  };
375
510
  for (const el of $('form').elements) for (const evt of ['input', 'change']) el.addEventListener(evt, () => { applyMode(); applyShape(); previewAddr(); });
376
- for (const evt of ['input', 'change']) { $('provider').addEventListener(evt, learnLayout); $('providerOther').addEventListener(evt, learnLayout); }
377
- applyMode(); learnLayout();
511
+ applyMode();
378
512
 
379
513
  // Step machine: one screen at a time, each gated by its own validation.
380
514
  const STEP_IDS = ['step-1', 'step-2'];
@@ -382,21 +516,11 @@ if (typeof document !== 'undefined') (async () => {
382
516
  const goStep = (n) => {
383
517
  STEP_IDS.forEach((id, i) => { $(id).hidden = i !== n - 1; });
384
518
  $('err-1').textContent = ''; $('form-error').textContent = '';
385
- if (n === 2) { applyShape(); previewAddr(); learnLayout(); }
519
+ if (n === 2) { applyShape(); previewAddr(); }
386
520
  if (FOCUS[n]) $(FOCUS[n]).focus();
387
521
  };
388
522
  const validateStep1 = () => {
389
523
  if (!providerHost()) return f().provider.value === '' ? 'A pod provider address is required under Other….' : 'A valid pod provider URL is required.';
390
- if (f().mode.value === 'existing') {
391
- if (!podUrl()) return 'A pod address is required, like https://alice.solidcommunity.net/ or https://server.example/alice/.';
392
- } else {
393
- const sub = f().podName.value.trim().toLowerCase();
394
- if (!sub) return 'A pod username/subdomain is required.';
395
- const sp = window.fedipodHandleProblem(sub);
396
- if (sp) return `Pod username: ${sp}`;
397
- }
398
- if (!f().email.value.trim()) return 'A pod email is required.';
399
- if (!f().password.value) return 'A pod password is required.';
400
524
  return null;
401
525
  };
402
526
  const validateStep2 = () => {
@@ -406,33 +530,47 @@ if (typeof document !== 'undefined') (async () => {
406
530
  };
407
531
  $('create').addEventListener('click', showForm);
408
532
  $('cancel').addEventListener('click', () => { showLanding(); goStep(1); });
409
- $('to-2').addEventListener('click', () => { const e = validateStep1(); if (e) { $('err-1').textContent = e; return; } goStep(2); });
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
+ });
410
541
  $('back-1').addEventListener('click', () => goStep(1));
411
542
 
412
543
  // From the setup screen back to the form (a failed run) or the landing.
413
544
  const backToForm = (errMsg) => {
414
545
  $('running').hidden = true; $('brand').hidden = false; $('pane-form').hidden = false;
415
- goStep(1);
416
- if (errMsg) $('err-1').textContent = errMsg; // remind them what failed
546
+ goStep(2);
547
+ if (errMsg) $('form-error').textContent = errMsg; // remind them what failed
417
548
  };
418
549
  $('run-retry').addEventListener('click', () => backToForm($('run-error').textContent));
419
550
  $('run-back').addEventListener('click', () => { showLanding(); goStep(1); });
420
551
 
421
- const LABELS = { account: 'Creating your account and pod', credential: 'Preparing this browser', keys: 'Making your signing key', gateway: 'Connecting your mail door' };
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' };
422
554
  $('form').addEventListener('submit', async (e) => {
423
555
  e.preventDefault(); $('form-error').textContent = '';
424
- const e1 = validateStep1(); if (e1) { $('form-error').textContent = e1; goStep(1); $('err-1').textContent = e1; return; }
425
556
  const e2 = validateStep2(); if (e2) { $('form-error').textContent = e2; goStep(2); return; }
426
557
  const a = answers();
427
558
  $('pane-form').hidden = true; $('running').hidden = false;
428
559
  $('running-title').textContent = 'Setting up…'; $('run-error').textContent = ''; $('run-actions').hidden = true;
429
560
  const steps = $('steps'); steps.textContent = ''; const mark = {};
430
- 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); };
431
- try { await window.fedipodSignup({ ...a, onStep }); }
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
+ }
432
568
  catch (err) {
433
569
  $('running-title').textContent = 'Setup did not finish';
434
570
  $('run-error').textContent = err.message || String(err);
435
571
  $('run-actions').hidden = false; // the way out of the failure screen
436
572
  }
437
573
  });
574
+
575
+ if (pendingIdentity) await showIdentity();
438
576
  })();