···
import { createStore } from "solid-js/store";
+
import { CredentialManager, XRPC } from "@atcute/client";
···
const [loginState, setLoginState] = createSignal(false);
let agent: OAuthUserAgent;
+
let manager: CredentialManager;
const resolveDid = async (did: string) => {
···
const Login: Component = () => {
const [loginInput, setLoginInput] = createSignal("");
+
const [password, setPassword] = createSignal("");
const [handle, setHandle] = createSignal("");
const [notice, setNotice] = createSignal("");
···
agent = new OAuthUserAgent(session);
rpc = new XRPC({ handler: agent });
setHandle(await resolveDid(agent.sub));
···
+
const getPDS = async (did: string) => {
+
const res = await fetch(
+
did.startsWith("did:web") ?
+
`https://${did.split(":")[2]}/.well-known/did.json`
+
: "https://plc.directory/" + did,
+
return res.json().then((doc: any) => {
+
for (const service of doc.service) {
+
if (service.id === "#atproto_pds") return service.serviceEndpoint;
+
const resolveHandle = async (handle: string) => {
+
handler: new CredentialManager({
+
service: "https://public.api.bsky.app",
+
const res = await rpc.get("com.atproto.identity.resolveHandle", {
+
params: { handle: handle },
+
const loginBsky = async (login: string) => {
+
agentDID = login.startsWith("did:") ? login : await resolveHandle(login);
+
manager = new CredentialManager({ service: await getPDS(agentDID) });
+
rpc = new XRPC({ handler: manager });
+
setNotice(`Resolving your identity...`);
+
const resolved = await resolveFromIdentity(login);
+
setNotice(`Contacting your data server...`);
+
const authUrl = await createAuthorizationUrl({
+
scope: import.meta.env.VITE_OAUTH_SCOPE,
+
setNotice(`Redirecting...`);
+
await new Promise((resolve) => setTimeout(resolve, 250));
+
location.assign(authUrl);
+
setNotice("Error during OAuth login");
···
class="dark:bg-dark-100 mb-2 rounded-lg border border-gray-400 px-2 py-1 focus:outline-none focus:ring-1 focus:ring-gray-300"
onInput={(e) => setLoginInput(e.currentTarget.value)}
+
<label for="password" class="ml-0.5">
+
placeholder="leave empty for oauth"
+
class="dark:bg-dark-100 mb-2 rounded-lg border border-gray-400 px-2 py-1 focus:outline-none focus:ring-1 focus:ring-gray-300"
+
onInput={(e) => setPassword(e.currentTarget.value)}
onclick={() => loginBsky(loginInput())}
class="rounded bg-blue-600 py-1.5 font-bold text-slate-100 hover:bg-blue-700"
···
<Show when={loginState() && handle()}>
···
const fetchPage = async (cursor?: string) => {
return await rpc.get("com.atproto.repo.listRecords", {
collection: "app.bsky.graph.follow",
···
viewer.blocking || viewer.blockingByList ?
RepoStatus.BLOCKEDBY | RepoStatus.BLOCKING
+
} else if (res.data.did.includes(agentDID)) {
status = RepoStatus.YOURSELF;
} else if (viewer.blocking || viewer.blockingByList) {
status = RepoStatus.BLOCKING;
···
for (let i = 0; i < writes.length; i += BATCHSIZE) {
await rpc.call("com.atproto.repo.applyWrites", {
writes: writes.slice(i, i + BATCHSIZE),