fedipod-server 0.29.0 → 0.30.0

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