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