Unfollow tool for Bluesky

switch to atcute oauth client

mary.my.id a6a4f37f b46524e8

verified
+42 -237
package-lock.json
···
"dependencies": {
"@atcute/bluesky": "^1.0.7",
"@atcute/client": "^2.0.2",
-
"@atproto/oauth-client-browser": "^0.2.0",
+
"@atcute/oauth-browser-client": "^1.0.1",
"solid-js": "^1.8.11"
},
"devDependencies": {
"@tailwindcss/forms": "^0.5.7",
+
"@types/node": "^22.7.5",
"autoprefixer": "^10.4.19",
"postcss": "^8.4.39",
"prettier": "^3.3.3",
···
}
},
"node_modules/@atcute/client": {
-
"version": "2.0.2",
-
"resolved": "https://registry.npmjs.org/@atcute/client/-/client-2.0.2.tgz",
-
"integrity": "sha512-bTGoo8cs0B0gXLwI8YYaFayjDIlo8V1wxgng3HkA+jyz22wCh8aL0/4F9Tt4GDKXGCgf+/6IHg1M6uGOX8JVSw==",
+
"version": "2.0.3",
+
"resolved": "https://registry.npmjs.org/@atcute/client/-/client-2.0.3.tgz",
+
"integrity": "sha512-j9GryA5l+4F0BTQWa6/1XmsuSPSq+bqNCY3mrHUGD592hMqUZxgpYDLgRWL+719V287AW/56AwvFYlbjlENp7A==",
"license": "MIT"
},
-
"node_modules/@atproto-labs/did-resolver": {
-
"version": "0.1.4",
-
"resolved": "https://registry.npmjs.org/@atproto-labs/did-resolver/-/did-resolver-0.1.4.tgz",
-
"integrity": "sha512-5d+LHScS2ueYsFRjMOC3c1EwM2ui1yBVbBA0yY3MH7aydbljm5D28scsOVuymIhHwPFwcGvZbMON4PVSfpBbbQ==",
+
"node_modules/@atcute/oauth-browser-client": {
+
"version": "1.0.1",
+
"resolved": "https://registry.npmjs.org/@atcute/oauth-browser-client/-/oauth-browser-client-1.0.1.tgz",
+
"integrity": "sha512-vMHf2P+R4tv4qG5cB5YHgOhZf3HNkZhV1DIWXBsRgbfBqoIRWSVTPt2NOunOk0aHtY1NvzU0RTr/j6OnKps/WA==",
"license": "MIT",
"dependencies": {
-
"@atproto-labs/fetch": "0.1.1",
-
"@atproto-labs/pipe": "0.1.0",
-
"@atproto-labs/simple-store": "0.1.1",
-
"@atproto-labs/simple-store-memory": "0.1.1",
-
"@atproto/did": "0.1.2",
-
"zod": "^3.23.8"
+
"@atcute/client": "^2.0.3",
+
"nanoid": "^5.0.7"
}
},
-
"node_modules/@atproto-labs/fetch": {
-
"version": "0.1.1",
-
"resolved": "https://registry.npmjs.org/@atproto-labs/fetch/-/fetch-0.1.1.tgz",
-
"integrity": "sha512-X1zO1MDoJzEurbWXMAe1H8EZ995Xam/aXdxhGVrXmOMyPDuvBa1oxwh/kQNZRCKcMQUbiwkk+Jfq6ZkTuvGbww==",
+
"node_modules/@atcute/oauth-browser-client/node_modules/nanoid": {
+
"version": "5.0.7",
+
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.7.tgz",
+
"integrity": "sha512-oLxFY2gd2IqnjcYyOXD8XGCftpGtZP2AbHbOkthDkvRywH5ayNtPVy9YlOPcHckXzbLTCHpkb7FB+yuxKV13pQ==",
+
"funding": [
+
{
+
"type": "github",
+
"url": "https://github.com/sponsors/ai"
+
}
+
],
"license": "MIT",
-
"dependencies": {
-
"@atproto-labs/pipe": "0.1.0"
+
"bin": {
+
"nanoid": "bin/nanoid.js"
},
-
"optionalDependencies": {
-
"zod": "^3.23.8"
-
}
-
},
-
"node_modules/@atproto-labs/handle-resolver": {
-
"version": "0.1.3",
-
"resolved": "https://registry.npmjs.org/@atproto-labs/handle-resolver/-/handle-resolver-0.1.3.tgz",
-
"integrity": "sha512-pUn8uqQNqMpecQjO0UWmdKhKX1NnXdLBXHRgID2g4kmhpz3hkbbec+h34uSk6wLfZnwPFaVQnGdEkyMq/tNToQ==",
-
"license": "MIT",
-
"dependencies": {
-
"@atproto-labs/simple-store": "0.1.1",
-
"@atproto-labs/simple-store-memory": "0.1.1",
-
"@atproto/did": "0.1.2",
-
"zod": "^3.23.8"
-
}
-
},
-
"node_modules/@atproto-labs/identity-resolver": {
-
"version": "0.1.4",
-
"resolved": "https://registry.npmjs.org/@atproto-labs/identity-resolver/-/identity-resolver-0.1.4.tgz",
-
"integrity": "sha512-uaRJsYFCRZQcw0c7S+RuziSVm5qHcK3N6uqsXz8NzYoJAE55Ah4DkQMj0rfapZmb0jyBau04RC/WoI4PSim+Aw==",
-
"license": "MIT",
-
"dependencies": {
-
"@atproto-labs/did-resolver": "0.1.4",
-
"@atproto-labs/handle-resolver": "0.1.3",
-
"@atproto/syntax": "0.3.0"
-
}
-
},
-
"node_modules/@atproto-labs/pipe": {
-
"version": "0.1.0",
-
"resolved": "https://registry.npmjs.org/@atproto-labs/pipe/-/pipe-0.1.0.tgz",
-
"integrity": "sha512-ghOqHFyJlQVFPESzlVHjKroP0tPzbmG5Jms0dNI9yLDEfL8xp4OFPWLX4f6T8mRq69wWs4nIDM3sSsFbFqLa1w==",
-
"license": "MIT"
-
},
-
"node_modules/@atproto-labs/simple-store": {
-
"version": "0.1.1",
-
"resolved": "https://registry.npmjs.org/@atproto-labs/simple-store/-/simple-store-0.1.1.tgz",
-
"integrity": "sha512-WKILW2b3QbAYKh+w5U2x6p5FqqLl0nAeLwGeDY+KjX01K4Dq3vQTR9b/qNp0jZm48CabPQVrqCv0PPU9LgRRRg==",
-
"license": "MIT"
-
},
-
"node_modules/@atproto-labs/simple-store-memory": {
-
"version": "0.1.1",
-
"resolved": "https://registry.npmjs.org/@atproto-labs/simple-store-memory/-/simple-store-memory-0.1.1.tgz",
-
"integrity": "sha512-PCRqhnZ8NBNBvLku53O56T0lsVOtclfIrQU/rwLCc4+p45/SBPrRYNBi6YFq5rxZbK6Njos9MCmILV/KLQxrWA==",
-
"license": "MIT",
-
"dependencies": {
-
"@atproto-labs/simple-store": "0.1.1",
-
"lru-cache": "^10.2.0"
-
}
-
},
-
"node_modules/@atproto/common-web": {
-
"version": "0.3.1",
-
"resolved": "https://registry.npmjs.org/@atproto/common-web/-/common-web-0.3.1.tgz",
-
"integrity": "sha512-N7wiTnus5vAr+lT//0y8m/FaHHLJ9LpGuEwkwDAeV3LCiPif4m/FS8x/QOYrx1PdZQwKso95RAPzCGWQBH5j6Q==",
-
"license": "MIT",
-
"dependencies": {
-
"graphemer": "^1.4.0",
-
"multiformats": "^9.9.0",
-
"uint8arrays": "3.0.0",
-
"zod": "^3.23.8"
-
}
-
},
-
"node_modules/@atproto/did": {
-
"version": "0.1.2",
-
"resolved": "https://registry.npmjs.org/@atproto/did/-/did-0.1.2.tgz",
-
"integrity": "sha512-gmY1SyAuqfmsFbIXkUIScfnULqn39FoUNz4oE0fUuMu9in6PEyoxlmD2lAo7Q3KMy3X/hvTn2u5f8W/2KuDg1w==",
-
"license": "MIT",
-
"dependencies": {
-
"zod": "^3.23.8"
-
}
-
},
-
"node_modules/@atproto/jwk": {
-
"version": "0.1.1",
-
"resolved": "https://registry.npmjs.org/@atproto/jwk/-/jwk-0.1.1.tgz",
-
"integrity": "sha512-6h/bj1APUk7QcV9t/oA6+9DB5NZx9SZru9x+/pV5oHFI9Xz4ZuM5+dq1PfsJV54pZyqdnZ6W6M717cxoC7q7og==",
-
"license": "MIT",
-
"dependencies": {
-
"multiformats": "^9.9.0",
-
"zod": "^3.23.8"
-
}
-
},
-
"node_modules/@atproto/jwk-jose": {
-
"version": "0.1.2",
-
"resolved": "https://registry.npmjs.org/@atproto/jwk-jose/-/jwk-jose-0.1.2.tgz",
-
"integrity": "sha512-lDwc/6lLn2aZ/JpyyggyjLFsJPMntrVzryyGUx5aNpuTS8SIuc4Ky0REhxqfLopQXJJZCuRRjagHG3uP05/moQ==",
-
"license": "MIT",
-
"dependencies": {
-
"@atproto/jwk": "0.1.1",
-
"jose": "^5.2.0"
-
}
-
},
-
"node_modules/@atproto/jwk-webcrypto": {
-
"version": "0.1.2",
-
"resolved": "https://registry.npmjs.org/@atproto/jwk-webcrypto/-/jwk-webcrypto-0.1.2.tgz",
-
"integrity": "sha512-vTBUbUZXh0GI+6KJiPGukmI4BQEHFAij8fJJ4WnReF/hefAs3ISZtrWZHGBebz+q2EcExYlnhhlmxvDzV7veGw==",
-
"license": "MIT",
-
"dependencies": {
-
"@atproto/jwk": "0.1.1",
-
"@atproto/jwk-jose": "0.1.2"
-
}
-
},
-
"node_modules/@atproto/lexicon": {
-
"version": "0.4.2",
-
"resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.4.2.tgz",
-
"integrity": "sha512-CXoOkhcdF3XVUnR2oNgCs2ljWfo/8zUjxL5RIhJW/UNLp/FSl+KpF8Jm5fbk8Y/XXVPGRAsv9OYfxyU/14N/pw==",
-
"license": "MIT",
-
"dependencies": {
-
"@atproto/common-web": "^0.3.1",
-
"@atproto/syntax": "^0.3.0",
-
"iso-datestring-validator": "^2.2.2",
-
"multiformats": "^9.9.0",
-
"zod": "^3.23.8"
-
}
-
},
-
"node_modules/@atproto/oauth-client": {
-
"version": "0.2.2",
-
"resolved": "https://registry.npmjs.org/@atproto/oauth-client/-/oauth-client-0.2.2.tgz",
-
"integrity": "sha512-hYL7Hx2h52zeC1WZeFjV9FFfqt8PZnURKofz0VJVeiPqB9wySJ46MgFVxsZ3t08c03WSDugujEz2JlhtQpS7Zg==",
-
"license": "MIT",
-
"dependencies": {
-
"@atproto-labs/did-resolver": "0.1.4",
-
"@atproto-labs/fetch": "0.1.1",
-
"@atproto-labs/handle-resolver": "0.1.3",
-
"@atproto-labs/identity-resolver": "0.1.4",
-
"@atproto-labs/simple-store": "0.1.1",
-
"@atproto-labs/simple-store-memory": "0.1.1",
-
"@atproto/did": "0.1.2",
-
"@atproto/jwk": "0.1.1",
-
"@atproto/oauth-types": "0.1.5",
-
"@atproto/xrpc": "0.6.3",
-
"multiformats": "^9.9.0",
-
"zod": "^3.23.8"
-
}
-
},
-
"node_modules/@atproto/oauth-client-browser": {
-
"version": "0.2.2",
-
"resolved": "https://registry.npmjs.org/@atproto/oauth-client-browser/-/oauth-client-browser-0.2.2.tgz",
-
"integrity": "sha512-Y36LTqNMq2iqWrdGJljD5yqWDy9CbhHElxI5syiPCcgLCm9/UU8Hu5QTgCrESDzAyV5viYWDweeqAmLrpVrpQg==",
-
"license": "MIT",
-
"dependencies": {
-
"@atproto-labs/did-resolver": "0.1.4",
-
"@atproto-labs/handle-resolver": "0.1.3",
-
"@atproto-labs/simple-store": "0.1.1",
-
"@atproto/did": "0.1.2",
-
"@atproto/jwk": "0.1.1",
-
"@atproto/jwk-webcrypto": "0.1.2",
-
"@atproto/oauth-client": "0.2.2",
-
"@atproto/oauth-types": "0.1.5"
-
}
-
},
-
"node_modules/@atproto/oauth-types": {
-
"version": "0.1.5",
-
"resolved": "https://registry.npmjs.org/@atproto/oauth-types/-/oauth-types-0.1.5.tgz",
-
"integrity": "sha512-vNab/6BYUQCfmfhGc3G61EcatQxvh2d41FDWqR8CAYsblNXO6nOEVXn7cXdQUkb3K49LU0vy5Jf1+wFNcpY3IQ==",
-
"license": "MIT",
-
"dependencies": {
-
"@atproto/jwk": "0.1.1",
-
"zod": "^3.23.8"
-
}
-
},
-
"node_modules/@atproto/syntax": {
-
"version": "0.3.0",
-
"resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.3.0.tgz",
-
"integrity": "sha512-Weq0ZBxffGHDXHl9U7BQc2BFJi/e23AL+k+i5+D9hUq/bzT4yjGsrCejkjq0xt82xXDjmhhvQSZ0LqxyZ5woxA==",
-
"license": "MIT"
-
},
-
"node_modules/@atproto/xrpc": {
-
"version": "0.6.3",
-
"resolved": "https://registry.npmjs.org/@atproto/xrpc/-/xrpc-0.6.3.tgz",
-
"integrity": "sha512-S3tRvOdA9amPkKLll3rc4vphlDitLrkN5TwWh5Tu/jzk7mnobVVE3akYgICV9XCNHKjWM+IAPxFFI2qi+VW6nQ==",
-
"license": "MIT",
-
"dependencies": {
-
"@atproto/lexicon": "^0.4.2",
-
"zod": "^3.23.8"
+
"engines": {
+
"node": "^18 || >=20"
}
},
"node_modules/@babel/code-frame": {
···
"dev": true,
"license": "MIT"
},
+
"node_modules/@types/node": {
+
"version": "22.7.5",
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz",
+
"integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==",
+
"dev": true,
+
"license": "MIT",
+
"dependencies": {
+
"undici-types": "~6.19.2"
+
}
+
},
"node_modules/agent-base": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
···
"node": ">=4"
},
-
"node_modules/graphemer": {
-
"version": "1.4.0",
-
"resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
-
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
-
"license": "MIT"
-
},
"node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
···
"dev": true,
"license": "ISC"
},
-
"node_modules/iso-datestring-validator": {
-
"version": "2.2.2",
-
"resolved": "https://registry.npmjs.org/iso-datestring-validator/-/iso-datestring-validator-2.2.2.tgz",
-
"integrity": "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==",
-
"license": "MIT"
-
},
"node_modules/jackspeak": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
···
"jiti": "bin/jiti.js"
},
-
"node_modules/jose": {
-
"version": "5.9.3",
-
"resolved": "https://registry.npmjs.org/jose/-/jose-5.9.3.tgz",
-
"integrity": "sha512-egLIoYSpcd+QUF+UHgobt5YzI2Pkw/H39ou9suW687MY6PmCwPmkNV/4TNjn1p2tX5xO3j0d0sq5hiYE24bSlg==",
-
"license": "MIT",
-
"funding": {
-
"url": "https://github.com/sponsors/panva"
-
}
-
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
···
"version": "10.4.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+
"dev": true,
"license": "ISC"
},
"node_modules/merge-anything": {
···
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true,
"license": "MIT"
-
},
-
"node_modules/multiformats": {
-
"version": "9.9.0",
-
"resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz",
-
"integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==",
-
"license": "(Apache-2.0 AND MIT)"
},
"node_modules/mz": {
"version": "2.7.0",
···
"node": ">=14.17"
},
-
"node_modules/uint8arrays": {
-
"version": "3.0.0",
-
"resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.0.0.tgz",
-
"integrity": "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==",
-
"license": "MIT",
-
"dependencies": {
-
"multiformats": "^9.4.2"
-
}
+
"node_modules/undici-types": {
+
"version": "6.19.8",
+
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
+
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
+
"dev": true,
+
"license": "MIT"
},
"node_modules/update-browserslist-db": {
"version": "1.1.1",
···
},
"engines": {
"node": ">= 14"
-
}
-
},
-
"node_modules/zod": {
-
"version": "3.23.8",
-
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
-
"integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
-
"license": "MIT",
-
"funding": {
-
"url": "https://github.com/sponsors/colinhacks"
+2 -1
package.json
···
"license": "0BSD",
"devDependencies": {
"@tailwindcss/forms": "^0.5.7",
+
"@types/node": "^22.7.5",
"autoprefixer": "^10.4.19",
"postcss": "^8.4.39",
"prettier": "^3.3.3",
···
"dependencies": {
"@atcute/bluesky": "^1.0.7",
"@atcute/client": "^2.0.2",
-
"@atproto/oauth-client-browser": "^0.2.0",
+
"@atcute/oauth-browser-client": "^1.0.1",
"solid-js": "^1.8.11"
}
}
+72 -34
src/App.tsx
···
import {
+
createEffect,
createSignal,
-
onMount,
For,
+
onMount,
Show,
type Component,
-
createEffect,
} from "solid-js";
import { createStore } from "solid-js/store";
-
import {
-
BrowserOAuthClient,
-
OAuthSession,
-
} from "@atproto/oauth-client-browser";
-
import "@atcute/bluesky/lexicons";
import { XRPC } from "@atcute/client";
import {
AppBskyGraphFollow,
-
ComAtprotoRepoListRecords,
+
At,
+
Brand,
ComAtprotoRepoApplyWrites,
-
Brand,
+
ComAtprotoRepoListRecords,
} from "@atcute/client/lexicons";
+
import {
+
configureOAuth,
+
createAuthorizationUrl,
+
finalizeAuthorization,
+
getSession,
+
OAuthUserAgent,
+
resolveFromIdentity,
+
type Session,
+
} from "@atcute/oauth-browser-client";
+
+
configureOAuth({
+
metadata: {
+
client_id: import.meta.env.VITE_OAUTH_CLIENT_ID,
+
redirect_uri: import.meta.env.VITE_OAUTH_REDIRECT_URL,
+
},
+
});
enum RepoStatus {
BLOCKEDBY = 1 << 0,
···
const [followRecords, setFollowRecords] = createStore<FollowRecord[]>([]);
const [loginState, setLoginState] = createSignal(false);
let rpc: XRPC;
-
let session: OAuthSession;
+
let agent: OAuthUserAgent;
const resolveDid = async (did: string) => {
const res = await fetch(
···
const [loginInput, setLoginInput] = createSignal("");
const [handle, setHandle] = createSignal("");
const [notice, setNotice] = createSignal("");
-
let client: BrowserOAuthClient;
onMount(async () => {
setNotice("Loading...");
-
client = await BrowserOAuthClient.load({
-
clientId: "https://cleanfollow-bsky.pages.dev/client-metadata.json",
-
handleResolver: "https://boletus.us-west.host.bsky.network",
-
});
-
client.addEventListener("deleted", () => {
-
setLoginState(false);
-
});
-
const result = await client.init().catch(() => {});
+
const init = async (): Promise<Session | undefined> => {
+
const params = new URLSearchParams(location.hash.slice(1));
+
+
if (params.has("state") && (params.has("code") || params.has("error"))) {
+
history.replaceState(null, "", location.pathname + location.search);
-
if (result) {
-
session = result.session;
-
rpc = new XRPC({
-
handler: { handle: session.fetchHandler.bind(session) },
-
});
+
const session = await finalizeAuthorization(params);
+
const did = session.info.sub;
+
+
localStorage.setItem("lastSignedIn", did);
+
return session;
+
} else {
+
const lastSignedIn = localStorage.getItem("lastSignedIn");
+
+
if (lastSignedIn) {
+
try {
+
const session = await getSession(lastSignedIn as At.DID);
+
return session;
+
} catch (err) {
+
localStorage.removeItem("lastSignedIn");
+
throw err;
+
}
+
}
+
}
+
};
+
+
const session = await init().catch(() => {});
+
+
if (session) {
+
agent = new OAuthUserAgent(session);
+
rpc = new XRPC({ handler: agent });
+
setLoginState(true);
-
setHandle(await resolveDid(session.did));
+
setHandle(await resolveDid(agent.sub));
}
+
setNotice("");
});
const loginBsky = async (handle: string) => {
-
setNotice("Redirecting...");
try {
-
await client.signIn(handle, {
-
scope: "atproto transition:generic",
-
signal: new AbortController().signal,
+
setNotice(`Resolving your identity...`);
+
const resolved = await resolveFromIdentity(handle);
+
+
setNotice(`Contacting your data server...`);
+
const authUrl = await createAuthorizationUrl({
+
scope: import.meta.env.VITE_OAUTH_SCOPE,
+
...resolved,
});
+
+
setNotice(`Redirecting...`);
+
await new Promise((resolve) => setTimeout(resolve, 250));
+
+
location.assign(authUrl);
} catch (err) {
-
setNotice("Error during OAuth redirection");
+
setNotice("Error during OAuth login");
}
};
const logoutBsky = async () => {
-
if (session.sub) await client.revoke(session.sub);
+
await agent.signOut();
};
return (
···
const fetchPage = async (cursor?: string) => {
return await rpc.get("com.atproto.repo.listRecords", {
params: {
-
repo: session.did,
+
repo: agent.sub,
collection: "app.bsky.graph.follow",
limit: PAGE_LIMIT,
cursor: cursor,
···
viewer.blocking || viewer.blockingByList ?
RepoStatus.BLOCKEDBY | RepoStatus.BLOCKING
: RepoStatus.BLOCKEDBY;
-
} else if (res.data.did.includes(session.did)) {
+
} else if (res.data.did.includes(agent.sub)) {
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", {
data: {
-
repo: session.did,
+
repo: agent.sub,
writes: writes.slice(i, i + BATCHSIZE),
},
});
+14
src/vite-env.d.ts
···
+
/// <reference types="vite/client" />
+
/// <reference types="@atcute/bluesky/lexicons" />
+
+
interface ImportMetaEnv {
+
readonly VITE_DEV_SERVER_PORT?: string;
+
readonly VITE_CLIENT_URI: string;
+
readonly VITE_OAUTH_CLIENT_ID: string;
+
readonly VITE_OAUTH_REDIRECT_URL: string;
+
readonly VITE_OAUTH_SCOPE: string;
+
}
+
+
interface ImportMeta {
+
readonly env: ImportMetaEnv;
+
}
+26
tsconfig.app.json
···
+
{
+
"compilerOptions": {
+
"target": "ESNext",
+
"useDefineForClassFields": true,
+
"module": "ESNext",
+
"lib": ["ESNext", "DOM", "DOM.Iterable"],
+
"types": [],
+
"skipLibCheck": true,
+
+
/* Bundler mode */
+
"moduleResolution": "bundler",
+
"allowImportingTsExtensions": true,
+
"isolatedModules": true,
+
"moduleDetection": "force",
+
"noEmit": true,
+
"jsx": "preserve",
+
"jsxImportSource": "solid-js",
+
+
/* Linting */
+
"strict": true,
+
"noUnusedLocals": true,
+
"noUnusedParameters": true,
+
"noFallthroughCasesInSwitch": true
+
},
+
"include": ["src"]
+
}
+6 -16
tsconfig.json
···
{
-
"compilerOptions": {
-
"strict": true,
-
"target": "ESNext",
-
"module": "nodenext",
-
"moduleResolution": "nodenext",
-
"allowSyntheticDefaultImports": true,
-
"esModuleInterop": true,
-
"jsx": "preserve",
-
"jsxImportSource": "solid-js",
-
"types": [
-
"vite/client"
-
],
-
"noEmit": true,
-
"isolatedModules": true
-
}
-
}
+
"files": [],
+
"references": [
+
{ "path": "./tsconfig.app.json" },
+
{ "path": "./tsconfig.node.json" }
+
]
+
}
+23
tsconfig.node.json
···
+
{
+
"compilerOptions": {
+
"target": "ESNext",
+
"lib": ["ESNext"],
+
"types": ["node"],
+
"module": "ESNext",
+
"skipLibCheck": true,
+
+
/* Bundler mode */
+
"moduleResolution": "bundler",
+
"allowImportingTsExtensions": true,
+
"isolatedModules": true,
+
"moduleDetection": "force",
+
"noEmit": true,
+
+
/* Linting */
+
"strict": true,
+
"noUnusedLocals": true,
+
"noUnusedParameters": true,
+
"noFallthroughCasesInSwitch": true
+
},
+
"include": ["vite.config.ts"]
+
}
+35 -2
vite.config.ts
···
import solidPlugin from "vite-plugin-solid";
// import devtools from 'solid-devtools/vite';
+
import metadata from "./public/client-metadata.json";
+
+
const SERVER_HOST = "127.0.0.1";
+
const SERVER_PORT = 13213;
+
export default defineConfig({
plugins: [
/*
···
*/
// devtools(),
solidPlugin(),
+
+
// Injects OAuth-related variables
+
{
+
name: "oauth",
+
config(_conf, { command }) {
+
if (command === "build") {
+
process.env.VITE_OAUTH_CLIENT_ID = metadata.client_id;
+
process.env.VITE_OAUTH_REDIRECT_URL = metadata.redirect_uris[0];
+
} else {
+
const redirectUri = ((): string => {
+
const url = new URL(metadata.redirect_uris[0]);
+
return `http://${SERVER_HOST}:${SERVER_PORT}${url.pathname}`;
+
})();
+
+
const clientId =
+
`http://localhost` +
+
`?redirect_uri=${encodeURIComponent(redirectUri)}` +
+
`&scope=${encodeURIComponent(metadata.scope)}`;
+
+
process.env.VITE_DEV_SERVER_PORT = "" + SERVER_PORT;
+
process.env.VITE_OAUTH_CLIENT_ID = clientId;
+
process.env.VITE_OAUTH_REDIRECT_URL = redirectUri;
+
}
+
+
process.env.VITE_CLIENT_URI = metadata.client_uri;
+
process.env.VITE_OAUTH_SCOPE = metadata.scope;
+
},
+
},
],
server: {
-
host: "127.0.0.1",
-
port: 3000,
+
host: SERVER_HOST,
+
port: SERVER_PORT,
},
build: {
target: "esnext",