fedipod-server 0.29.0 → 0.31.0

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