Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
170024a
feat(mobile): scaffold Expo project with dependencies
kawamataryo Apr 5, 2026
39486f7
feat(mobile): add type definitions, constants, and utils
kawamataryo Apr 5, 2026
73b0870
feat(mobile): port bskyHelpers with isSimilarUser matching logic
kawamataryo Apr 5, 2026
ec9b019
feat(mobile): port fuzzy search logic for Bluesky user matching
kawamataryo Apr 5, 2026
9ec9ff5
feat(mobile): add WebView injection scripts for X DOM scraping
kawamataryo Apr 5, 2026
c87d990
feat(mobile): add session storage and Bluesky agent wrapper
kawamataryo Apr 5, 2026
e9c119d
feat(mobile): add AuthContext with app-password login and session res…
kawamataryo Apr 5, 2026
40295e9
feat(mobile): add ScanContext with batch user processing
kawamataryo Apr 5, 2026
8bd8caf
feat(mobile): wire up AuthProvider and ScanProvider in root layout
kawamataryo Apr 5, 2026
00ea1e9
feat(mobile): implement Welcome screen with auto-redirect
kawamataryo Apr 5, 2026
428a519
feat(mobile): implement Bluesky auth screen with app-password login
kawamataryo Apr 5, 2026
46c8aae
feat(mobile): add X login guide screen with privacy note
kawamataryo Apr 5, 2026
764ddc3
feat(mobile): implement X WebView login with auto-redirect on login d…
kawamataryo Apr 5, 2026
4a4256d
feat(mobile): implement scan screen with off-screen WebView scraping
kawamataryo Apr 5, 2026
a5ff993
feat(mobile): implement results screen with UserCard and follow action
kawamataryo Apr 5, 2026
b1b5a59
feat(server): add mobile deep link to OAuth redirect URIs
kawamataryo Apr 5, 2026
3fa23c0
feat(mobile): implement OAuth login via expo-auth-session
kawamataryo Apr 5, 2026
dde6110
fix(mobile): address code review issues (XSS, race conditions, error …
kawamataryo Apr 5, 2026
81e6e42
fix(mobile): update test to match JSON.stringify escaped selector
kawamataryo Apr 5, 2026
1d451d8
design(mobile): redesign all screens with Aurora Bridge dark theme
kawamataryo Apr 5, 2026
5d2534a
fix(mobile): switch entry point to expo-router/entry
kawamataryo Apr 5, 2026
5cc541d
fix(mobile): fix TextInput not responding on auth screen
kawamataryo Apr 5, 2026
f3fe539
fix(mobile): remove Animated.View and focusedField state causing Text…
kawamataryo Apr 5, 2026
f91b191
fix(mobile): merge X login and scan into single WebView to share cookies
kawamataryo Apr 5, 2026
9237050
feat(mobile): add back button to X login WebView header
kawamataryo Apr 5, 2026
3670b49
fix(mobile): improve X login detection to catch all non-login redirects
kawamataryo Apr 5, 2026
8702df4
[from now] 2026/04/06 12:58:09
kawamataryo Apr 6, 2026
ccfa525
docs(mobile): add OAuth design spec using @atproto/oauth-client-expo
kawamataryo Apr 10, 2026
8f12e74
docs(mobile): finalize OAuth expo spec and add implementation plan
kawamataryo Apr 10, 2026
0dff7b9
feat(server): add mobile OAuth client metadata helper
kawamataryo Apr 10, 2026
bcde3f9
feat(server): add /oauth/mobile/client-metadata.json endpoint
kawamataryo Apr 10, 2026
3245c2b
feat(mobile): add canonical OAuth client metadata asset
kawamataryo Apr 10, 2026
57a5f2a
chore(mobile): add @atproto/oauth-client-expo, remove expo-auth-session
kawamataryo Apr 10, 2026
3e43309
chore(mobile): update URL scheme to bundle identifier
kawamataryo Apr 10, 2026
b2b0ef8
feat(mobile): add ExpoOAuthClient singleton wrapper
kawamataryo Apr 10, 2026
40d2951
feat(mobile): rewrite bskyOAuth with ExpoOAuthClient and error normal…
kawamataryo Apr 10, 2026
4d79b64
chore(mobile): remove unused BSKY_OAUTH_* constants
kawamataryo Apr 10, 2026
ce5f547
feat(mobile): implement OAuth branch in restoreAgent
kawamataryo Apr 10, 2026
431a7b2
feat(mobile): harden AuthContext for OAuth, widen agent type to base …
kawamataryo Apr 10, 2026
74bdf66
feat(mobile): normalize OAuth login error messages in auth screen
kawamataryo Apr 10, 2026
85cab7e
test(mobile): snapshot OAuth metadata consistency with server
kawamataryo Apr 10, 2026
e71a2eb
refactor(mobile): address code review from OAuth migration
kawamataryo Apr 10, 2026
a38a732
fix(mobile): provide handleResolver and reverse-FQDN redirect scheme
kawamataryo Apr 10, 2026
a545114
fix(mobile): polyfill AbortSignal.timeout for Hermes runtime
kawamataryo Apr 10, 2026
602da0d
fix(mobile): polyfill AbortSignal.prototype.throwIfAborted for Hermes
kawamataryo Apr 10, 2026
833db83
chore(mobile): remove temporary [oauth] diagnostic logs
kawamataryo Apr 10, 2026
42a2869
[from now] 2026/04/10 22:24:13
kawamataryo Apr 10, 2026
76f1b52
[from now] 2026/04/11 05:55:37
kawamataryo Apr 10, 2026
e92daa2
[from now] 2026/04/11 05:55:40
kawamataryo Apr 10, 2026
a8d0077
[from now] 2026/04/13 05:55:23
kawamataryo Apr 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
197 changes: 197 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Sky Follower Bridge is a browser extension that helps users migrate their social connections from X (Twitter), Threads, Instagram, TikTok, and Facebook to Bluesky. It uses web scraping to detect users on these platforms and matches them with Bluesky accounts using fuzzy search algorithms.

**Tech Stack:**
- **Framework**: Plasmo (Manifest V3 browser extension framework)
- **Frontend**: React 18.2.0 + TypeScript
- **Styling**: Tailwind CSS + DaisyUI
- **Bluesky API**: @atproto/api
- **Testing**: Vitest + Happy DOM
- **Linting**: Biome
- **Backend**: Cloudflare Workers (Hono framework)

## Development Commands

```bash
# Development
npm run dev # Start development server (Chrome)
npm run dev:firefox # Start development server (Firefox)

# Building
npm run build # Build for Chrome (creates build/chrome-mv3-prod)
npm run build:firefox # Build for Firefox
npm run package # Package for Chrome distribution
npm run package:firefox # Package for Firefox distribution

# Testing & Quality
npm run test # Run Vitest tests
npm run check # Run Biome formatter/linter (auto-fix)
npm run check:ci # CI check (no auto-fix)

# Component Development
npm run storybook # Launch Storybook on port 6006
npm run build-storybook # Build Storybook

# Documentation
npm run docs:dev # Start VitePress dev server
npm run docs:build # Build VitePress docs
npm run docs:preview # Preview built docs
```

## Architecture

### High-Level Flow

```
User opens Extension (Alt+B)
[Popup] Login to Bluesky → Start Search
[Content Script] Detects current page → Scrapes users → Matches with Bluesky
[Service Worker] Performs Bluesky API operations (follow/block/list)
[Popup] Shows matched users in modal
```

### Core Components

1. **Popup** (`src/popup.tsx`): Main UI for authentication and search initiation
2. **Content Scripts** (`src/contents/`): Injected into target sites to scrape user data
3. **Service Worker** (`src/background/messages/`): Handles Bluesky API communication
4. **Services** (`src/services/`): Platform-specific scraping logic for X, Threads, Instagram, TikTok, Facebook

### Message Handlers (`src/background/messages/`)

All Bluesky API operations are handled via Plasmo message handlers:
- `login.ts`: Authenticate with Bluesky
- `follow.ts`, `unfollow.ts`: Follow/unfollow operations
- `block.ts`, `unblock.ts`: Block/unblock operations
- `searchUser.ts`: Search for users on Bluesky
- `createList.ts`, `addUserToList.ts`: List management
- `getMyProfile.ts`: Fetch authenticated user profile
- `getImageSimilarityScore.ts`: Calculate avatar similarity

### Platform Services (`src/services/`)

Each service implements the same interface for scraping user data:
- `xService.ts`: X.com (Twitter) following/followers/blocked pages
- `threadsService.ts`: Threads user lists
- `instagramService.ts`: Instagram followers/following
- `tikTokService.ts`: TikTok user lists
- `facebookService.ts`: Facebook friends

**Service Pattern:**
```typescript
class XService {
extractUsersFromDom(): CrawledUserInfo[]
observeDomChanges(callback: (users: CrawledUserInfo[]) => void): void
}
```

### User Matching Algorithm

Location: `src/lib/fuzzySearchBskyUser.ts`

Uses Jaro-Winkler algorithm to match scraped users with Bluesky accounts:
1. **Handle matching**: Exact or fuzzy match on username
2. **Display name matching**: Fuzzy match on display name
3. **Description matching**: Check if X/Threads handle appears in Bluesky bio
4. **Avatar similarity**: Calculate image similarity score (threshold: 0.6)

Match types are defined in `BSKY_USER_MATCH_TYPE` (handle, display_name, description, none).

### Constants (`src/lib/constants.ts`)

Critical configuration file containing:
- `TARGET_URLS_REGEX`: URL patterns that trigger the extension
- `MESSAGE_NAMES`: Inter-component communication message types
- `ACTION_MODE`: Follow, block, or import_list operations
- `STORAGE_KEYS`: Browser storage key prefixes
- `FILTER_TYPE`: User filtering criteria in results modal
- `BSKY_DOMAIN`: Configurable via `PLASMO_PUBLIC_BSKY_DOMAIN` env var

## Key Files to Understand

When working with this codebase, start with these files in order:

1. **`src/lib/constants.ts`**: All enums, regex patterns, and configuration
2. **`src/popup.tsx`**: Main user interface entry point
3. **`src/hooks/useSearch.ts`**: Search initialization logic
4. **`src/contents/App.tsx`**: Content script that coordinates scraping
5. **`src/lib/fuzzySearchBskyUser.ts`**: Core matching algorithm
6. **`src/background/messages/`**: Bluesky API operations

## Storage Architecture

Uses `@plasmohq/storage` for persistent data:
- `BSKY_CLIENT_SESSION`: Authenticated Bluesky session
- `DETECTED_BSKY_USERS`: Matched Bluesky users for current search
- `BSKY_MESSAGE_NAME`: Current operation mode (follow/block/list)
- `LIST_NAME`: Name for imported lists

## Multi-Platform Support

The extension detects the current page using `TARGET_URLS_REGEX` and instantiates the appropriate service:
- X.com: Follow, Followers, Blocked users, List members
- Threads: All pages
- Instagram: Followers/Following pages
- TikTok: User pages
- Facebook: Friends list

## Custom PDS Support

The extension can be built for custom Bluesky PDS servers:
```bash
PLASMO_PUBLIC_BSKY_DOMAIN=custom-domain.com npm run build
```

Default domain is `bsky.social` (defined in `src/lib/constants.ts`).

## Browser Extension Loading

**Chrome/Edge:**
1. Navigate to `chrome://extensions/`
2. Enable "Developer mode"
3. Click "Load unpacked"
4. Select `build/chrome-mv3-prod`

**Firefox:**
1. Navigate to `about:debugging#/runtime/this-firefox`
2. Click "Load Temporary Add-on"
3. Select the `.zip` file from `build/`

## Testing

- Tests are located alongside source files (e.g., `src/lib/__tests__/`)
- Run with `npm run test`
- Uses Vitest with Happy DOM for browser environment simulation

## Common Patterns

### Adding a New Platform Service

1. Create service file in `src/services/` (e.g., `newPlatformService.ts`)
2. Implement `extractUsersFromDom()` and `observeDomChanges()` methods
3. Add URL pattern to `TARGET_URLS_REGEX` in `src/lib/constants.ts`
4. Add message name to `MESSAGE_NAMES`
5. Update `src/contents/App.tsx` to instantiate the new service
6. Add host permission to `manifest.host_permissions` in `package.json`

### Adding a New Bluesky Operation

1. Create message handler in `src/background/messages/` (e.g., `newOperation.ts`)
2. Use `getBskyServiceWorkerClient()` from `src/lib/bskyServiceWorkerClient.ts`
3. Export handler using Plasmo's message handler pattern
4. Call from frontend using `@plasmohq/messaging`

## Internationalization

- Locale files in `locales/` directory (JSON format)
- Access translations via `chrome.i18n.getMessage(key)`
- Default locale: `en` (set in `package.json` manifest)
41 changes: 41 additions & 0 deletions mobile/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files

# dependencies
node_modules/

# Expo
.expo/
dist/
web-build/
expo-env.d.ts

# Native
.kotlin/
*.orig.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision

# Metro
.metro-health-check*

# debug
npm-debug.*
yarn-debug.*
yarn-error.*

# macOS
.DS_Store
*.pem

# local env files
.env*.local

# typescript
*.tsbuildinfo

# generated native folders
/ios
/android
Loading
Loading