From d6ae71877beb0d581c26fdc074b0188c00613304 Mon Sep 17 00:00:00 2001 From: Madiator2011 Date: Sat, 16 Nov 2024 18:24:16 +0100 Subject: [PATCH] support for self hosted PDS --- README.md | 74 +++++++++++++++++++++++++++++++++++++++++++ src/lib/bskyClient.ts | 3 +- src/lib/constants.ts | 2 ++ src/lib/domHelpers.ts | 7 ++-- src/popup.tsx | 5 +-- 5 files changed, 86 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 764c756..10394d9 100644 --- a/README.md +++ b/README.md @@ -48,3 +48,77 @@ https://github.com/kawamataryo/sky-follower-bridge/assets/11070996/67bdd228-dc67 ## 🚨 Limitations - User search may fail due to late limit in Bluesky's API. In this case, please wait for 2 to 3 minutes and execute the search again. + +## Development + +### Environment Variables + +- `PLASMO_PUBLIC_BSKY_DOMAIN`: The Bluesky domain to use (default: "bsky.social") + +## Building for Custom PDS Servers + +If you want to use this extension with a custom PDS (Personal Data Server) instead of the default bsky.social, you have two options: + +### Option 1: Using .env file + +1. Clone the repository: +```bash +git clone https://github.com/kawamataryo/sky-follower-bridge.git +cd sky-follower-bridge +``` + +2. Install dependencies: +```bash +npm install +``` + +3. Create a `.env` file in the root directory: +```bash +echo "PLASMO_PUBLIC_BSKY_DOMAIN=bsky.social" > .env +``` + +4. Build the extension: +```bash +# For Chrome +npm run build +npm run package + +# For Firefox +npm run build:firefox +npm run package:firefox +``` + +### Option 2: Using environment variable directly + +You can also pass the domain directly during build: + +```bash +# For Chrome +PLASMO_PUBLIC_BSKY_DOMAIN=your-custom-domain.com npm run build +PLASMO_PUBLIC_BSKY_DOMAIN=your-custom-domain.com npm run package + +# For Firefox +PLASMO_PUBLIC_BSKY_DOMAIN=your-custom-domain.com npm run build:firefox +PLASMO_PUBLIC_BSKY_DOMAIN=your-custom-domain.com npm run package:firefox +``` + +### Loading the Built Extension + +After building, you can load the extension: + +**For Chrome/Edge:** +1. Go to `chrome://extensions/` (or `edge://extensions/`) +2. Enable "Developer mode" in the top right +3. Click "Load unpacked" +4. Select the `build/chrome-mv3-prod` directory + +**For Firefox:** +1. Go to `about:debugging#/runtime/this-firefox` +2. Click "Load Temporary Add-on" +3. Select the zip file from the `dist` directory + +### Notes +- The built extension will be in the `build` directory +- The packaged extension (.zip) will be in the `dist` directory +- When using a custom PDS, users will need to use handles in the format `username.your-custom-domain.com` +- Make sure your custom PDS server is compatible with the AT Protocol diff --git a/src/lib/bskyClient.ts b/src/lib/bskyClient.ts index 0a06a96..e3a9195 100644 --- a/src/lib/bskyClient.ts +++ b/src/lib/bskyClient.ts @@ -1,4 +1,5 @@ import { AtUri, AtpAgent, type AtpSessionData } from "@atproto/api"; +import { BSKY_DOMAIN } from "./constants"; // try and cut down the amount of session resumes by caching the clients const clientCache = new Map(); @@ -10,7 +11,7 @@ export type BskyLoginParams = { }; export class BskyClient { - private service = "https://bsky.social"; + private service = `https://${BSKY_DOMAIN}`; me: { did: string; handle: string; diff --git a/src/lib/constants.ts b/src/lib/constants.ts index d86edf1..542e2e6 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -99,3 +99,5 @@ export const DOCUMENT_LINK = { PAGE_ERROR: "https://www.sky-follower-bridge.dev/troubleshooting.html#page-errors", } as const; + +export const BSKY_DOMAIN = process.env.PLASMO_PUBLIC_BSKY_DOMAIN || "bsky.social"; \ No newline at end of file diff --git a/src/lib/domHelpers.ts b/src/lib/domHelpers.ts index 87a116f..929ff72 100644 --- a/src/lib/domHelpers.ts +++ b/src/lib/domHelpers.ts @@ -1,3 +1,5 @@ +import { BSKY_DOMAIN } from "./constants"; + export const getUserCells = ({ queryParam, filterInsertedElement, @@ -20,13 +22,14 @@ export const getUserCells = ({ }; export const getAccountNameAndDisplayName = (userCell: Element) => { - const [avatarEl, displayNameEl] = userCell.querySelectorAll("a"); + const anchors = Array.from(userCell.querySelectorAll("a")); + const [avatarEl, displayNameEl] = anchors; const twAccountName = avatarEl?.getAttribute("href")?.replace("/", ""); const twAccountNameRemoveUnderscore = twAccountName.replaceAll("_", ""); // bsky does not allow underscores in handle, so remove them. const twAccountNameReplaceUnderscore = twAccountName.replaceAll("_", "-"); const twDisplayName = displayNameEl?.textContent; const bskyHandle = - userCell.textContent?.match(/([^/\s]+\.bsky\.social)/)?.[1] ?? + userCell.textContent?.match(new RegExp(`([^/\\s]+\\.${BSKY_DOMAIN})`))?.[1] ?? userCell.textContent ?.match(/bsky\.app\/profile\/([^/\s]+)…?/)?.[1] ?.replace("…", "") ?? diff --git a/src/popup.tsx b/src/popup.tsx index 81e2bff..d2f972b 100644 --- a/src/popup.tsx +++ b/src/popup.tsx @@ -14,6 +14,7 @@ import { RATE_LIMIT_ERROR_MESSAGE, STORAGE_KEYS, TARGET_URLS_REGEX, + BSKY_DOMAIN, } from "~lib/constants"; function IndexPopup() { @@ -135,7 +136,7 @@ function IndexPopup() { setIsLoading(true); const formattedIdentifier = ( - identifier.includes(".") ? identifier : `${identifier}.bsky.social` + identifier.includes(".") ? identifier : `${identifier}.${BSKY_DOMAIN}` ).replace(/^@/, ""); try { const { session, error } = await sendToBackground({ @@ -236,7 +237,7 @@ function IndexPopup() { setIdentifier(e.target.value)} className="input input-bordered input-sm w-full max-w-xs join-item focus:outline-none mt-1"