A decentralized music tracking and discovery platform built on AT Protocol 🎵
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add prompt support for login and remove client-side OAuth

Support a "prompt" query param in /login and include it when
redirecting from the web client. Server uses a fallback handle when
prompt is present and forwards the prompt to the OAuth client. Remove
client-side identity resolver and oauth-browser-client usage and tidy
related dependencies in package.json and bun.lock.

+23 -106
+10 -5
apps/api/src/bsky/app.ts
··· 22 22 23 23 app.get("/login", async (c) => { 24 24 requestCounter.add(1, { method: "GET", route: "/login" }); 25 - const { handle, cli } = c.req.query(); 26 - if (typeof handle !== "string" || !isValidHandle(handle)) { 25 + const { handle, cli, prompt } = c.req.query(); 26 + if ((typeof handle !== "string" || !isValidHandle(handle)) && !prompt) { 27 27 c.status(400); 28 28 return c.text("Invalid handle"); 29 29 } 30 30 try { 31 - const url = await ctx.oauthClient.authorize(handle, { 32 - scope: "atproto transition:generic", 33 - }); 31 + const url = await ctx.oauthClient.authorize( 32 + prompt ? "tsiry.selfhosted.social" : handle, 33 + { 34 + scope: "atproto transition:generic", 35 + // @ts-ignore: allow custom prompt param 36 + prompt, 37 + }, 38 + ); 34 39 if (cli) { 35 40 ctx.kv.set(`cli:${handle}`, "1"); 36 41 }
-2
apps/web/package.json
··· 16 16 "format": "biome format src" 17 17 }, 18 18 "dependencies": { 19 - "@atcute/identity-resolver": "^1.2.2", 20 - "@atcute/oauth-browser-client": "^2.0.3", 21 19 "@emotion/react": "^11.14.0", 22 20 "@emotion/styled": "^11.14.0", 23 21 "@hookform/resolvers": "^4.0.0",
+12 -66
apps/web/src/layouts/Main.tsx
··· 18 18 import SpotifyLogin from "./SpotifyLogin"; 19 19 import { IconEye, IconEyeOff, IconLock } from "@tabler/icons-react"; 20 20 import { consola } from "consola"; 21 - import { 22 - CompositeDidDocumentResolver, 23 - CompositeHandleResolver, 24 - DohJsonHandleResolver, 25 - LocalActorResolver, 26 - PlcDidDocumentResolver, 27 - WebDidDocumentResolver, 28 - WellKnownHandleResolver, 29 - } from "@atcute/identity-resolver"; 30 - import { 31 - configureOAuth, 32 - // createAuthorizationUrl, 33 - } from "@atcute/oauth-browser-client"; 34 - 35 - const DOH_RESOLVER = "https://mozilla.cloudflare-dns.com/dns-query"; 36 - const PUBLIC_URL: string = 37 - import.meta.env.VITE_PUBLIC_URL || "http://localhost:8000"; 38 - const REDIRECT_URI = `${PUBLIC_URL}/oauth/callback`; 39 - const scope = "atproto transition:generic"; 40 21 41 22 const Container = styled.div` 42 23 display: flex; ··· 88 69 const [passwordLogin, setPasswordLogin] = useState(false); 89 70 90 71 useEffect(() => { 91 - const clientId = PUBLIC_URL.startsWith("http://localhost") 92 - ? `http://localhost` + 93 - `?redirect_uri=${encodeURIComponent(REDIRECT_URI)}` + 94 - `&scope=${encodeURIComponent(scope)}` 95 - : `${PUBLIC_URL}/oauth-client-metadata.json`; 96 - 97 - const handleResolver = new CompositeHandleResolver({ 98 - methods: { 99 - dns: new DohJsonHandleResolver({ dohUrl: DOH_RESOLVER }), 100 - http: new WellKnownHandleResolver(), 101 - }, 102 - }); 103 - 104 - configureOAuth({ 105 - metadata: { 106 - client_id: clientId, 107 - redirect_uri: REDIRECT_URI, 108 - }, 109 - identityResolver: new LocalActorResolver({ 110 - handleResolver: handleResolver, 111 - didDocumentResolver: new CompositeDidDocumentResolver({ 112 - methods: { 113 - plc: new PlcDidDocumentResolver(), 114 - web: new WebDidDocumentResolver(), 115 - }, 116 - }), 117 - }), 118 - }); 119 - }, []); 120 - 121 - useEffect(() => { 122 72 if (did && did !== "null") { 123 73 localStorage.setItem("did", did); 124 74 ··· 158 108 159 109 useProfile(token || localStorage.getItem("token")); 160 110 161 - const onLogin = async () => { 111 + const onLogin = async (prompt?: string) => { 162 112 if (!handle.trim()) { 163 113 return; 164 114 } ··· 205 155 } 206 156 207 157 if (API_URL.includes("localhost")) { 208 - window.location.href = `${API_URL}/login?handle=${handle}`; 158 + window.location.href = prompt 159 + ? `${API_URL}/login?handle=${handle}&prompt=${prompt}` 160 + : `${API_URL}/login?handle=${handle}`; 209 161 return; 210 162 } 211 163 212 - window.location.href = `https://rocksky.pages.dev/loading?handle=${handle}`; 164 + window.location.href = prompt 165 + ? `https://rocksky.pages.dev/loading?handle=${handle}&prompt=${prompt}` 166 + : `https://rocksky.pages.dev/loading?handle=${handle}`; 213 167 }; 214 168 215 - /*const onCreateAccount = async () => { 216 - const authUrl = await createAuthorizationUrl({ 217 - target: { type: "pds", serviceUrl: "https://selfhosted.social" }, 218 - // @ts-expect-error - new stuff 219 - prompt: "create", 220 - scope, 221 - }); 222 - window.location.assign(authUrl); 223 - };*/ 169 + const onCreateAccount = async () => { 170 + await onLogin("create_account"); 171 + }; 224 172 225 173 return ( 226 174 <Container ··· 362 310 )} 363 311 </div> 364 312 <Button 365 - onClick={onLogin} 313 + onClick={() => onLogin()} 366 314 overrides={{ 367 315 BaseButton: { 368 316 style: { ··· 385 333 </LabelMedium> 386 334 <div className="text-center text-[var(--color-text-muted)] "> 387 335 You can create one at{" "} 388 - {/* 389 - <span 336 + <span 390 337 onClick={onCreateAccount} 391 338 className="no-underline cursor-pointer !text-[var(--color-primary)]" 392 339 > 393 340 selfhosted.social 394 341 </span> 395 342 ,{" "} 396 - */} 397 343 <a 398 344 href="https://bsky.app" 399 345 className="no-underline cursor-pointer !text-[var(--color-primary)]"
+1 -33
bun.lock
··· 196 196 "name": "@rocksky/web", 197 197 "version": "0.0.0", 198 198 "dependencies": { 199 - "@atcute/identity-resolver": "^1.2.2", 200 - "@atcute/oauth-browser-client": "^2.0.3", 201 199 "@emotion/react": "^11.14.0", 202 200 "@emotion/styled": "^11.14.0", 203 201 "@hookform/resolvers": "^4.0.0", ··· 374 372 375 373 "@asteasolutions/zod-to-openapi": ["@asteasolutions/zod-to-openapi@7.3.4", "", { "dependencies": { "openapi3-ts": "^4.1.2" }, "peerDependencies": { "zod": "^3.20.2" } }, "sha512-/2rThQ5zPi9OzVwes6U7lK1+Yvug0iXu25olp7S0XsYmOqnyMfxH7gdSQjn/+DSOHRg7wnotwGJSyL+fBKdnEA=="], 376 374 377 - "@atcute/client": ["@atcute/client@4.2.1", "", { "dependencies": { "@atcute/identity": "^1.1.3", "@atcute/lexicons": "^1.2.6" } }, "sha512-ZBFM2pW075JtgGFu5g7HHZBecrClhlcNH8GVP9Zz1aViWR+cjjBsTpeE63rJs+FCOHFYlirUyo5L8SGZ4kMINw=="], 378 - 379 - "@atcute/identity": ["@atcute/identity@1.1.3", "", { "dependencies": { "@atcute/lexicons": "^1.2.4", "@badrap/valita": "^0.4.6" } }, "sha512-oIqPoI8TwWeQxvcLmFEZLdN2XdWcaLVtlm8pNk0E72As9HNzzD9pwKPrLr3rmTLRIoULPPFmq9iFNsTeCIU9ng=="], 380 - 381 - "@atcute/identity-resolver": ["@atcute/identity-resolver@1.2.2", "", { "dependencies": { "@atcute/lexicons": "^1.2.6", "@atcute/util-fetch": "^1.0.5", "@badrap/valita": "^0.4.6" }, "peerDependencies": { "@atcute/identity": "^1.0.0" } }, "sha512-eUh/UH4bFvuXS0X7epYCeJC/kj4rbBXfSRumLEH4smMVwNOgTo7cL/0Srty+P/qVPoZEyXdfEbS0PHJyzoXmHw=="], 382 - 383 - "@atcute/lexicons": ["@atcute/lexicons@1.2.6", "", { "dependencies": { "@atcute/uint8array": "^1.0.6", "@atcute/util-text": "^0.0.1", "@standard-schema/spec": "^1.1.0", "esm-env": "^1.2.2" } }, "sha512-s76UQd8D+XmHIzrjD9CJ9SOOeeLPHc+sMmcj7UFakAW/dDFXc579fcRdRfuUKvXBL5v1Gs2VgDdlh/IvvQZAwA=="], 384 - 385 - "@atcute/multibase": ["@atcute/multibase@1.1.6", "", { "dependencies": { "@atcute/uint8array": "^1.0.5" } }, "sha512-HBxuCgYLKPPxETV0Rot4VP9e24vKl8JdzGCZOVsDaOXJgbRZoRIF67Lp0H/OgnJeH/Xpva8Z5ReoTNJE5dn3kg=="], 386 - 387 - "@atcute/oauth-browser-client": ["@atcute/oauth-browser-client@2.0.3", "", { "dependencies": { "@atcute/client": "^4.1.1", "@atcute/identity-resolver": "^1.2.0", "@atcute/lexicons": "^1.2.5", "@atcute/multibase": "^1.1.6", "@atcute/uint8array": "^1.0.6", "nanoid": "^5.1.6" } }, "sha512-rzUjwhjE4LRRKdQnCFQag/zXRZMEAB1hhBoLfnoQuHwWbmDUCL7fzwC3jRhDPp3om8XaYNDj8a/iqRip0wRqoQ=="], 388 - 389 - "@atcute/uint8array": ["@atcute/uint8array@1.0.6", "", {}, "sha512-ucfRBQc7BFT8n9eCyGOzDHEMKF/nZwhS2pPao4Xtab1ML3HdFYcX2DM1tadCzas85QTGxHe5urnUAAcNKGRi9A=="], 390 - 391 - "@atcute/util-fetch": ["@atcute/util-fetch@1.0.5", "", { "dependencies": { "@badrap/valita": "^0.4.6" } }, "sha512-qjHj01BGxjSjIFdPiAjSARnodJIIyKxnCMMEcXMESo9TAyND6XZQqrie5fia+LlYWVXdpsTds8uFQwc9jdKTig=="], 392 - 393 - "@atcute/util-text": ["@atcute/util-text@0.0.1", "", { "dependencies": { "unicode-segmenter": "^0.14.4" } }, "sha512-t1KZqvn0AYy+h2KcJyHnKF9aEqfRfMUmyY8j1ELtAEIgqN9CxINAjxnoRCJIFUlvWzb+oY3uElQL/Vyk3yss0g=="], 394 - 395 375 "@atproto-labs/did-resolver": ["@atproto-labs/did-resolver@0.1.11", "", { "dependencies": { "@atproto-labs/fetch": "0.2.2", "@atproto-labs/pipe": "0.1.0", "@atproto-labs/simple-store": "0.1.2", "@atproto-labs/simple-store-memory": "0.1.2", "@atproto/did": "0.1.5", "zod": "^3.23.8" } }, "sha512-qXNzIX2GPQnxT1gl35nv/8ErDdc4Fj/+RlJE7oyE7JGkFAPUyuY03TvKJ79SmWFsWE8wyTXEpLuphr9Da1Vhkw=="], 396 376 397 377 "@atproto-labs/fetch": ["@atproto-labs/fetch@0.2.2", "", { "dependencies": { "@atproto-labs/pipe": "0.1.0" } }, "sha512-QyafkedbFeVaN20DYUpnY2hcArYxjdThPXbYMqOSoZhcvkrUqaw4xDND4wZB5TBD9cq2yqe9V6mcw9P4XQKQuQ=="], ··· 505 485 "@babel/traverse": ["@babel/traverse@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/types": "^7.28.4", "debug": "^4.3.1" } }, "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ=="], 506 486 507 487 "@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="], 508 - 509 - "@badrap/valita": ["@badrap/valita@0.4.6", "", {}, "sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg=="], 510 488 511 489 "@biomejs/biome": ["@biomejs/biome@2.2.5", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.2.5", "@biomejs/cli-darwin-x64": "2.2.5", "@biomejs/cli-linux-arm64": "2.2.5", "@biomejs/cli-linux-arm64-musl": "2.2.5", "@biomejs/cli-linux-x64": "2.2.5", "@biomejs/cli-linux-x64-musl": "2.2.5", "@biomejs/cli-win32-arm64": "2.2.5", "@biomejs/cli-win32-x64": "2.2.5" }, "bin": { "biome": "bin/biome" } }, "sha512-zcIi+163Rc3HtyHbEO7CjeHq8DjQRs40HsGbW6vx2WI0tg8mYQOPouhvHSyEnCBAorfYNnKdR64/IxO7xQ5faw=="], 512 490 ··· 1846 1824 1847 1825 "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], 1848 1826 1849 - "esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="], 1850 - 1851 1827 "espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], 1852 1828 1853 1829 "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], ··· 2304 2280 2305 2281 "mustache": ["mustache@4.2.0", "", { "bin": { "mustache": "bin/mustache" } }, "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="], 2306 2282 2307 - "nanoid": ["nanoid@5.1.6", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg=="], 2283 + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], 2308 2284 2309 2285 "napi-build-utils": ["napi-build-utils@2.0.0", "", {}, "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA=="], 2310 2286 ··· 2858 2834 2859 2835 "unenv": ["unenv@2.0.0-rc.14", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.1", "ohash": "^2.0.10", "pathe": "^2.0.3", "ufo": "^1.5.4" } }, "sha512-od496pShMen7nOy5VmVJCnq8rptd45vh6Nx/r2iPbrba6pa6p+tS2ywuIHRZ/OBvSbQZB0kWvpO9XBNVFXHD3Q=="], 2860 2836 2861 - "unicode-segmenter": ["unicode-segmenter@0.14.5", "", {}, "sha512-jHGmj2LUuqDcX3hqY12Ql+uhUTn8huuxNZGq7GvtF6bSybzH3aFgedYu/KTzQStEgt1Ra2F3HxadNXsNjb3m3g=="], 2862 - 2863 2837 "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], 2864 2838 2865 2839 "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], ··· 2965 2939 "zod-to-json-schema": ["zod-to-json-schema@3.24.6", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg=="], 2966 2940 2967 2941 "zx": ["zx@8.8.4", "", { "bin": { "zx": "build/cli.js" } }, "sha512-44GcD+ZlM/v1OQtbwnSxLPcoE1ZEUICmR+RSbJZLAqfIixNLuMjLyh0DcS75OyfJ/sWYAwCWDmDvJ4hdnANAPQ=="], 2968 - 2969 - "@atcute/lexicons/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], 2970 2942 2971 2943 "@atproto-labs/fetch-node/ipaddr.js": ["ipaddr.js@2.2.0", "", {}, "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA=="], 2972 2944 ··· 3284 3256 3285 3257 "pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], 3286 3258 3287 - "postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], 3288 - 3289 3259 "posthog-js/fflate": ["fflate@0.4.8", "", {}, "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA=="], 3290 3260 3291 3261 "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], ··· 3693 3663 "send/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], 3694 3664 3695 3665 "styled-components/@emotion/is-prop-valid/@emotion/memoize": ["@emotion/memoize@0.8.1", "", {}, "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="], 3696 - 3697 - "styled-components/postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], 3698 3666 3699 3667 "table/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], 3700 3668