pds.js#
A zero-dependency AT Protocol Personal Data Server written in JavaScript, running on Cloudflare Workers with Durable Objects. Let's see how far we can get with just Web APIs.
鈿狅笍 Work in progress - This is experimental. You probably shouldn't use this yet.
Status#
- Repo operations (createRecord, getRecord, putRecord, deleteRecord, applyWrites, listRecords)
- Sync endpoints (getRepo, getRecord, subscribeRepos, listRepos, getLatestCommit)
- Auth (createSession, getSession, refreshSession)
- Handle resolution (resolveHandle)
- AppView proxy (app.bsky.* forwarding with service auth)
- Relay notification (requestCrawl)
- Single or multi-user (each DID gets isolated storage, no self-service signup yet)
- Blob storage (uploadBlob, getBlob, listBlobs)
- deleteSession (logout)
- updateHandle
- importRepo
- OAuth
- Account management (createAccount, deleteAccount)
- Email verification
- Invite codes
- Admin/moderation
- Rate limiting
Prerequisites#
- Node.js 18+
- shfmt (optional, for
npm run format)brew install shfmt
Quick Start#
npm install
# Create local dev config
cp .env.example .dev.vars
# Edit .dev.vars with your values
# Run locally
npm run dev
Configuration#
For local development, create .dev.vars:
PDS_PASSWORD=your-password
JWT_SECRET=your-secret
RELAY_HOST=https://bsky.network # optional
For production, use Cloudflare secrets:
wrangler secret put PDS_PASSWORD
wrangler secret put JWT_SECRET
wrangler secret put RELAY_HOST # optional
Blob Storage#
Blobs (images, videos) are stored in Cloudflare R2. Create the bucket before deploying:
npx wrangler r2 bucket create pds-blobs
The binding is already configured in wrangler.toml. Supported formats: JPEG, PNG, GIF, WebP, MP4. Max size: 50MB. Orphaned blobs are automatically cleaned up after 24 hours.
Testing#
npm test # Unit tests
npm run test:e2e # E2E tests (starts local server)
Deploy#
wrangler deploy
Initialize#
After deployment, run the setup script to register with PLC and initialize:
npm run setup -- --pds https://your-pds.workers.dev
This generates keys, registers your DID with the PLC directory, initializes the PDS, and saves credentials. Handle defaults to the worker hostname.