fedipod-server 0.28.1 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -34
- package/config/server.json +22 -0
- package/dist/claims.js +3 -2
- package/dist/directory.d.ts +2 -0
- package/dist/door.d.ts +4 -0
- package/dist/door.js +31 -0
- package/dist/fedipod.d.ts +16 -0
- package/dist/fedipod.js +13 -0
- package/dist/front.d.ts +3 -0
- package/dist/front.js +94 -0
- package/dist/handler.d.ts +39 -101
- package/dist/handler.js +86 -617
- package/dist/handler.jsonld +6 -30
- package/dist/identities.d.ts +62 -0
- package/dist/identities.js +236 -0
- package/dist/mounts.d.ts +43 -0
- package/dist/mounts.js +123 -0
- package/dist/opt-in.d.ts +46 -0
- package/dist/opt-in.js +176 -0
- package/dist/store-pod.js +37 -0
- package/package.json +10 -18
- package/lib/client/c2s.mjs +0 -582
- package/lib/client/localapi.mjs +0 -87
- package/lib/client/masto/accounts.mjs +0 -309
- package/lib/client/masto/body.mjs +0 -156
- package/lib/client/masto/index.mjs +0 -206
- package/lib/client/masto/instance.mjs +0 -112
- package/lib/client/masto/media.mjs +0 -79
- package/lib/client/masto/oauth.mjs +0 -656
- package/lib/client/masto/render.mjs +0 -518
- package/lib/client/masto/statuses.mjs +0 -372
- package/lib/client/masto/timelines.mjs +0 -438
- package/lib/client/oidc-auth.mjs +0 -62
- package/lib/client/streaming.mjs +0 -154
- package/lib/client/webpush.mjs +0 -98
- package/lib/connections/acctfeed.mjs +0 -257
- package/lib/connections/atproto.mjs +0 -309
- package/lib/connections/bskyfeed.mjs +0 -243
- package/lib/connections/bskygroup.mjs +0 -162
- package/lib/connections/fediacct.mjs +0 -253
- package/lib/connections/import.mjs +0 -357
- package/lib/connections/tagfeed.mjs +0 -212
- package/lib/connections/vault.mjs +0 -114
- package/lib/core/as2.mjs +0 -206
- package/lib/core/contexts/activitystreams.json +0 -379
- package/lib/core/contexts/anno.json +0 -126
- package/lib/core/contexts/did-v1.json +0 -57
- package/lib/core/contexts/fep-5711.json +0 -36
- package/lib/core/contexts/gotosocial.json +0 -86
- package/lib/core/contexts/identity-v1.json +0 -152
- package/lib/core/contexts/index.mjs +0 -63
- package/lib/core/contexts/join-lemmy.json +0 -33
- package/lib/core/contexts/joinmastodon.json +0 -28
- package/lib/core/contexts/litepub-0.1.json +0 -60
- package/lib/core/contexts/map.json +0 -19
- package/lib/core/contexts/miscellany.json +0 -19
- package/lib/core/contexts/quotes.json +0 -18
- package/lib/core/contexts/schemaorg.json +0 -8845
- package/lib/core/contexts/security-data-integrity-v1.json +0 -78
- package/lib/core/contexts/security-data-integrity-v2.json +0 -81
- package/lib/core/contexts/security-multikey-v1.json +0 -35
- package/lib/core/contexts/security-v1.json +0 -74
- package/lib/core/contexts/webfinger.json +0 -10
- package/lib/core/deliver.mjs +0 -371
- package/lib/core/graphview.mjs +0 -327
- package/lib/core/intake/activities.mjs +0 -633
- package/lib/core/intake/activity.mjs +0 -318
- package/lib/core/intake/channel.mjs +0 -144
- package/lib/core/intake/group.mjs +0 -256
- package/lib/core/intake/index.mjs +0 -701
- package/lib/core/intake/notes.mjs +0 -360
- package/lib/core/intake/verify.mjs +0 -142
- package/lib/core/keys.mjs +0 -153
- package/lib/core/lease.mjs +0 -206
- package/lib/core/polls.mjs +0 -105
- package/lib/core/profile-page.mjs +0 -104
- package/lib/core/proof.mjs +0 -79
- package/lib/core/publisher/collections.mjs +0 -237
- package/lib/core/publisher/index.mjs +0 -500
- package/lib/core/publisher/notes.mjs +0 -453
- package/lib/core/publisher/questions.mjs +0 -239
- package/lib/core/publisher/restore.mjs +0 -224
- package/lib/core/shapes/activitystreams.ttl +0 -157
- package/lib/core/shapes/index.mjs +0 -132
- package/lib/core/shapes/shapes-text.mjs +0 -13
- package/lib/core/social.mjs +0 -531
- package/lib/core/storage.mjs +0 -176
- package/lib/core/store.mjs +0 -568
- package/lib/core/wire-quotes.mjs +0 -71
- package/lib/core/wire.mjs +0 -889
- package/lib/device/account.mjs +0 -87
- package/lib/device/admin/index.mjs +0 -13
- package/lib/device/admin/origins.mjs +0 -35
- package/lib/device/admin/routes/connections.mjs +0 -144
- package/lib/device/admin/routes/gateway.mjs +0 -199
- package/lib/device/admin/routes/lifecycle.mjs +0 -200
- package/lib/device/admin/routes/owner.mjs +0 -322
- package/lib/device/admin/routes/setup.mjs +0 -412
- package/lib/device/admin/routes/social.mjs +0 -188
- package/lib/device/admin/server.mjs +0 -95
- package/lib/device/admin/static.mjs +0 -247
- package/lib/device/admin/surface.mjs +0 -315
- package/lib/device/certs.mjs +0 -281
- package/lib/device/cli/commands/account.mjs +0 -586
- package/lib/device/cli/commands/run.mjs +0 -278
- package/lib/device/cli/commands/service.mjs +0 -221
- package/lib/device/cli/commands/setup.mjs +0 -447
- package/lib/device/cli/commands/state.mjs +0 -561
- package/lib/device/cli/context.mjs +0 -288
- package/lib/device/export-collections.mjs +0 -161
- package/lib/device/gateway-move.mjs +0 -58
- package/lib/device/home.mjs +0 -161
- package/lib/device/migrate.mjs +0 -115
- package/lib/device/ports.mjs +0 -27
- package/lib/device/remote.mjs +0 -54
- package/lib/device/setup.mjs +0 -459
- package/lib/device/update.mjs +0 -96
- package/lib/gateway/caches.mjs +0 -36
- package/lib/gateway/directory.mjs +0 -90
- package/lib/gateway/front-core.mjs +0 -970
- package/lib/gateway/gateway-core.mjs +0 -165
- package/lib/gateway/headers.mjs +0 -49
- package/lib/gateway/httpsig.mjs +0 -159
- package/lib/gateway/notices.mjs +0 -84
- package/lib/gateway/quiet.mjs +0 -189
- package/lib/pod/README.md +0 -61
- package/lib/pod/actor.mjs +0 -96
- package/lib/pod/collection.mjs +0 -77
- package/lib/pod/containers.mjs +0 -140
- package/lib/pod/discovery.mjs +0 -46
- package/lib/pod/featured.mjs +0 -18
- package/lib/pod/followers.mjs +0 -24
- package/lib/pod/following.mjs +0 -10
- package/lib/pod/http.mjs +0 -74
- package/lib/pod/inbox.mjs +0 -166
- package/lib/pod/links.mjs +0 -35
- package/lib/pod/media.mjs +0 -27
- package/lib/pod/notes.mjs +0 -80
- package/lib/pod/notifications.mjs +0 -89
- package/lib/pod/outbox.mjs +0 -18
- package/lib/pod/package.json +0 -19
- package/lib/pod/policy.mjs +0 -58
- package/lib/pod/private.mjs +0 -19
- package/lib/pod/root.mjs +0 -104
- package/lib/pod/state.mjs +0 -40
- package/lib/pod/transport.mjs +0 -525
- package/lib/pod/urls.mjs +0 -85
- package/lib/server/embed.mjs +0 -423
- package/lib/session/README.md +0 -137
- package/lib/session/demo.html +0 -94
- package/lib/session/fedi-account.mjs +0 -408
- package/lib/session/fedi-login.mjs +0 -123
- package/lib/session/oidc-session.mjs +0 -233
- package/lib/session/package.json +0 -49
- package/lib/shared/guard.mjs +0 -213
- package/lib/shared/links.mjs +0 -9
- package/lib/shared/safefetch.mjs +0 -235
- package/lib/shared/ua.mjs +0 -29
- package/phanpy/dist/404.html +0 -40
- package/phanpy/dist/_headers +0 -2
- package/phanpy/dist/apple-touch-icon.png +0 -0
- package/phanpy/dist/assets/ICONS-DIPJeU0C.js +0 -2
- package/phanpy/dist/assets/ICONS-DIPJeU0C.js.map +0 -1
- package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js +0 -183
- package/phanpy/dist/assets/ScheduledAtField-D-Abfo4J.js.map +0 -1
- package/phanpy/dist/assets/Temml-CCjoacWt.woff2 +0 -0
- package/phanpy/dist/assets/__vite-browser-external-C7iut881.js +0 -2
- package/phanpy/dist/assets/__vite-browser-external-C7iut881.js.map +0 -1
- package/phanpy/dist/assets/boosts-carousel-BiOaNdMT.jpg +0 -0
- package/phanpy/dist/assets/catch-up-O5q5C75Z.png +0 -0
- package/phanpy/dist/assets/chunk-aKtaBQYM.js +0 -1
- package/phanpy/dist/assets/compose-CFEx7wb4.js +0 -2
- package/phanpy/dist/assets/compose-CFEx7wb4.js.map +0 -1
- package/phanpy/dist/assets/compose-ZJN5xSb4.js +0 -35
- package/phanpy/dist/assets/compose-ZJN5xSb4.js.map +0 -1
- package/phanpy/dist/assets/debug.module-YFQgwnIr.js +0 -52
- package/phanpy/dist/assets/debug.module-YFQgwnIr.js.map +0 -1
- package/phanpy/dist/assets/dom-p1YcJ5Rw.js +0 -2
- package/phanpy/dist/assets/dom-p1YcJ5Rw.js.map +0 -1
- package/phanpy/dist/assets/home-mobile-dark@2x-Dc-J8-SM.png +0 -0
- package/phanpy/dist/assets/home-mobile-light@2x-Bd3fod8m.png +0 -0
- package/phanpy/dist/assets/home-tablet-dark@2x-BgcNI8le.png +0 -0
- package/phanpy/dist/assets/home-tablet-light@2x-BW2RV9T6.png +0 -0
- package/phanpy/dist/assets/icons/add-circle-line-WD0mwORD.js +0 -1
- package/phanpy/dist/assets/icons/alert-line-CpFUMf9s.js +0 -1
- package/phanpy/dist/assets/icons/android-2-line-Bzxnrd3S.js +0 -1
- package/phanpy/dist/assets/icons/announcement-line-5nwaJFJm.js +0 -1
- package/phanpy/dist/assets/icons/arrow-down-circle-line-a7Id9-Iv.js +0 -1
- package/phanpy/dist/assets/icons/arrow-down-line-B8uzXzq6.js +0 -1
- package/phanpy/dist/assets/icons/arrow-left-line-CGrGT9C-.js +0 -1
- package/phanpy/dist/assets/icons/arrow-right-line-CE-HERfX.js +0 -1
- package/phanpy/dist/assets/icons/arrow-to-up-line-CvdQjmcy.js +0 -1
- package/phanpy/dist/assets/icons/arrow-up-circle-line-DEparSNF.js +0 -1
- package/phanpy/dist/assets/icons/arrow-up-line-C7yBeugc.js +0 -1
- package/phanpy/dist/assets/icons/arrows-right-line-BtbXmJGP.js +0 -1
- package/phanpy/dist/assets/icons/at-line-CF66Bznk.js +0 -1
- package/phanpy/dist/assets/icons/attachment-line-BY8It-l9.js +0 -1
- package/phanpy/dist/assets/icons/blockquote-line-BS6pU_hm.js +0 -1
- package/phanpy/dist/assets/icons/board-line-C0UWXyA6.js +0 -1
- package/phanpy/dist/assets/icons/bookmark-line-1CtX5JLF.js +0 -1
- package/phanpy/dist/assets/icons/building-5-line-Dd59MzbO.js +0 -1
- package/phanpy/dist/assets/icons/bus-2-line-6_dvA0GG.js +0 -1
- package/phanpy/dist/assets/icons/calendar-day-line-Crpl_fmu.js +0 -1
- package/phanpy/dist/assets/icons/calendar-month-line-vommts2C.js +0 -1
- package/phanpy/dist/assets/icons/calendar-time-add-line-BU_DTlQk.js +0 -1
- package/phanpy/dist/assets/icons/camera-line-Cv69MEei.js +0 -1
- package/phanpy/dist/assets/icons/celebrate-line-B8DvIoi0.js +0 -1
- package/phanpy/dist/assets/icons/chart-bar-line-FK-QOmtF.js +0 -1
- package/phanpy/dist/assets/icons/chart-line-line-BGcJAFWw.js +0 -1
- package/phanpy/dist/assets/icons/chat-3-line-YFK2-hwz.js +0 -1
- package/phanpy/dist/assets/icons/check-circle-line-DsAxFr5-.js +0 -1
- package/phanpy/dist/assets/icons/clipboard-line-BBp364gJ.js +0 -1
- package/phanpy/dist/assets/icons/close-circle-line-CICdiuGz.js +0 -1
- package/phanpy/dist/assets/icons/close-line-DYrFWcjv.js +0 -1
- package/phanpy/dist/assets/icons/cloud-line-tiQAbah8.js +0 -1
- package/phanpy/dist/assets/icons/code-line-fAl8iiV3.js +0 -1
- package/phanpy/dist/assets/icons/comment-2-line-CR3g7WeB.js +0 -1
- package/phanpy/dist/assets/icons/copy-2-line-CLW69yF5.js +0 -1
- package/phanpy/dist/assets/icons/delete-2-line-B8xmbr4n.js +0 -1
- package/phanpy/dist/assets/icons/document-3-line-DBGNhAg2.js +0 -1
- package/phanpy/dist/assets/icons/document-line-C7mb9sb7.js +0 -1
- package/phanpy/dist/assets/icons/down-line-BGqSSThd.js +0 -1
- package/phanpy/dist/assets/icons/edit-4-line-DcgGaEhx.js +0 -1
- package/phanpy/dist/assets/icons/emoji-2-line-D8YgnM-y.js +0 -1
- package/phanpy/dist/assets/icons/exit-line-Dc07BS-x.js +0 -1
- package/phanpy/dist/assets/icons/external-link-line-BvpSkmjO.js +0 -1
- package/phanpy/dist/assets/icons/eye-2-line-CiWXx-f_.js +0 -1
- package/phanpy/dist/assets/icons/eye-close-line-BgTaSJ4P.js +0 -1
- package/phanpy/dist/assets/icons/filter-2-line-B_mR2usy.js +0 -1
- package/phanpy/dist/assets/icons/filter-line-C_nm-3cU.js +0 -1
- package/phanpy/dist/assets/icons/flag-1-line-C2HB05I0.js +0 -1
- package/phanpy/dist/assets/icons/forbid-circle-line-D3LTT9yd.js +0 -1
- package/phanpy/dist/assets/icons/formula-line-DLrt2d6j.js +0 -1
- package/phanpy/dist/assets/icons/grid-line-CgUmEikf.js +0 -1
- package/phanpy/dist/assets/icons/group-line-C5fnX0wU.js +0 -1
- package/phanpy/dist/assets/icons/hand-finger-2-line-BGgxbuL9.js +0 -1
- package/phanpy/dist/assets/icons/hashtag-line-CyTEEXBb.js +0 -1
- package/phanpy/dist/assets/icons/heart-crack-line-BZddbO2C.js +0 -1
- package/phanpy/dist/assets/icons/heart-line-CJ7K47J4.js +0 -1
- package/phanpy/dist/assets/icons/history-2-line-kWWvFzqv.js +0 -1
- package/phanpy/dist/assets/icons/history-line-bGQiwbTH.js +0 -1
- package/phanpy/dist/assets/icons/home-3-line-fRU1zeLG.js +0 -1
- package/phanpy/dist/assets/icons/information-line-iNk6-sOY.js +0 -1
- package/phanpy/dist/assets/icons/keyboard-line-DsCyuQNz.js +0 -1
- package/phanpy/dist/assets/icons/layout-4-line-CZkOX52Z.js +0 -1
- package/phanpy/dist/assets/icons/layout-5-line-B_znt5wO.js +0 -1
- package/phanpy/dist/assets/icons/left-line-eUw0tya4.js +0 -1
- package/phanpy/dist/assets/icons/lightning-line-DaKoDdix.js +0 -1
- package/phanpy/dist/assets/icons/link-2-line-DCqLmMA7.js +0 -1
- package/phanpy/dist/assets/icons/list-check-line-BAxosBh9.js +0 -1
- package/phanpy/dist/assets/icons/lock-line-CPoaXeUW.js +0 -1
- package/phanpy/dist/assets/icons/mail-line-B0P8aa1L.js +0 -1
- package/phanpy/dist/assets/icons/moon-line-CEqNAToP.js +0 -1
- package/phanpy/dist/assets/icons/more-1-fill-Dw2e5xab.js +0 -1
- package/phanpy/dist/assets/icons/more-3-line-BIiVjYTz.js +0 -1
- package/phanpy/dist/assets/icons/notification-line-BZZq2Gtu.js +0 -1
- package/phanpy/dist/assets/icons/pencil-line-CKh8-A1v.js +0 -1
- package/phanpy/dist/assets/icons/photo-album-line-Bnfg2u40.js +0 -1
- package/phanpy/dist/assets/icons/pin-line-DpTolyhs.js +0 -1
- package/phanpy/dist/assets/icons/play-fill-B0-G_8lX.js +0 -1
- package/phanpy/dist/assets/icons/qrcode-2-line-B6SPCaHn.js +0 -1
- package/phanpy/dist/assets/icons/quill-pen-line-B6LUrnCP.js +0 -1
- package/phanpy/dist/assets/icons/quote-left-fill-hQZ1cj_6.js +0 -1
- package/phanpy/dist/assets/icons/radar-line-CKyroTth.js +0 -1
- package/phanpy/dist/assets/icons/react-line-CoIKhhtK.js +0 -1
- package/phanpy/dist/assets/icons/refresh-2-line-D0mTF97S.js +0 -1
- package/phanpy/dist/assets/icons/right-line-B3KWJaqc.js +0 -1
- package/phanpy/dist/assets/icons/rocket-line-4KZl537D.js +0 -1
- package/phanpy/dist/assets/icons/round-fill-C69NTrZ0.js +0 -1
- package/phanpy/dist/assets/icons/round-line-B9k_1uo-.js +0 -1
- package/phanpy/dist/assets/icons/route-line-B28ReHcE.js +0 -1
- package/phanpy/dist/assets/icons/rows-4-line-CrBniagM.js +0 -1
- package/phanpy/dist/assets/icons/scan-line-DSf74YdP.js +0 -1
- package/phanpy/dist/assets/icons/search-2-line-B6geIU1z.js +0 -1
- package/phanpy/dist/assets/icons/settings-3-line-azJwK47w.js +0 -1
- package/phanpy/dist/assets/icons/settings-6-line-C_5zc5YR.js +0 -1
- package/phanpy/dist/assets/icons/share-2-line-D5MxWjrm.js +0 -1
- package/phanpy/dist/assets/icons/share-forward-line-Cp61fZzZ.js +0 -1
- package/phanpy/dist/assets/icons/sparkles-2-line-DYYyXTaW.js +0 -1
- package/phanpy/dist/assets/icons/sparkles-line-C2hY1s6I.js +0 -1
- package/phanpy/dist/assets/icons/time-line-BF3eet1v.js +0 -1
- package/phanpy/dist/assets/icons/transfer-4-line-oisfvTBw.js +0 -1
- package/phanpy/dist/assets/icons/translate-line-BFWol2Ce.js +0 -1
- package/phanpy/dist/assets/icons/unlock-line-X_x5vwv3.js +0 -1
- package/phanpy/dist/assets/icons/upload-3-line-DgzwUJeW.js +0 -1
- package/phanpy/dist/assets/icons/user-4-line-BVSynZCp.js +0 -1
- package/phanpy/dist/assets/icons/user-add-2-line-BlGS5Q8q.js +0 -1
- package/phanpy/dist/assets/icons/user-add-line-BbXdHG4z.js +0 -1
- package/phanpy/dist/assets/icons/user-edit-line-BFAHOV0X.js +0 -1
- package/phanpy/dist/assets/icons/user-follow-line-BXux0wSd.js +0 -1
- package/phanpy/dist/assets/icons/user-star-line-DdYlpHLU.js +0 -1
- package/phanpy/dist/assets/icons/user-warning-line-Cj43j0_E.js +0 -1
- package/phanpy/dist/assets/icons/user-x-line-DIDgNlPH.js +0 -1
- package/phanpy/dist/assets/icons/volume-line-Bs390KQt.js +0 -1
- package/phanpy/dist/assets/icons/volume-mute-line-DzlzIqFZ.js +0 -1
- package/phanpy/dist/assets/icons/walk-line-yNXfB-md.js +0 -1
- package/phanpy/dist/assets/icons/world-2-line-CenkGIwj.js +0 -1
- package/phanpy/dist/assets/icons/zoom-in-line-CaENUphf.js +0 -1
- package/phanpy/dist/assets/icons/zoom-out-line-BDNk0EWo.js +0 -1
- package/phanpy/dist/assets/instances-BNPptnn-.json +0 -333
- package/phanpy/dist/assets/locales/ar-SA-CfheRbCu.js +0 -1
- package/phanpy/dist/assets/locales/ca-ES-DHRW86Tz.js +0 -1
- package/phanpy/dist/assets/locales/cs-CZ-CKoqEuA1.js +0 -1
- package/phanpy/dist/assets/locales/de-DE-ByRPMRFy.js +0 -1
- package/phanpy/dist/assets/locales/eo-UY-CPC7wLCS.js +0 -1
- package/phanpy/dist/assets/locales/es-ES-dJa0Fd9t.js +0 -1
- package/phanpy/dist/assets/locales/eu-ES-C3djlPR2.js +0 -1
- package/phanpy/dist/assets/locales/fa-IR-DTT490Ck.js +0 -1
- package/phanpy/dist/assets/locales/fi-FI-B23MCPuz.js +0 -1
- package/phanpy/dist/assets/locales/fr-FR-BcaQsO5C.js +0 -1
- package/phanpy/dist/assets/locales/gl-ES-BR-CVKBN.js +0 -1
- package/phanpy/dist/assets/locales/he-IL-CfheRbCu.js +0 -1
- package/phanpy/dist/assets/locales/hu-HU-CfheRbCu.js +0 -1
- package/phanpy/dist/assets/locales/it-IT-C1136UFV.js +0 -1
- package/phanpy/dist/assets/locales/ja-JP-CRZmRAhD.js +0 -1
- package/phanpy/dist/assets/locales/kab-Cz8xH_TT.js +0 -1
- package/phanpy/dist/assets/locales/ko-KR-CG9UiY4o.js +0 -1
- package/phanpy/dist/assets/locales/lt-LT-CJcI6sHZ.js +0 -1
- package/phanpy/dist/assets/locales/nb-NO-CfheRbCu.js +0 -1
- package/phanpy/dist/assets/locales/nl-NL-DxN4Yc1t.js +0 -1
- package/phanpy/dist/assets/locales/oc-FR-CfheRbCu.js +0 -1
- package/phanpy/dist/assets/locales/pl-PL-DkwGXf6P.js +0 -1
- package/phanpy/dist/assets/locales/pseudo-LOCALE-CQ4XxkQ0.js +0 -1
- package/phanpy/dist/assets/locales/pt-BR-nGL0HdFS.js +0 -1
- package/phanpy/dist/assets/locales/pt-PT-Cp17aj2z.js +0 -1
- package/phanpy/dist/assets/locales/ru-RU-0Y8cIoaK.js +0 -1
- package/phanpy/dist/assets/locales/th-TH-CfheRbCu.js +0 -1
- package/phanpy/dist/assets/locales/tok-CfheRbCu.js +0 -1
- package/phanpy/dist/assets/locales/tr-TR-CfheRbCu.js +0 -1
- package/phanpy/dist/assets/locales/uk-UA-C5E3dFBf.js +0 -1
- package/phanpy/dist/assets/locales/zh-CN-BHJi7_et.js +0 -1
- package/phanpy/dist/assets/locales/zh-TW-CfheRbCu.js +0 -1
- package/phanpy/dist/assets/main-BdqNbG-a.js +0 -26
- package/phanpy/dist/assets/main-BdqNbG-a.js.map +0 -1
- package/phanpy/dist/assets/mock-home-DGhR__He.js +0 -2
- package/phanpy/dist/assets/mock-home-DGhR__He.js.map +0 -1
- package/phanpy/dist/assets/multi-column-ROck0NVt.jpg +0 -0
- package/phanpy/dist/assets/multi-hashtag-timeline-DH5INVHi.jpg +0 -0
- package/phanpy/dist/assets/nested-comments-thread-hv59kZLc.jpg +0 -0
- package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js +0 -2
- package/phanpy/dist/assets/polyfill-force-H8sUkLGp.js.map +0 -1
- package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js +0 -20
- package/phanpy/dist/assets/pwa-viewport-ogKbF51K.js.map +0 -1
- package/phanpy/dist/assets/style-B1iLPTPR.css +0 -2
- package/phanpy/dist/assets/temml-DuyIQMei.js +0 -97
- package/phanpy/dist/assets/temml-DuyIQMei.js.map +0 -1
- package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js +0 -2
- package/phanpy/dist/assets/tinyld.light.node-DtbBhLYC.js.map +0 -1
- package/phanpy/dist/assets/year-in-posts-B2lywqdx.png +0 -0
- package/phanpy/dist/assets/year-in-posts-DJv_star.js +0 -3
- package/phanpy/dist/assets/year-in-posts-DJv_star.js.map +0 -1
- package/phanpy/dist/compose/index.html +0 -20
- package/phanpy/dist/favicon.ico +0 -0
- package/phanpy/dist/index.html +0 -73
- package/phanpy/dist/logo-192.png +0 -0
- package/phanpy/dist/logo-512.png +0 -0
- package/phanpy/dist/logo-badge-72.png +0 -0
- package/phanpy/dist/logo-maskable-512.png +0 -0
- package/phanpy/dist/logo-monochrome-512.png +0 -0
- package/phanpy/dist/logo-monochrome-maskable-512.png +0 -0
- package/phanpy/dist/manifest.webmanifest +0 -1
- package/phanpy/dist/og-image-2.jpg +0 -0
- package/phanpy/dist/og-image.png +0 -0
- package/phanpy/dist/robots.txt +0 -2
- package/phanpy/dist/sw.js +0 -2
- package/phanpy/dist/sw.js.map +0 -1
- package/phanpy/dist/version.json +0 -1
- package/run-agent.mjs +0 -897
- package/vendor/gate.cjs +0 -138
- package/vendor/idp-grant.cjs +0 -394
- package/vendor/jfetch.cjs +0 -16
- package/web/admin/actors.js +0 -145
- package/web/admin/bar.css +0 -126
- package/web/admin/bar.js +0 -99
- package/web/admin/client/client.js +0 -66
- package/web/admin/client/index.html +0 -69
- package/web/admin/client-pick.js +0 -79
- package/web/admin/common.js +0 -23
- package/web/admin/connections.js +0 -112
- package/web/admin/gateway.js +0 -133
- package/web/admin/group.js +0 -258
- package/web/admin/index.html +0 -603
- package/web/admin/notices-bar.js +0 -90
- package/web/admin/oauth-signin.mjs +0 -37
- package/web/admin/record.js +0 -390
- package/web/admin/setup/index.html +0 -241
- package/web/admin/setup/setup.js +0 -326
- package/web/admin/tokens.css +0 -68
- package/web/admin/upkeep.js +0 -177
- package/web/admin/window.css +0 -55
- package/web/admin/window.js +0 -136
- package/web/app/README.md +0 -81
- package/web/app/admin-facade.mjs +0 -588
- package/web/app/agent.mjs +0 -663
- package/web/app/atproto-browser.mjs +0 -86
- package/web/app/authorize_interaction.html +0 -56
- package/web/app/authorize_interaction.js +0 -69
- package/web/app/boot.mjs +0 -576
- package/web/app/deliver-relay.mjs +0 -129
- package/web/app/dist/boot.js +0 -34218
- package/web/app/dist/boot.js.map +0 -7
- package/web/app/dist/sw.js +0 -72810
- package/web/app/dist/sw.js.map +0 -7
- package/web/app/fediacct-browser.mjs +0 -146
- package/web/app/gateway-move.mjs +0 -60
- package/web/app/idb-kv.mjs +0 -35
- package/web/app/index.html +0 -242
- package/web/app/keys-browser.mjs +0 -71
- package/web/app/keystore.mjs +0 -82
- package/web/app/oidc-session.mjs +0 -6
- package/web/app/pod-auth.mjs +0 -248
- package/web/app/pod-remote.mjs +0 -84
- package/web/app/shims/_globals.mjs +0 -2
- package/web/app/shims/fedify-sig.mjs +0 -77
- package/web/app/shims/node-crypto.mjs +0 -113
- package/web/app/shims/node-fs.mjs +0 -17
- package/web/app/shims/node-path.mjs +0 -19
- package/web/app/shims/node-url.mjs +0 -7
- package/web/app/shims/prelude.js +0 -58
- package/web/app/shims/safefetch.mjs +0 -58
- package/web/app/shims/shapes-text.mjs +0 -8
- package/web/app/shims/web-push.mjs +0 -14
- package/web/app/signup.mjs +0 -318
- package/web/app/sw-src.mjs +0 -220
- package/web/app/update.js +0 -70
- package/web/front/admin.html +0 -55
- package/web/front/admin.js +0 -89
- package/web/front/install.sh +0 -69
- package/web/front/new-account.html +0 -35
- package/web/front/new-account.js +0 -13
- package/web/front/notices.html +0 -69
- package/web/front/notices.js +0 -107
- package/web/front/run.html +0 -58
- package/web/front/run.js +0 -195
- package/web/front/solid-oidc-client.js +0 -6
- package/web/icons/forum.svg +0 -11
- package/web/icons/gateway.svg +0 -14
- package/web/icons/local.svg +0 -11
package/web/admin/upkeep.js
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
// upkeep.js — upkeep and the lifecycle: the output pane, drain, recover,
|
|
2
|
-
// log and dead letters; the confirmations for rotate, retire and move; and
|
|
3
|
-
// the inbox backlog panel.
|
|
4
|
-
|
|
5
|
-
// Which button filled the output pane, so clicking that one again closes it
|
|
6
|
-
// rather than re-fetching the same thing under an already-open panel.
|
|
7
|
-
let outputSource = null;
|
|
8
|
-
|
|
9
|
-
const OUTPUT_TITLES = { log: 'Log', deadletter: 'Dead letters', drain: 'Inbox drain', rebuild: 'Recovered posts' };
|
|
10
|
-
const output = (obj, source = null) => {
|
|
11
|
-
closePanels('output');
|
|
12
|
-
outputSource = source;
|
|
13
|
-
solWindow.show('output', OUTPUT_TITLES[source] || 'Output');
|
|
14
|
-
$('output').textContent = typeof obj === 'string' ? obj : JSON.stringify(obj, null, 2);
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const showingFrom = (source) => outputSource === source && solWindow.openId() === 'output';
|
|
18
|
-
|
|
19
|
-
// Drain is the one that does work rather than reveals it, so a second click
|
|
20
|
-
// re-runs instead of closing. It can take a while — the agent joins a sweep
|
|
21
|
-
// already in flight and queues another after it — and a button that looks dead
|
|
22
|
-
// for a minute reads as broken.
|
|
23
|
-
$('do-drain').addEventListener('click', async (ev) => {
|
|
24
|
-
const b = ev.currentTarget;
|
|
25
|
-
b.disabled = true;
|
|
26
|
-
b.textContent = 'draining…';
|
|
27
|
-
say('draining the inbox — if a sweep is already running this waits for it to finish');
|
|
28
|
-
const r = await write('/drain', {}, 'inbox drained');
|
|
29
|
-
b.disabled = false;
|
|
30
|
-
b.textContent = 'Drain the inbox';
|
|
31
|
-
if (r) {
|
|
32
|
-
const box = r.inbox || {};
|
|
33
|
-
say(`inbox drained — ${box.count ?? 0} still waiting`);
|
|
34
|
-
output(r, 'drain');
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
// Like the drain, this does work rather than reveals it, so a second click
|
|
39
|
-
// re-runs. Nothing here can lose anything: it only adds posts back.
|
|
40
|
-
$('do-rebuild').addEventListener('click', async (ev) => {
|
|
41
|
-
const b = ev.currentTarget;
|
|
42
|
-
b.disabled = true;
|
|
43
|
-
b.textContent = 'recovering…';
|
|
44
|
-
say('reading what the pod still holds — one request per post, so this takes a moment');
|
|
45
|
-
const r = await write('/rebuild', {}, 'checked');
|
|
46
|
-
b.disabled = false;
|
|
47
|
-
b.textContent = 'Recover posts';
|
|
48
|
-
if (!r) return;
|
|
49
|
-
if (r.why) { say(r.why, 'err'); return; }
|
|
50
|
-
if (!r.landed) { say('recovered posts could NOT be saved — see the log', 'err'); return; }
|
|
51
|
-
say(r.recovered
|
|
52
|
-
? `recovered ${r.recovered} post(s) the pod had and this machine did not`
|
|
53
|
-
: `nothing was missing — the pod indexed ${r.indexed} post(s), all of them already here`);
|
|
54
|
-
output(r, 'rebuild');
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
$('do-log').addEventListener('click', async () => {
|
|
58
|
-
if (showingFrom('log')) { closePanels(); return; }
|
|
59
|
-
const { json } = await api('/log');
|
|
60
|
-
output((json?.lines || []).slice(-60).join('\n') || 'nothing logged yet', 'log');
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
$('do-deadletter').addEventListener('click', async () => {
|
|
64
|
-
if (showingFrom('deadletter')) { closePanels(); return; }
|
|
65
|
-
const { json } = await api('/deadletter');
|
|
66
|
-
output(json?.items?.length ? json.items : 'no dead letters', 'deadletter');
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
// ---- lifecycle ----
|
|
70
|
-
// None of these can be taken back by clicking again, so the button only opens
|
|
71
|
-
// the matching warning in the markup; the second click is the one that acts.
|
|
72
|
-
// Retire also wants the handle typed, because a misclick cannot produce it.
|
|
73
|
-
|
|
74
|
-
const LIFECYCLE = {
|
|
75
|
-
'rotate-key': { path: '/rotate-key', title: 'Rotate the signing key', done: (r) => (r.changed ? 'rotated and republished' : 'no change — the key was already fresh') },
|
|
76
|
-
retire: { path: '/retire', title: 'Retire this identity', go: 'Retire it', danger: true, done: (r) => `retired ${r.deletedAt}: Delete delivered to ${r.inboxes} inbox(es)` },
|
|
77
|
-
move: { path: '/move', title: 'Transfer this account away', go: 'Transfer it', focus: 'move-target',
|
|
78
|
-
done: (r) => `transferred to ${r.target}: Move delivered to ${r.inboxes} inbox(es), unfollowed ${r.unfollowed}/${r.following}` },
|
|
79
|
-
// The address at the gateway, not the identity: the pod keeps everything.
|
|
80
|
-
'close-address': { path: '/gateway/close', title: 'Close this address', go: 'Close it', danger: true, focus: 'confirm-handle-close',
|
|
81
|
-
done: (r) => (r.closed ? 'closed — this address is gone for good; everything on your pod is untouched' : 'not closed') },
|
|
82
|
-
};
|
|
83
|
-
let pending = null;
|
|
84
|
-
|
|
85
|
-
const closeConfirm = () => closePanels();
|
|
86
|
-
|
|
87
|
-
for (const btn of document.querySelectorAll('[data-confirm]')) {
|
|
88
|
-
btn.addEventListener('click', () => {
|
|
89
|
-
const what = btn.dataset.confirm;
|
|
90
|
-
// The same button again closes its question rather than re-asking it.
|
|
91
|
-
if (pending === what && solWindow.openId() === 'confirm-form') { closePanels(); return; }
|
|
92
|
-
closePanels(); // including whatever else was open
|
|
93
|
-
pending = what;
|
|
94
|
-
const spec = LIFECYCLE[what];
|
|
95
|
-
$(`warn-${what}`).hidden = false;
|
|
96
|
-
solWindow.show('confirm-form', spec.title);
|
|
97
|
-
$('confirm-go').className = spec.danger ? 'danger' : 'primary';
|
|
98
|
-
$('confirm-go').textContent = spec.go || 'Confirm';
|
|
99
|
-
if (spec.focus) $(spec.focus).focus();
|
|
100
|
-
else if (what === 'retire') $('confirm-handle').focus();
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Offered from inside the retire warning: someone reading it has already said
|
|
105
|
-
// what they want ("not this account, here, any more") and these are the two
|
|
106
|
-
// answers that are not destruction. Switching panels rather than closing means
|
|
107
|
-
// they do not have to go and find the button themselves.
|
|
108
|
-
const openConfirm = (what) => {
|
|
109
|
-
closePanels(); // or `show` toggles: same panel, different warning
|
|
110
|
-
document.querySelector(`[data-confirm="${what}"]`).click();
|
|
111
|
-
};
|
|
112
|
-
// Park lives on the status control now; from inside the retire warning it is
|
|
113
|
-
// still one click — close the question and park.
|
|
114
|
-
$('go-park').addEventListener('click', () => { closePanels(); setStatus(true); });
|
|
115
|
-
$('go-move').addEventListener('click', () => openConfirm('move'));
|
|
116
|
-
|
|
117
|
-
$('confirm-cancel').addEventListener('click', () => { closeConfirm(); say('nothing changed'); });
|
|
118
|
-
|
|
119
|
-
$('confirm-form').addEventListener('submit', async (ev) => {
|
|
120
|
-
ev.preventDefault();
|
|
121
|
-
if (!pending) return;
|
|
122
|
-
const what = pending;
|
|
123
|
-
const body = what === 'retire' ? { confirm: $('confirm-handle').value.trim() }
|
|
124
|
-
: what === 'move' ? { target: $('move-target').value.trim(), confirm: $('confirm-handle-move').value.trim() }
|
|
125
|
-
: what === 'close-address' ? { confirm: $('confirm-handle-close').value.trim() }
|
|
126
|
-
: {};
|
|
127
|
-
if (what === 'move' && !body.target) { say('name the account to transfer to', 'err'); return; }
|
|
128
|
-
$('confirm-go').disabled = true;
|
|
129
|
-
say(`${what} — this talks to the pod and to other servers, so it takes a moment`);
|
|
130
|
-
const r = await write(LIFECYCLE[what].path, body, what);
|
|
131
|
-
$('confirm-go').disabled = false;
|
|
132
|
-
if (!r) return; // write() already said why
|
|
133
|
-
closeConfirm();
|
|
134
|
-
say(LIFECYCLE[what].done(r));
|
|
135
|
-
load(); // mode, and whether it is retired, both changed
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
// ---- inbox ----
|
|
139
|
-
// Only appears when there is enough waiting to be worth a decision. The agent
|
|
140
|
-
// drains oldest-first regardless; this exists to let the owner say "do not
|
|
141
|
-
// bother with that fortnight", which is not a call an agent should make on
|
|
142
|
-
// someone's mail by itself.
|
|
143
|
-
const INBOX_PROMPT_AT = 500;
|
|
144
|
-
let dismissed = false;
|
|
145
|
-
|
|
146
|
-
async function renderInbox() {
|
|
147
|
-
const { json: st } = await api('/status');
|
|
148
|
-
// A state document the last load could not read is a timeline or a contact
|
|
149
|
-
// list quietly missing; the page says which, under the facts.
|
|
150
|
-
const skipped = st?.stateSkipped || [];
|
|
151
|
-
const line = $('state-skipped');
|
|
152
|
-
line.hidden = !skipped.length;
|
|
153
|
-
line.textContent = skipped.length
|
|
154
|
-
? `${skipped.length} state document${skipped.length === 1 ? '' : 's'} could not be read on the last load: ${skipped.join(', ')}.`
|
|
155
|
-
: '';
|
|
156
|
-
if (dismissed) return;
|
|
157
|
-
const box = st?.inbox;
|
|
158
|
-
const panel = $('pane-inbox');
|
|
159
|
-
if (!box || box.count < INBOX_PROMPT_AT) { panel.hidden = true; return; }
|
|
160
|
-
const mb = box.bytes >= 1048576
|
|
161
|
-
? `${(box.bytes / 1048576).toFixed(1)} MB` : `${Math.round(box.bytes / 1024)} kB`;
|
|
162
|
-
const since = box.oldest ? new Date(box.oldest).toLocaleDateString() : 'unknown';
|
|
163
|
-
$('inbox-summary').textContent =
|
|
164
|
-
`${box.count.toLocaleString()} deliveries waiting (${mb}), the oldest from ${since}.`;
|
|
165
|
-
// One request each to read and delete, and the agent holds itself to 60 a
|
|
166
|
-
// minute, so the honest number is minutes not seconds.
|
|
167
|
-
$('inbox-warn').hidden = box.count < 2000;
|
|
168
|
-
$('inbox-warn').textContent = box.count >= 2000
|
|
169
|
-
? `At 60 requests a minute this is roughly ${Math.ceil(box.count * 2 / 60)} minutes of `
|
|
170
|
-
+ 'draining if you keep everything. Discarding the old content is much quicker.'
|
|
171
|
-
: '';
|
|
172
|
-
panel.hidden = false;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// The gateway, as a facts row under software: attach through a multi-user
|
|
176
|
-
// front with this agent's own credential, detach back to the pod inbox. The
|
|
177
|
-
// forms live in the floating window, like every other disclosure.
|
package/web/admin/window.css
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/* window.css — the floating panel every page of ours puts a form in.
|
|
2
|
-
Shared like bar.css, so the three surfaces cannot drift apart. */
|
|
3
|
-
|
|
4
|
-
/* Fixed, so it floats over the page rather than pushing it about — which is
|
|
5
|
-
what the accordions did, moving the line you were reading every time one
|
|
6
|
-
opened. Resizing is the browser's own grip: `resize` needs `overflow` set to
|
|
7
|
-
anything but visible, which is also what keeps a long form inside the frame. */
|
|
8
|
-
#win {
|
|
9
|
-
position: fixed; z-index: 40;
|
|
10
|
-
top: 5rem; left: 50%; transform: translateX(-50%);
|
|
11
|
-
width: min(46rem, calc(100vw - 2rem));
|
|
12
|
-
/* Tall enough for what is in it and no taller: a fixed height made a short
|
|
13
|
-
panel roomy and a long one scroll for no reason. `auto` up to a cap, so it
|
|
14
|
-
only ever scrolls when the content genuinely will not fit the screen — and
|
|
15
|
-
the moment you drag the corner, that inline height wins over both. */
|
|
16
|
-
height: auto;
|
|
17
|
-
min-width: 18rem; min-height: 8rem;
|
|
18
|
-
max-width: 100vw; max-height: calc(100vh - 7rem);
|
|
19
|
-
resize: both; overflow: hidden;
|
|
20
|
-
display: flex; flex-direction: column;
|
|
21
|
-
/* Raised, like the bar: it sits ON the page, so it takes the same colour the
|
|
22
|
-
bar does rather than the page's own. The shadow lifts it; the colour says
|
|
23
|
-
which layer it belongs to. */
|
|
24
|
-
background: var(--raised); color: CanvasText;
|
|
25
|
-
border: 1px solid var(--btn-edge); border-radius: .5rem;
|
|
26
|
-
box-shadow: 0 .6rem 2rem #0004;
|
|
27
|
-
}
|
|
28
|
-
/* Dragged by the bar, so the grab area is obvious and a text selection inside
|
|
29
|
-
the form never moves the window. */
|
|
30
|
-
/* Its own title bar keeps a rule: this one IS two surfaces meeting inside a
|
|
31
|
-
single small box, where a tone change alone is too quiet to read as a grab
|
|
32
|
-
handle. Different problem from the page bar, different answer. */
|
|
33
|
-
#win-bar {
|
|
34
|
-
flex: 0 0 auto; display: flex; align-items: baseline; gap: .6rem;
|
|
35
|
-
padding: .45rem .7rem; cursor: move; user-select: none;
|
|
36
|
-
border-bottom: 1px solid var(--btn-edge); border-radius: .5rem .5rem 0 0;
|
|
37
|
-
background: var(--surface);
|
|
38
|
-
}
|
|
39
|
-
#win-title { flex: 1 1 auto; font-weight: 600; color: var(--heading); }
|
|
40
|
-
/* 24x24 is the 2.5.8 minimum; at .1rem of vertical padding this came out
|
|
41
|
-
21.6px tall, which is a small target for the one control that dismisses the
|
|
42
|
-
thing covering your page. Same glyph, same place, bigger hit area. */
|
|
43
|
-
#win-close {
|
|
44
|
-
font: inherit; line-height: 1; cursor: pointer;
|
|
45
|
-
min-width: 24px; min-height: 24px; padding: .2rem .5rem;
|
|
46
|
-
display: inline-flex; align-items: center; justify-content: center;
|
|
47
|
-
border: 0; background: none; color: var(--link);
|
|
48
|
-
}
|
|
49
|
-
/* The window scrolls, never the page — same rule the rest of the app follows. */
|
|
50
|
-
#win-body { flex: 1 1 auto; min-height: 0; overflow: auto; padding: .2rem 1rem 1rem; }
|
|
51
|
-
#win-body > * { margin-top: .6rem; }
|
|
52
|
-
#win-body pre { overflow-x: auto; background: #0001; padding: .6rem; border-radius: .3rem;
|
|
53
|
-
font-size: .9rem; }
|
|
54
|
-
/* Dragging with the pointer over the frame would otherwise select text inside it. */
|
|
55
|
-
body.dragging { user-select: none; }
|
package/web/admin/window.js
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
// window.js — the floating panel, shared by every page of ours.
|
|
2
|
-
//
|
|
3
|
-
// It replaces the accordions. Those opened at the foot of the page and pushed
|
|
4
|
-
// whatever you were reading out from under you; worse, only one could be open,
|
|
5
|
-
// so looking at the log meant closing the form you were filling in. A window
|
|
6
|
-
// floats over the page instead, and you can move it off whatever it covers.
|
|
7
|
-
//
|
|
8
|
-
// Resizing is the browser's own grip (`resize: both`), so there is no drag
|
|
9
|
-
// maths here beyond moving it. Nothing is created in script: every panel is
|
|
10
|
-
// declared in the page's markup inside #win-body, and this only shows one.
|
|
11
|
-
|
|
12
|
-
(() => {
|
|
13
|
-
const win = document.getElementById('win');
|
|
14
|
-
if (!win) return;
|
|
15
|
-
const bar = document.getElementById('win-bar');
|
|
16
|
-
const title = document.getElementById('win-title');
|
|
17
|
-
const body = document.getElementById('win-body');
|
|
18
|
-
|
|
19
|
-
// Every direct child of the body is a panel; showing one hides the rest.
|
|
20
|
-
const panels = () => [...body.children];
|
|
21
|
-
let open = null;
|
|
22
|
-
// Where focus was when the window opened, so closing can put it back. Without
|
|
23
|
-
// this, Escape from inside the panel drops focus on <body> and the tab order
|
|
24
|
-
// restarts from the top of the page.
|
|
25
|
-
let returnTo = null;
|
|
26
|
-
|
|
27
|
-
// It IS a dialog, so it says so — and a dialog that opens without taking
|
|
28
|
-
// focus leaves a keyboard user tabbing forward through the rest of the page
|
|
29
|
-
// to find it, and a screen-reader user with no announcement that anything
|
|
30
|
-
// happened at all. It also sits over the control that opened it, so moving
|
|
31
|
-
// focus in is what stops that control being focused-but-obscured.
|
|
32
|
-
win.setAttribute('role', 'dialog');
|
|
33
|
-
win.setAttribute('aria-modal', 'false'); // the page behind stays usable
|
|
34
|
-
win.setAttribute('aria-labelledby', 'win-title');
|
|
35
|
-
|
|
36
|
-
// The first focusable that is actually SHOWING. A plain querySelector matches
|
|
37
|
-
// elements inside hidden sub-blocks (a confirm panel has one warning block per
|
|
38
|
-
// action, all but one hidden), and .focus() on a display:none element is a
|
|
39
|
-
// silent no-op — so a dialog whose first match is hidden would open with focus
|
|
40
|
-
// still outside it. offsetParent is null for anything display:none.
|
|
41
|
-
const focusFirst = () => {
|
|
42
|
-
const panel = panels().find(p => !p.hidden);
|
|
43
|
-
if (!panel) { document.getElementById('win-close')?.focus(); return; }
|
|
44
|
-
const candidates = panel.querySelectorAll(
|
|
45
|
-
'input:not([type=hidden]), select, textarea, button, [href], [tabindex]:not([tabindex="-1"])',
|
|
46
|
-
);
|
|
47
|
-
// Prefer a non-committing control: never open a destructive dialog with a
|
|
48
|
-
// submit/confirm button pre-focused where a stray Enter would fire it.
|
|
49
|
-
let firstVisible = null;
|
|
50
|
-
for (const el of candidates) {
|
|
51
|
-
if (el.offsetParent === null && el !== document.body) continue; // hidden
|
|
52
|
-
if (!firstVisible) firstVisible = el;
|
|
53
|
-
const commits = el.type === 'submit' || /\bconfirm-go\b/.test(el.id);
|
|
54
|
-
if (!commits) { el.focus(); return; }
|
|
55
|
-
}
|
|
56
|
-
(firstVisible || document.getElementById('win-close'))?.focus();
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const close = () => {
|
|
60
|
-
win.hidden = true;
|
|
61
|
-
for (const p of panels()) p.hidden = true;
|
|
62
|
-
const was = open;
|
|
63
|
-
open = null;
|
|
64
|
-
// Only if focus is still ours to move: the user may have clicked away.
|
|
65
|
-
const back = returnTo;
|
|
66
|
-
returnTo = null;
|
|
67
|
-
if (back && document.contains(back) && win.contains(document.activeElement)) back.focus();
|
|
68
|
-
else if (back && document.contains(back) && document.activeElement === document.body) back.focus();
|
|
69
|
-
win.dispatchEvent(new CustomEvent('win:closed', { detail: { was } }));
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
// Returns false when it CLOSED an already-open panel, so a button can toggle
|
|
73
|
-
// itself without every caller repeating the check.
|
|
74
|
-
const show = (id, label) => {
|
|
75
|
-
if (open === id && !win.hidden) { close(); return false; }
|
|
76
|
-
const opener = document.activeElement;
|
|
77
|
-
for (const p of panels()) p.hidden = p.id !== id;
|
|
78
|
-
title.textContent = label || '';
|
|
79
|
-
win.hidden = false;
|
|
80
|
-
open = id;
|
|
81
|
-
clampIntoView();
|
|
82
|
-
if (opener && opener !== document.body && !win.contains(opener)) returnTo = opener;
|
|
83
|
-
focusFirst();
|
|
84
|
-
return true;
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
// A window remembers where it was left, so it does not jump back to the
|
|
88
|
-
// middle every time — but only within the page, because a position saved on a
|
|
89
|
-
// wide screen is off-screen on a narrow one and there is nothing to grab.
|
|
90
|
-
let placed = false;
|
|
91
|
-
function clampIntoView() {
|
|
92
|
-
if (!placed) return;
|
|
93
|
-
const r = win.getBoundingClientRect();
|
|
94
|
-
const x = Math.min(Math.max(r.left, 0), Math.max(0, innerWidth - r.width));
|
|
95
|
-
const y = Math.min(Math.max(r.top, 0), Math.max(0, innerHeight - r.height));
|
|
96
|
-
moveTo(x, y);
|
|
97
|
-
}
|
|
98
|
-
function moveTo(x, y) {
|
|
99
|
-
win.style.transform = 'none'; // the centring transform, undone once moved
|
|
100
|
-
win.style.left = `${x}px`;
|
|
101
|
-
win.style.top = `${y}px`;
|
|
102
|
-
placed = true;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
let drag = null;
|
|
106
|
-
bar.addEventListener('pointerdown', (e) => {
|
|
107
|
-
if (e.target.closest('button')) return; // the close button is not a handle
|
|
108
|
-
const r = win.getBoundingClientRect();
|
|
109
|
-
drag = { dx: e.clientX - r.left, dy: e.clientY - r.top };
|
|
110
|
-
bar.setPointerCapture(e.pointerId);
|
|
111
|
-
document.body.classList.add('dragging');
|
|
112
|
-
});
|
|
113
|
-
bar.addEventListener('pointermove', (e) => {
|
|
114
|
-
if (!drag) return;
|
|
115
|
-
const r = win.getBoundingClientRect();
|
|
116
|
-
moveTo(Math.min(Math.max(e.clientX - drag.dx, 0), Math.max(0, innerWidth - r.width)),
|
|
117
|
-
Math.min(Math.max(e.clientY - drag.dy, 0), Math.max(0, innerHeight - r.height)));
|
|
118
|
-
});
|
|
119
|
-
const endDrag = (e) => {
|
|
120
|
-
if (!drag) return;
|
|
121
|
-
drag = null;
|
|
122
|
-
try { bar.releasePointerCapture(e.pointerId); } catch { /* already released */ }
|
|
123
|
-
document.body.classList.remove('dragging');
|
|
124
|
-
};
|
|
125
|
-
bar.addEventListener('pointerup', endDrag);
|
|
126
|
-
bar.addEventListener('pointercancel', endDrag);
|
|
127
|
-
addEventListener('resize', clampIntoView);
|
|
128
|
-
|
|
129
|
-
document.getElementById('win-close').addEventListener('click', close);
|
|
130
|
-
// Escape closes it, which is what every floating thing does and what people
|
|
131
|
-
// try first when a window is covering the thing they wanted to read.
|
|
132
|
-
addEventListener('keydown', (e) => { if (e.key === 'Escape' && !win.hidden) close(); });
|
|
133
|
-
|
|
134
|
-
// The whole API: open a declared panel by id, close, and ask what is open.
|
|
135
|
-
window.solWindow = { show, close, openId: () => (win.hidden ? null : open) };
|
|
136
|
-
})();
|
package/web/app/README.md
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
# web/app — FediPod in the browser
|
|
2
|
-
|
|
3
|
-
The in-browser build: sign up and run a FediPod account in a tab, no install.
|
|
4
|
-
See `claude/plans/browser-agent.md` for the whole design and status.
|
|
5
|
-
|
|
6
|
-
| file | what |
|
|
7
|
-
|---|---|
|
|
8
|
-
| `pod-auth.mjs` | A CSS account API client, browser-native: create an account + pod, mint a client credential, and a DPoP-bound `fetch`. Since 1.28.0 the app itself uses none of it — a pod is made on the provider's own page and the app runs on the pod's Solid-OIDC login — but the harnesses do, to make scratch pods and stand in for a login form. The twin of `lib/device/account.mjs` + `vendor/idp-grant.cjs`. |
|
|
9
|
-
| `keystore.mjs` | WebCrypto RSA/Ed25519 key generation. The key is stored on the pod as it is, in the owner-only state container, since 1.28.0 (2026-09-22); `unwrapKeys` remains for accounts from before then, whose key is under the sign-up password until it is opened once. |
|
|
10
|
-
| `keys-browser.mjs` | Importing a keys record for signing, and finding one: this browser's opened copy in IndexedDB first, else the pod's, read with the pod session. A pre-1.28.0 envelope raises `KeyPasswordNeeded`, which `boot.mjs` answers with the open-once pane; the same pane offers a new key to someone who no longer has that password. |
|
|
11
|
-
| `signup.mjs` | The `fedipod setup` flow, in the browser, up to publish, on the pod session the person already holds: pod check, gateway attach, key stored on the pod (owner-only ACL written *before* the key), config. Takes no password and no credential. Also `readAccount` (what the pod already holds) and `moveIn` (an address at another gateway moving here: attach fronted, rewrite the config with the old actor as an alias, restamp the key, leave the Move pending). |
|
|
12
|
-
| `gateway-move.mjs` | The pending half of a move, run when the agent goes active under the new ids: tells the old gateway (`/api/move`) and sends the Move to every follower from the old actor, signed under the old key id through the old relay. Safe to run again. |
|
|
13
|
-
| `shims/fedify-sig.mjs` | Browser stand-in for `@fedify/fedify/sig` (which will not bundle for a browser). `sign()` returns signed headers as data for the relay; `signRequest()` wraps it Fedify-shaped. Proven byte-identical to Fedify. |
|
|
14
|
-
| `shims/node-crypto.mjs` | Browser stand-in for `node:crypto` — the small synchronous slice the agent uses, via crypto-browserify, plus native WebCrypto. |
|
|
15
|
-
| `shims/safefetch.mjs` | Browser stand-in for `lib/shared/safefetch.mjs`. Pinning and the private-address checks are unnecessary here (a browser closes DNS rebinding itself); the BYTE BUDGET is not, so `readCapped` streams and stops at the cap exactly as the Node one does. |
|
|
16
|
-
| `dist/` | The bundled agent, built by `scripts/build-app.mjs`. Committed like `phanpy/dist`, regenerated on release. (Not present until the agent entry is built.) |
|
|
17
|
-
|
|
18
|
-
Build: `node scripts/build-app.mjs`. Tests live in `claude/validation/`:
|
|
19
|
-
`signup-browser/`, `signing-shim/`, `agent-bundle/`.
|
|
20
|
-
|
|
21
|
-
## The agent (built 2026-09-07)
|
|
22
|
-
|
|
23
|
-
| file | what |
|
|
24
|
-
|---|---|
|
|
25
|
-
| `pod-remote.mjs` | RemotePod over the DPoP session — the agent's pod I/O, ACLs and deletion deny-list, browser-native. |
|
|
26
|
-
| `keys-browser.mjs` | Load the signing key into WebCrypto. |
|
|
27
|
-
| `deliver-relay.mjs` | lib's Deliverer, sending through the relay (a browser cannot set Date/Host). |
|
|
28
|
-
| `agent.mjs` | Wires lib's store, publisher, intake and Mastodon facade with the browser edges. |
|
|
29
|
-
| `sw-src.mjs` | The service worker that hosts the agent and answers the facade (Mastodon paths + the owner/manage paths); static files fall through. Built to `dist/sw.js`. |
|
|
30
|
-
| `boot.mjs` | Page side: sign in at the pod (also the first half of sign-up), the identity screen on the way back, sign in by address, register the worker, route into `/admin/client/`; `?signout` / `?add` teardown. Built to `dist/boot.js`. |
|
|
31
|
-
| `shims/` | Browser stand-ins the bundle needs: `node-crypto`, `node-path`, `node-url`, `node-fs`, `web-push`, `safefetch`, `prelude` (process + Buffer). |
|
|
32
|
-
|
|
33
|
-
## The manage surface & connected accounts (built 2026-09-08)
|
|
34
|
-
|
|
35
|
-
The owner's record/manage page is the SAME `web/admin` UI the Node agent serves,
|
|
36
|
-
reused as static files under `/admin/` (staged by `scripts/stage-site.mjs`); the
|
|
37
|
-
worker answers the data endpoints it calls. See
|
|
38
|
-
`claude/plans/browser-manage-surface.md` for the whole design and status, and
|
|
39
|
-
`claude/plans/post-as-connected-account.md` for the deferred "post as" plan.
|
|
40
|
-
|
|
41
|
-
| file | what |
|
|
42
|
-
|---|---|
|
|
43
|
-
| `admin-facade.mjs` | Answers the owner/manage endpoints (`/status`, `/config`, `/gateway`, `/alias`, `/rotate-key`, `/rebuild`, `/move`, `/retire`, `/inbox/prune`, `/deadletter`, `/blocks`, `/atproto*`, `/fediacct*`) over the browser agent, mirroring `lib/device/admin.mjs`. Personal only. |
|
|
44
|
-
| `atproto-browser.mjs` | The Bluesky connection (`lib/connections/atproto.mjs`) with a per-connection storage choice — IndexedDB (this browser) or owner-only pod state — plus pause. |
|
|
45
|
-
| `fediacct-browser.mjs` | Connections to fediverse accounts on other servers (`lib/connections/fediacct.mjs`): the OAuth dance, the same storage choice, and a best-effort server-side revoke on disconnect. |
|
|
46
|
-
| `idb-kv.mjs` | The per-origin IndexedDB key/value store the two connectors use for "on this device, never the pod" credentials. |
|
|
47
|
-
|
|
48
|
-
`agent.mjs` also holds the single-active-agent **lease** (`lib/core/lease.mjs`) — a
|
|
49
|
-
second device runs read-only until it takes over — and starts the drain/mirrors
|
|
50
|
-
only when it is the active holder.
|
|
51
|
-
|
|
52
|
-
Build: `node scripts/build-app.mjs --entry web/app/sw-src.mjs --out web/app/dist/sw.js` and `--entry web/app/boot.mjs --out web/app/dist/boot.js`, then `node scripts/stage-site.mjs` to assemble `web/app/site/` (the front, the worker, Phanpy under `/app/`, and `web/admin` under `/admin/`).
|
|
53
|
-
|
|
54
|
-
Tests: `claude/smoke-tests/admin-facade-smoke.mjs`, and eight harnesses in
|
|
55
|
-
`claude/validation/browser-agent/` that drive a real Chrome against a scratch
|
|
56
|
-
Solid server — `run` (the agent and the facade), `sw-run` (the same through the
|
|
57
|
-
service worker, plus media upload and notification paging), `full-run` (the
|
|
58
|
-
staged site, sign-up to Phanpy rendering), `unlock-run` (a browser with no opened
|
|
59
|
-
key, and a pre-1.28.0 account opened once), `oidc-run`, `resume-run`,
|
|
60
|
-
`gateway-run`, and `provider-csp-run` (the sign-up page's own policy, read from
|
|
61
|
-
the browser's refusal reports). Four helpers sit beside them: `idp-login.mjs`
|
|
62
|
-
fills the pod's login and consent screens, `page-signup.mjs` drives the page
|
|
63
|
-
through sign-up the way a person does since 1.28.0 (pod first, then the pod's
|
|
64
|
-
login, then the identity screen), `worker-log.mjs` reads the agent's console
|
|
65
|
-
out of the service worker, and the attach and relay stubs in `sw-run.mjs` stand
|
|
66
|
-
in for the front.
|
|
67
|
-
|
|
68
|
-
## What this build does not have
|
|
69
|
-
|
|
70
|
-
Declared rather than pretended: each is omitted from the instance document, so
|
|
71
|
-
a client hides the control instead of offering one that quietly does nothing.
|
|
72
|
-
See the `MastoApi` options in `agent.mjs`.
|
|
73
|
-
|
|
74
|
-
| | why |
|
|
75
|
-
|---|---|
|
|
76
|
-
| **Streaming** | a service worker answers fetches, not sockets. No streaming URL is advertised, so clients poll. |
|
|
77
|
-
| **Web push** | `shims/web-push.mjs` is a no-op. `vapid` is omitted, and a client that subscribes anyway gets a 422 rather than a subscription nothing will push to. |
|
|
78
|
-
| **Scheduled posts** | nothing runs between now and the scheduled time. A `scheduled_at` is refused with a 422 that says so — accepting one was silent loss. |
|
|
79
|
-
| **Groups** | sign-up makes personal identities only (`signup.mjs`), and the moderation surface is not here. Joining a group works; hosting one needs the DeviceAgent. See `groups.md`. |
|
|
80
|
-
| **Changing where the address lives** | the shape is chosen at sign-up (`signup.mjs`): on the pod, `@you@yourpod` with the gateway as a mail door, or at the gateway, `@you@front` — and a pod on a suffix-based host is always fronted. `admin-facade.mjs` refuses changing it afterwards, because a rename needs a restart a browser does not have. |
|
|
81
|
-
| **Moving the private half** | `/state-move` is about filesystem paths and `credential.json`. A browser has neither; its private half is always on the pod. |
|